Commit f4269504 authored by Sophie Brun's avatar Sophie Brun

New upstream version 2.21.1

parent d3fa11ec
......@@ -83,7 +83,7 @@
revision = "2ce16c963a8ac5bd6af851d4877e38701346983f"
[[projects]]
digest = "1:da1be9af4c3f262bd385cc722b08d98d4a47ddea57731e98b85c7ba21b35bc31"
digest = "1:5247f5757ba31623c464db149dc272a37604516d8fbae1561b36e0d7cee070a5"
name = "github.com/evilsocket/islazy"
packages = [
"data",
......@@ -96,8 +96,8 @@
"zip",
]
pruneopts = "UT"
revision = "6ef79e84ded205e48f296d21e3bc65d1cf4f5c78"
version = "v1.10.3"
revision = "c5c7a41bb1c20e6df409825ed24af8de5fb7fb70"
version = "v1.10.4"
[[projects]]
branch = "master"
......
......@@ -2,7 +2,7 @@ package core
const (
Name = "bettercap"
Version = "2.20"
Version = "2.21.1"
Author = "Simone 'evilsocket' Margaritelli"
Website = "https://bettercap.org/"
)
......@@ -22,7 +22,7 @@ func ParseOptions() (Options, error) {
o := Options{
InterfaceName: flag.String("iface", "", "Network interface to bind to, if empty the default interface will be auto selected."),
Gateway: flag.String("gateway-override", "", "Use the provided IP address instead of the default gateway. If not specified or invalid, the default gateway will be used."),
AutoStart: flag.String("autostart", "events.stream, net.recon", "Comma separated list of modules to auto start."),
AutoStart: flag.String("autostart", "events.stream", "Comma separated list of modules to auto start."),
Caplet: flag.String("caplet", "", "Read commands from this file and execute them in the interactive session."),
Debug: flag.Bool("debug", false, "Print debug messages."),
PrintVersion: flag.Bool("version", false, "Print the version and exit."),
......
......@@ -80,7 +80,7 @@ func (mod *AnyProxy) Configure() error {
var dstAddress string
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err, iface = mod.StringParam("any.proxy.iface"); err != nil {
return err
} else if err, protocol = mod.StringParam("any.proxy.protocol"); err != nil {
......
......@@ -126,7 +126,7 @@ func (mod *RestAPI) Configure() error {
var port int
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err, ip = mod.StringParam("api.rest.address"); err != nil {
return err
} else if err, port = mod.IntParam("api.rest.port"); err != nil {
......
......@@ -140,7 +140,7 @@ func (w dummyWriter) Write(p []byte) (n int, err error) {
func (mod *BLERecon) Configure() (err error) {
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if mod.gattDevice == nil {
mod.Debug("initializing device ...")
......@@ -239,7 +239,7 @@ func (mod *BLERecon) enumAllTheThings(mac string) error {
}
mod.setCurrentDevice(dev)
if err := mod.Configure(); err != nil && err != session.ErrAlreadyStarted {
if err := mod.Configure(); err != nil && err.Error() != session.ErrAlreadyStarted("ble.recon").Error() {
return err
}
......
......@@ -78,7 +78,7 @@ func (mod *DHCP6Spoofer) Configure() error {
var err error
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
}
if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
......
......@@ -87,7 +87,7 @@ func (mod *DNSSpoofer) Configure() error {
var address net.IP
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
return err
} else if err = mod.Handle.SetBPFFilter("udp"); err != nil {
......
......@@ -72,7 +72,7 @@ func (mod *GPS) Author() string {
func (mod *GPS) Configure() (err error) {
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err, mod.serialPort = mod.StringParam("gps.device"); err != nil {
return err
} else if err, mod.baudRate = mod.IntParam("gps.baudrate"); err != nil {
......
......@@ -163,7 +163,7 @@ func (mod *HIDRecon) Configure() error {
var n int
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
}
if err, mod.useLNA = mod.BoolParam("hid.lna"); err != nil {
......
......@@ -89,7 +89,7 @@ func (mod *HttpProxy) Configure() error {
var whitelist string
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err, address = mod.StringParam("http.proxy.address"); err != nil {
return err
} else if err, proxyPort = mod.IntParam("http.proxy.port"); err != nil {
......
......@@ -71,7 +71,7 @@ func (mod *HttpServer) Configure() error {
var port int
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
}
if err, path = mod.StringParam("http.server.path"); err != nil {
......@@ -82,7 +82,7 @@ func (mod *HttpServer) Configure() error {
fileServer := http.FileServer(http.Dir(path))
router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mod.Info("%s %s %s%s", tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path)
mod.Debug("%s %s %s%s", tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path)
fileServer.ServeHTTP(w, r)
}))
......
......@@ -106,7 +106,7 @@ func (mod *HttpsProxy) Configure() error {
var blacklist string
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err, address = mod.StringParam("https.proxy.address"); err != nil {
return err
} else if err, proxyPort = mod.IntParam("https.proxy.port"); err != nil {
......
......@@ -89,7 +89,7 @@ func (mod *HttpsServer) Configure() error {
var keyFile string
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
}
if err, path = mod.StringParam("https.server.path"); err != nil {
......@@ -100,7 +100,7 @@ func (mod *HttpsServer) Configure() error {
fileServer := http.FileServer(http.Dir(path))
router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mod.Info("%s %s %s%s", tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path)
mod.Debug("%s %s %s%s", tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path)
fileServer.ServeHTTP(w, r)
}))
......
......@@ -103,7 +103,7 @@ func (mod *MacChanger) setMac(mac net.HardwareAddr) error {
func (mod *MacChanger) Start() error {
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err := mod.Configure(); err != nil {
return err
} else if err := mod.setMac(mod.fakeMac); err != nil {
......
......@@ -24,6 +24,7 @@ import (
"github.com/bettercap/bettercap/modules/syn_scan"
"github.com/bettercap/bettercap/modules/tcp_proxy"
"github.com/bettercap/bettercap/modules/ticker"
"github.com/bettercap/bettercap/modules/ui"
"github.com/bettercap/bettercap/modules/update"
"github.com/bettercap/bettercap/modules/wifi"
"github.com/bettercap/bettercap/modules/wol"
......@@ -36,7 +37,6 @@ func LoadModules(sess *session.Session) {
sess.Register(arp_spoof.NewArpSpoofer(sess))
sess.Register(api_rest.NewRestAPI(sess))
sess.Register(ble.NewBLERecon(sess))
sess.Register(caplets.NewCapletsModule(sess))
sess.Register(dhcp6_spoof.NewDHCP6Spoofer(sess))
sess.Register(net_recon.NewDiscovery(sess))
sess.Register(dns_spoof.NewDNSSpoofer(sess))
......@@ -54,8 +54,11 @@ func LoadModules(sess *session.Session) {
sess.Register(syn_scan.NewSynScanner(sess))
sess.Register(tcp_proxy.NewTcpProxy(sess))
sess.Register(ticker.NewTicker(sess))
sess.Register(update.NewUpdateModule(sess))
sess.Register(wifi.NewWiFiModule(sess))
sess.Register(wol.NewWOL(sess))
sess.Register(hid.NewHIDRecon(sess))
sess.Register(caplets.NewCapletsModule(sess))
sess.Register(update.NewUpdateModule(sess))
sess.Register(ui.NewUIModule(sess))
}
......@@ -79,7 +79,7 @@ func (mod *MySQLServer) Configure() error {
var port int
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err, mod.infile = mod.StringParam("mysql.server.infile"); err != nil {
return err
} else if err, mod.outfile = mod.StringParam("mysql.server.outfile"); err != nil {
......
......@@ -146,7 +146,7 @@ func (mod *Sniffer) Configure() error {
var err error
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err, mod.Ctx = mod.GetContext(); err != nil {
if mod.Ctx != nil {
mod.Ctx.Close()
......
......@@ -190,7 +190,7 @@ func dummyCallback(payload *nfqueue.Payload) int {
func (mod *PacketProxy) Start() error {
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err := mod.Configure(); err != nil {
return err
}
......
......@@ -95,7 +95,7 @@ func (mod *TcpProxy) Configure() error {
var tunnelPort int
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err, address = mod.StringParam("tcp.address"); err != nil {
return err
} else if err, proxyAddress = mod.StringParam("tcp.proxy.address"); err != nil {
......
......@@ -59,7 +59,7 @@ func (mod *Ticker) Configure() error {
var period int
if mod.Running() {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
} else if err, commands = mod.StringParam("ticker.commands"); err != nil {
return err
} else if err, period = mod.IntParam("ticker.period"); err != nil {
......
package ui
import (
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"regexp"
"github.com/bettercap/bettercap/session"
"github.com/google/go-github/github"
"github.com/evilsocket/islazy/fs"
"github.com/evilsocket/islazy/tui"
"github.com/evilsocket/islazy/zip"
)
var versionParser = regexp.MustCompile(`name:"ui",version:"([^"]+)"`)
type UIModule struct {
session.SessionModule
client *github.Client
tmpFile string
basePath string
uiPath string
}
func NewUIModule(s *session.Session) *UIModule {
mod := &UIModule{
SessionModule: session.NewSessionModule("ui", s),
client: github.NewClient(nil),
}
mod.AddParam(session.NewStringParameter("ui.basepath",
"/usr/local/share/bettercap/",
"",
"UI base installation path."))
mod.AddParam(session.NewStringParameter("ui.tmpfile",
filepath.Join(os.TempDir(), "ui.zip"),
"",
"Temporary file to use while downloading UI updates."))
mod.AddHandler(session.NewModuleHandler("ui.version", "",
"Print the currently installed UI version.",
func(args []string) error {
return mod.showVersion()
}))
mod.AddHandler(session.NewModuleHandler("ui.update", "",
"Download the latest available version of the UI and install it.",
func(args []string) error {
return mod.Start()
}))
return mod
}
func (mod *UIModule) Name() string {
return "ui"
}
func (mod *UIModule) Description() string {
return "A module to manage bettercap's UI updates and installed version."
}
func (mod *UIModule) Author() string {
return "Simone Margaritelli <evilsocket@gmail.com>"
}
func (mod *UIModule) Configure() (err error) {
if err, mod.basePath = mod.StringParam("ui.basepath"); err != nil {
return err
} else {
mod.uiPath = filepath.Join(mod.basePath, "ui")
}
if err, mod.tmpFile = mod.StringParam("ui.tmpfile"); err != nil {
return err
}
return nil
}
func (mod *UIModule) Stop() error {
return nil
}
func (mod *UIModule) download(version, url string) error {
if !fs.Exists(mod.basePath) {
mod.Warning("creating ui install path %s ...", mod.basePath)
if err := os.MkdirAll(mod.basePath, os.ModePerm); err != nil {
return err
}
}
out, err := os.Create(mod.tmpFile)
if err != nil {
return err
}
defer out.Close()
defer os.Remove(mod.tmpFile)
mod.Info("downloading ui %s from %s ...", tui.Bold(version), url)
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if _, err := io.Copy(out, resp.Body); err != nil {
return err
}
if fs.Exists(mod.uiPath) {
mod.Warning("removing previously installed UI from %s ...", mod.uiPath)
if err := os.RemoveAll(mod.uiPath); err != nil {
return err
}
}
mod.Info("installing to %s ...", mod.uiPath)
if _, err = zip.Unzip(mod.tmpFile, mod.basePath); err != nil {
return err
}
mod.Info("installation complete, you can now run the %s (or https-ui) caplet to start the UI.", tui.Bold("http-ui"))
return nil
}
func (mod *UIModule) showVersion() error {
if err := mod.Configure(); err != nil {
return err
}
if !fs.Exists(mod.uiPath) {
return fmt.Errorf("path %s does not exist, ui not installed", mod.uiPath)
}
search := filepath.Join(mod.uiPath, "/main.*.js")
matches, err := filepath.Glob(search)
if err != nil {
return err
} else if len(matches) == 0 {
return fmt.Errorf("can't find any main.*.js files in %s", mod.uiPath)
}
for _, filename := range matches {
if raw, err := ioutil.ReadFile(filename); err != nil {
return err
} else if m := versionParser.FindStringSubmatch(string(raw)); m != nil {
version := m[1]
mod.Info("v%s", version)
return nil
}
}
return fmt.Errorf("can't parse version from %s", search)
}
func (mod *UIModule) Start() error {
if err := mod.Configure(); err != nil {
return err
} else if err := mod.SetRunning(true, nil); err != nil {
return err
}
defer mod.SetRunning(false, nil)
mod.Info("checking latest stable release ...")
if releases, _, err := mod.client.Repositories.ListReleases(context.Background(), "bettercap", "ui", nil); err == nil {
latest := releases[0]
for _, a := range latest.Assets {
if *a.Name == "ui.zip" {
return mod.download(*latest.TagName, *a.BrowserDownloadURL)
}
}
} else {
mod.Error("error while fetching latest release info from GitHub: %s", err)
}
return nil
}
......@@ -35,7 +35,7 @@ func (mod *WiFiModule) startAp() error {
if !mod.Running() {
return errNoRecon
} else if mod.apRunning {
return session.ErrAlreadyStarted
return session.ErrAlreadyStarted(mod.Name())
}
go func() {
......
......@@ -230,9 +230,9 @@ func (m *SessionModule) Running() bool {
func (m *SessionModule) SetRunning(running bool, cb func()) error {
if running == m.Running() {
if m.Started {
return ErrAlreadyStarted
return ErrAlreadyStarted(m.Name)
} else {
return ErrAlreadyStopped
return ErrAlreadyStopped(m.Name)
}
}
......
......@@ -35,14 +35,20 @@ const (
var (
I = (*Session)(nil)
ErrAlreadyStarted = errors.New("module is already running")
ErrAlreadyStopped = errors.New("module is not running")
ErrNotSupported = errors.New("this component is not supported on this OS")
ErrNotSupported = errors.New("this component is not supported on this OS")
reCmdSpaceCleaner = regexp.MustCompile(`^([^\s]+)\s+(.+)$`)
reEnvVarCapture = regexp.MustCompile(`{env\.([^}]+)}`)
)
func ErrAlreadyStarted(name string) error {
return fmt.Errorf("module %s is already running", name)
}
func ErrAlreadyStopped(name string) error {
return fmt.Errorf("module %s is not running", name)
}
type UnknownCommandCallback func(cmd string) bool
type GPS struct {
......
......@@ -13,6 +13,8 @@ import (
// 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 outFile *os.File
var zipFile io.ReadCloser
var filenames []string
r, err := zip.OpenReader(src)
......@@ -21,33 +23,55 @@ func Unzip(src string, dest string) ([]string, error) {
}
defer r.Close()
clean := func() {
if outFile != nil {
outFile.Close()
outFile = nil
}
if zipFile != nil {
zipFile.Close()
zipFile = nil
}
}
for _, f := range r.File {
rc, err := f.Open()
zipFile, 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)) {
clean()
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 {
clean()
continue
}
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
clean()
return filenames, err
} else if outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()); err != nil {
}
outFile, err = os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
clean()
return filenames, err
}
_, err = io.Copy(outFile, zipFile)
clean()
if err != nil {
return filenames, err
} else {
defer outFile.Close()
if _, err = io.Copy(outFile, rc); err != nil {
return filenames, err
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment