new: new caplets module to manage system caplets

This commit is contained in:
evilsocket 2018-09-21 16:49:20 +02:00
commit e79ba4952e
6 changed files with 213 additions and 3 deletions

View file

@ -8,8 +8,12 @@ import (
)
const (
Suffix = ".cap"
InstallPath = "/usr/local/share/bettercap/caplets/"
EnvVarName = "CAPSPATH"
Suffix = ".cap"
InstallArchive = "https://github.com/bettercap/caplets/archive/master.zip"
InstallBase = "/usr/local/share/bettercap/"
InstallPathArchive = "/usr/local/share/bettercap/caplets-master/"
InstallPath = "/usr/local/share/bettercap/caplets/"
)
var (
@ -20,7 +24,7 @@ var (
)
func init() {
for _, path := range core.SepSplit(core.Trim(os.Getenv("CAPSPATH")), ":") {
for _, path := range core.SepSplit(core.Trim(os.Getenv(EnvVarName)), ":") {
if path = core.Trim(path); len(path) > 0 {
LoadPaths = append(LoadPaths, path)
}

View file

@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"sync"
@ -38,6 +39,10 @@ func List() []Caplet {
}
}
sort.Slice(caplets, func(i, j int) bool {
return strings.Compare(caplets[i].Name, caplets[j].Name) == -1
})
return caplets
}

View file

@ -1,7 +1,9 @@
package core
import (
"archive/zip"
"fmt"
"io"
"os"
"os/exec"
"os/user"
@ -102,3 +104,48 @@ func ExpandPath(path string) (string, error) {
}
return "", nil
}
// Unzip will decompress a zip archive, moving all files and folders
// within the zip file (parameter 1) to an output directory (parameter 2).
// Credits to https://golangcode.com/unzip-files-in-go/
func Unzip(src string, dest string) ([]string, error) {
var filenames []string
r, err := zip.OpenReader(src)
if err != nil {
return filenames, err
}
defer r.Close()
for _, f := range r.File {
rc, err := f.Open()
if err != nil {
return filenames, err
}
defer rc.Close()
// Store filename/path for returning and using later on
fpath := filepath.Join(dest, f.Name)
// Check for ZipSlip. More Info: https://snyk.io/research/zip-slip-vulnerability#go
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
return filenames, fmt.Errorf("%s: illegal file path", fpath)
}
filenames = append(filenames, fpath)
if f.FileInfo().IsDir() {
os.MkdirAll(fpath, os.ModePerm)
} else if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return filenames, err
} else if outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()); err != nil {
return filenames, err
} else {
defer outFile.Close()
if _, err = io.Copy(outFile, rc); err != nil {
return filenames, err
}
}
}
return filenames, nil
}

View file

@ -35,6 +35,7 @@ func main() {
sess.Register(modules.NewEventsStream(sess))
sess.Register(modules.NewTicker(sess))
sess.Register(modules.NewUpdateModule(sess))
sess.Register(modules.NewCapletsModule(sess))
sess.Register(modules.NewMacChanger(sess))
sess.Register(modules.NewProber(sess))
sess.Register(modules.NewDiscovery(sess))

148
modules/caplets.go Normal file
View file

@ -0,0 +1,148 @@
package modules
import (
"fmt"
"io"
"net/http"
"os"
"github.com/bettercap/bettercap/caplets"
"github.com/bettercap/bettercap/core"
"github.com/bettercap/bettercap/log"
"github.com/bettercap/bettercap/session"
"github.com/dustin/go-humanize"
)
type CapletsModule struct {
session.SessionModule
}
func NewCapletsModule(s *session.Session) *CapletsModule {
c := &CapletsModule{
SessionModule: session.NewSessionModule("caplets", s),
}
c.AddHandler(session.NewModuleHandler("caplets.show", "",
"Show a list of installed caplets.",
func(args []string) error {
return c.Show()
}))
c.AddHandler(session.NewModuleHandler("caplets.paths", "",
"Show a list caplet search paths.",
func(args []string) error {
return c.Paths()
}))
c.AddHandler(session.NewModuleHandler("caplets.update", "",
"Install/updates the caplets.",
func(args []string) error {
return c.Update()
}))
return c
}
func (c *CapletsModule) Name() string {
return "caplets"
}
func (c *CapletsModule) Description() string {
return "A module to list and update caplets."
}
func (c *CapletsModule) Author() string {
return "Simone Margaritelli <evilsocket@protonmail.com>"
}
func (c *CapletsModule) Configure() error {
return nil
}
func (c *CapletsModule) Stop() error {
return nil
}
func (c *CapletsModule) Start() error {
return nil
}
func (c *CapletsModule) Show() error {
caplets := caplets.List()
if len(caplets) == 0 {
return fmt.Errorf("no installed caplets on this system, use the caplets.update command to download them")
}
colNames := []string{
"Name",
"Path",
"Size",
}
rows := [][]string{}
for _, caplet := range caplets {
rows = append(rows, []string{
core.Bold(caplet.Name),
caplet.Path,
core.Dim(humanize.Bytes(uint64(caplet.Size))),
})
}
core.AsTable(os.Stdout, colNames, rows)
return nil
}
func (c *CapletsModule) Paths() error {
colNames := []string{
"Path",
}
rows := [][]string{[]string{"."}}
for _, path := range caplets.LoadPaths {
rows = append(rows, []string{path})
}
core.AsTable(os.Stdout, colNames, rows)
fmt.Printf("(paths can be customized by defining the %s environment variable)\n", core.Bold(caplets.EnvVarName))
return nil
}
func (c *CapletsModule) Update() error {
if !core.Exists(caplets.InstallBase) {
log.Info("creating caplets install path %s ...", caplets.InstallBase)
if err := os.MkdirAll(caplets.InstallBase, os.ModePerm); err != nil {
return err
}
}
out, err := os.Create("/tmp/caplets.zip")
if err != nil {
return err
}
defer out.Close()
log.Info("downloading caplets from %s ...", caplets.InstallArchive)
resp, err := http.Get(caplets.InstallArchive)
if err != nil {
return err
}
defer resp.Body.Close()
if _, err := io.Copy(out, resp.Body); err != nil {
return err
}
log.Info("installing caplets to %s ...", caplets.InstallPath)
if _, err = core.Unzip("/tmp/caplets.zip", caplets.InstallBase); err != nil {
return err
}
os.RemoveAll(caplets.InstallPath)
return os.Rename(caplets.InstallPathArchive, caplets.InstallPath)
}

View file

@ -63,6 +63,11 @@ func (p *EventPool) Listen() <-chan Event {
// will receive all the queued events
go func() {
for i := len(p.events) - 1; i >= 0; i-- {
defer func() {
if recover() != nil {
}
}()
l <- p.events[i]
}
}()