mirror of
https://github.com/bettercap/bettercap
synced 2025-08-19 21:13:18 -07:00
Merge branch 'master' into wifi.flood
This commit is contained in:
commit
8444a783a1
19 changed files with 279 additions and 82 deletions
2
build.sh
2
build.sh
|
@ -187,7 +187,7 @@ build_macos_amd64 && create_archive bettercap_macos_amd64_$VERSION.zip
|
||||||
build_android_arm && create_archive bettercap_android_arm_$VERSION.zip
|
build_android_arm && create_archive bettercap_android_arm_$VERSION.zip
|
||||||
build_windows_amd64 && create_exe_archive bettercap_windows_amd64_$VERSION.zip
|
build_windows_amd64 && create_exe_archive bettercap_windows_amd64_$VERSION.zip
|
||||||
build_linux_arm7_static && create_archive bettercap_linux_arm7_$VERSION.zip
|
build_linux_arm7_static && create_archive bettercap_linux_arm7_$VERSION.zip
|
||||||
build_linux_arm7hf_static && create_archive bettercap_linux_arm7hf_$VERSION.zip
|
# build_linux_arm7hf_static && create_archive bettercap_linux_arm7hf_$VERSION.zip
|
||||||
build_linux_mips_static && create_archive bettercap_linux_mips_$VERSION.zip
|
build_linux_mips_static && create_archive bettercap_linux_mips_$VERSION.zip
|
||||||
build_linux_mipsle_static && create_archive bettercap_linux_mipsle_$VERSION.zip
|
build_linux_mipsle_static && create_archive bettercap_linux_mipsle_$VERSION.zip
|
||||||
build_linux_mips64_static && create_archive bettercap_linux_mips64_$VERSION.zip
|
build_linux_mips64_static && create_archive bettercap_linux_mips64_$VERSION.zip
|
||||||
|
|
|
@ -2,7 +2,7 @@ package core
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Name = "bettercap"
|
Name = "bettercap"
|
||||||
Version = "2.1"
|
Version = "2.2"
|
||||||
Author = "Simone 'evilsocket' Margaritelli"
|
Author = "Simone 'evilsocket' Margaritelli"
|
||||||
Website = "https://bettercap.org/"
|
Website = "https://bettercap.org/"
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,7 +19,7 @@ type Options struct {
|
||||||
func ParseOptions() (Options, error) {
|
func ParseOptions() (Options, error) {
|
||||||
o := Options{
|
o := Options{
|
||||||
InterfaceName: flag.String("iface", "", "Network interface to bind to, if empty the default interface will be auto selected."),
|
InterfaceName: flag.String("iface", "", "Network interface to bind to, if empty the default interface will be auto selected."),
|
||||||
AutoStart: flag.String("autostart", "events.stream, net.recon", "Comma separated list of modules to auto start."),
|
AutoStart: flag.String("autostart", "events.stream, net.recon, update.check", "Comma separated list of modules to auto start."),
|
||||||
Caplet: flag.String("caplet", "", "Read commands from this file and execute them in the interactive session."),
|
Caplet: flag.String("caplet", "", "Read commands from this file and execute them in the interactive session."),
|
||||||
Debug: flag.Bool("debug", false, "Print debug messages."),
|
Debug: flag.Bool("debug", false, "Print debug messages."),
|
||||||
Silent: flag.Bool("silent", false, "Suppress all logs which are not errors."),
|
Silent: flag.Bool("silent", false, "Suppress all logs which are not errors."),
|
||||||
|
|
65
core/swag.go
65
core/swag.go
|
@ -5,6 +5,15 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DEBUG = iota
|
||||||
|
INFO
|
||||||
|
IMPORTANT
|
||||||
|
WARNING
|
||||||
|
ERROR
|
||||||
|
FATAL
|
||||||
|
)
|
||||||
|
|
||||||
// https://misc.flogisoft.com/bash/tip_colors_and_formatting
|
// https://misc.flogisoft.com/bash/tip_colors_and_formatting
|
||||||
var (
|
var (
|
||||||
BOLD = "\033[1m"
|
BOLD = "\033[1m"
|
||||||
|
@ -26,6 +35,24 @@ var (
|
||||||
|
|
||||||
RESET = "\033[0m"
|
RESET = "\033[0m"
|
||||||
|
|
||||||
|
LogLabels = map[int]string{
|
||||||
|
DEBUG: "dbg",
|
||||||
|
INFO: "inf",
|
||||||
|
IMPORTANT: "imp",
|
||||||
|
WARNING: "war",
|
||||||
|
ERROR: "err",
|
||||||
|
FATAL: "!!!",
|
||||||
|
}
|
||||||
|
|
||||||
|
LogColors = map[int]string{
|
||||||
|
DEBUG: DIM + FG_BLACK + BG_DGRAY,
|
||||||
|
INFO: FG_WHITE + BG_GREEN,
|
||||||
|
IMPORTANT: FG_WHITE + BG_LBLUE,
|
||||||
|
WARNING: FG_WHITE + BG_YELLOW,
|
||||||
|
ERROR: FG_WHITE + BG_RED,
|
||||||
|
FATAL: FG_WHITE + BG_RED + BOLD,
|
||||||
|
}
|
||||||
|
|
||||||
HasColors = true
|
HasColors = true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,38 +78,20 @@ func InitSwag(disableColors bool) {
|
||||||
BG_YELLOW = ""
|
BG_YELLOW = ""
|
||||||
BG_LBLUE = ""
|
BG_LBLUE = ""
|
||||||
RESET = ""
|
RESET = ""
|
||||||
|
|
||||||
|
LogColors = map[int]string{
|
||||||
|
DEBUG: "",
|
||||||
|
INFO: "",
|
||||||
|
IMPORTANT: "",
|
||||||
|
WARNING: "",
|
||||||
|
ERROR: "",
|
||||||
|
FATAL: "",
|
||||||
|
}
|
||||||
|
|
||||||
HasColors = false
|
HasColors = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
DEBUG = iota
|
|
||||||
INFO
|
|
||||||
IMPORTANT
|
|
||||||
WARNING
|
|
||||||
ERROR
|
|
||||||
FATAL
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
LogLabels = map[int]string{
|
|
||||||
DEBUG: "dbg",
|
|
||||||
INFO: "inf",
|
|
||||||
IMPORTANT: "imp",
|
|
||||||
WARNING: "war",
|
|
||||||
ERROR: "err",
|
|
||||||
FATAL: "!!!",
|
|
||||||
}
|
|
||||||
LogColors = map[int]string{
|
|
||||||
DEBUG: DIM + FG_BLACK + BG_DGRAY,
|
|
||||||
INFO: FG_WHITE + BG_GREEN,
|
|
||||||
IMPORTANT: FG_WHITE + BG_LBLUE,
|
|
||||||
WARNING: FG_WHITE + BG_YELLOW,
|
|
||||||
ERROR: FG_WHITE + BG_RED,
|
|
||||||
FATAL: FG_WHITE + BG_RED + BOLD,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// W for Wrap
|
// W for Wrap
|
||||||
func W(e, s string) string {
|
func W(e, s string) string {
|
||||||
return e + s + RESET
|
return e + s + RESET
|
||||||
|
|
|
@ -35,26 +35,14 @@ func (f WindowsFirewall) IsForwardingEnabled() bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f WindowsFirewall) isSuccess(output string) bool {
|
|
||||||
if trimmed := core.Trim(strings.ToUpper(output)); trimmed == "" || strings.Contains(trimmed, "OK") == true {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f WindowsFirewall) EnableForwarding(enabled bool) error {
|
func (f WindowsFirewall) EnableForwarding(enabled bool) error {
|
||||||
v := "enabled"
|
v := "enabled"
|
||||||
if enabled == false {
|
if enabled == false {
|
||||||
v = "disabled"
|
v = "disabled"
|
||||||
}
|
}
|
||||||
out, err := core.Exec("netsh", []string{"interface", "ipv4", "set", "interface", fmt.Sprintf("%d", f.iface.Index), fmt.Sprintf("forwarding=\"%s\"", v)})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.isSuccess(out) == false {
|
if _, err := core.Exec("netsh", []string{"interface", "ipv4", "set", "interface", fmt.Sprintf("%d", f.iface.Index), fmt.Sprintf("forwarding=\"%s\"", v)}); err != nil {
|
||||||
return fmt.Errorf("Unexpected netsh output: %s", out)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -90,15 +78,10 @@ func (f *WindowsFirewall) AllowPort(port int, address string, proto string, allo
|
||||||
cmd = []string{"advfirewall", "firewall", "delete", "rule", nameField, protoField, portField}
|
cmd = []string{"advfirewall", "firewall", "delete", "rule", nameField, protoField, portField}
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := core.Exec("netsh", cmd)
|
if _, err := core.Exec("netsh", cmd); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.isSuccess(out) == false {
|
|
||||||
return fmt.Errorf("Unexpected netsh output: %s", out)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,14 +99,10 @@ func (f *WindowsFirewall) EnableRedirection(r *Redirection, enabled bool) error
|
||||||
rule = append([]string{"interface", "portproxy", "delete", "v4tov4"}, rule...)
|
rule = append([]string{"interface", "portproxy", "delete", "v4tov4"}, rule...)
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := core.Exec("netsh", rule)
|
if _, err := core.Exec("netsh", rule); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.isSuccess(out) == false {
|
|
||||||
return fmt.Errorf("Unexpected netsh output: %s", out)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
main.go
1
main.go
|
@ -40,6 +40,7 @@ func main() {
|
||||||
|
|
||||||
sess.Register(modules.NewEventsStream(sess))
|
sess.Register(modules.NewEventsStream(sess))
|
||||||
sess.Register(modules.NewTicker(sess))
|
sess.Register(modules.NewTicker(sess))
|
||||||
|
sess.Register(modules.NewUpdateModule(sess))
|
||||||
sess.Register(modules.NewMacChanger(sess))
|
sess.Register(modules.NewMacChanger(sess))
|
||||||
sess.Register(modules.NewProber(sess))
|
sess.Register(modules.NewProber(sess))
|
||||||
sess.Register(modules.NewDiscovery(sess))
|
sess.Register(modules.NewDiscovery(sess))
|
||||||
|
|
|
@ -153,12 +153,11 @@ func (p *ArpSpoofer) parseTargets(targets string) (err error) {
|
||||||
targets = strings.Replace(targets, mac, "", -1)
|
targets = strings.Replace(targets, mac, "", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
targets = strings.TrimLeft(targets, ", ")
|
targets = strings.Trim(targets, ", ")
|
||||||
targets = strings.TrimRight(targets, ", ")
|
|
||||||
|
|
||||||
log.Debug("Parsing IP range %s", targets)
|
log.Debug("Parsing IP range %s", targets)
|
||||||
if len(p.macs) == 0 || targets != "" {
|
if len(p.macs) == 0 || targets != "" {
|
||||||
list, err := iprange.Parse(targets)
|
list, err := iprange.ParseList(targets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error while parsing arp.spoof.targets variable '%s': %s.", targets, err)
|
return fmt.Errorf("Error while parsing arp.spoof.targets variable '%s': %s.", targets, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package modules
|
package modules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -109,6 +110,69 @@ func (s *ProxyScript) defineBuiltins() error {
|
||||||
return otto.Value{}
|
return otto.Value{}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// log debug
|
||||||
|
s.VM.Set("log_debug", func(call otto.FunctionCall) otto.Value {
|
||||||
|
for _, v := range call.ArgumentList {
|
||||||
|
log.Debug("%s", v.String())
|
||||||
|
}
|
||||||
|
return otto.Value{}
|
||||||
|
})
|
||||||
|
|
||||||
|
// log info
|
||||||
|
s.VM.Set("log_info", func(call otto.FunctionCall) otto.Value {
|
||||||
|
for _, v := range call.ArgumentList {
|
||||||
|
log.Info("%s", v.String())
|
||||||
|
}
|
||||||
|
return otto.Value{}
|
||||||
|
})
|
||||||
|
|
||||||
|
// log warning
|
||||||
|
s.VM.Set("log_warn", func(call otto.FunctionCall) otto.Value {
|
||||||
|
for _, v := range call.ArgumentList {
|
||||||
|
log.Warning("%s", v.String())
|
||||||
|
}
|
||||||
|
return otto.Value{}
|
||||||
|
})
|
||||||
|
|
||||||
|
// log error
|
||||||
|
s.VM.Set("log_error", func(call otto.FunctionCall) otto.Value {
|
||||||
|
for _, v := range call.ArgumentList {
|
||||||
|
log.Error("%s", v.String())
|
||||||
|
}
|
||||||
|
return otto.Value{}
|
||||||
|
})
|
||||||
|
|
||||||
|
// log fatal
|
||||||
|
s.VM.Set("log_fatal", func(call otto.FunctionCall) otto.Value {
|
||||||
|
for _, v := range call.ArgumentList {
|
||||||
|
log.Fatal("%s", v.String())
|
||||||
|
}
|
||||||
|
return otto.Value{}
|
||||||
|
})
|
||||||
|
|
||||||
|
// javascript btoa function
|
||||||
|
s.VM.Set("btoa", func(call otto.FunctionCall) otto.Value {
|
||||||
|
varValue := base64.StdEncoding.EncodeToString([]byte(call.Argument(0).String()))
|
||||||
|
v, err := s.VM.ToValue(varValue)
|
||||||
|
if err != nil {
|
||||||
|
return errOtto("Could not convert to string: %s", varValue)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
})
|
||||||
|
|
||||||
|
// javascript atob function
|
||||||
|
s.VM.Set("atob", func(call otto.FunctionCall) otto.Value {
|
||||||
|
varValue, err := base64.StdEncoding.DecodeString(call.Argument(0).String())
|
||||||
|
if err != nil {
|
||||||
|
return errOtto("Could not decode string: %s", call.Argument(0).String())
|
||||||
|
}
|
||||||
|
v, err := s.VM.ToValue(string(varValue))
|
||||||
|
if err != nil {
|
||||||
|
return errOtto("Could not convert to string: %s", varValue)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
})
|
||||||
|
|
||||||
// read or write environment variable
|
// read or write environment variable
|
||||||
s.VM.Set("env", func(call otto.FunctionCall) otto.Value {
|
s.VM.Set("env", func(call otto.FunctionCall) otto.Value {
|
||||||
argv := call.ArgumentList
|
argv := call.ArgumentList
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"github.com/bettercap/bettercap/core"
|
"github.com/bettercap/bettercap/core"
|
||||||
"github.com/bettercap/bettercap/network"
|
"github.com/bettercap/bettercap/network"
|
||||||
"github.com/bettercap/bettercap/session"
|
"github.com/bettercap/bettercap/session"
|
||||||
|
|
||||||
|
"github.com/google/go-github/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
const eventTimeFormat = "15:04:05"
|
const eventTimeFormat = "15:04:05"
|
||||||
|
@ -23,7 +25,6 @@ func (s *EventsStream) viewLogEvent(e session.Event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *EventsStream) viewWiFiEvent(e session.Event) {
|
func (s *EventsStream) viewWiFiEvent(e session.Event) {
|
||||||
|
|
||||||
if strings.HasPrefix(e.Tag, "wifi.ap.") {
|
if strings.HasPrefix(e.Tag, "wifi.ap.") {
|
||||||
ap := e.Data.(*network.AccessPoint)
|
ap := e.Data.(*network.AccessPoint)
|
||||||
vend := ""
|
vend := ""
|
||||||
|
@ -167,6 +168,16 @@ func (s *EventsStream) viewSynScanEvent(e session.Event) {
|
||||||
core.Bold(se.Address))
|
core.Bold(se.Address))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *EventsStream) viewUpdateEvent(e session.Event) {
|
||||||
|
update := e.Data.(*github.RepositoryRelease)
|
||||||
|
|
||||||
|
fmt.Fprintf(s.output, "[%s] [%s] An update to version %s is available at %s\n",
|
||||||
|
e.Time.Format(eventTimeFormat),
|
||||||
|
core.Bold(core.Yellow(e.Tag)),
|
||||||
|
core.Bold(*update.TagName),
|
||||||
|
*update.HTMLURL)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *EventsStream) View(e session.Event, refresh bool) {
|
func (s *EventsStream) View(e session.Event, refresh bool) {
|
||||||
if e.Tag == "sys.log" {
|
if e.Tag == "sys.log" {
|
||||||
s.viewLogEvent(e)
|
s.viewLogEvent(e)
|
||||||
|
@ -180,8 +191,10 @@ func (s *EventsStream) View(e session.Event, refresh bool) {
|
||||||
s.viewModuleEvent(e)
|
s.viewModuleEvent(e)
|
||||||
} else if strings.HasPrefix(e.Tag, "net.sniff.") {
|
} else if strings.HasPrefix(e.Tag, "net.sniff.") {
|
||||||
s.viewSnifferEvent(e)
|
s.viewSnifferEvent(e)
|
||||||
} else if strings.HasPrefix(e.Tag, "syn.scan.") {
|
} else if e.Tag == "syn.scan" {
|
||||||
s.viewSynScanEvent(e)
|
s.viewSynScanEvent(e)
|
||||||
|
} else if e.Tag == "update.available" {
|
||||||
|
s.viewUpdateEvent(e)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(s.output, "[%s] [%s] %v\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), e)
|
fmt.Fprintf(s.output, "[%s] [%s] %v\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,6 @@ func (t *CookieTracker) keyOf(req *http.Request) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *CookieTracker) IsClean(req *http.Request) bool {
|
func (t *CookieTracker) IsClean(req *http.Request) bool {
|
||||||
// t.RLock()
|
|
||||||
// defer t.RUnlock()
|
|
||||||
|
|
||||||
// we only clean GET requests
|
// we only clean GET requests
|
||||||
if req.Method != "GET" {
|
if req.Method != "GET" {
|
||||||
return true
|
return true
|
||||||
|
@ -53,6 +50,9 @@ func (t *CookieTracker) IsClean(req *http.Request) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.RLock()
|
||||||
|
defer t.RUnlock()
|
||||||
|
|
||||||
// was it already processed?
|
// was it already processed?
|
||||||
if _, found := t.set[t.keyOf(req)]; found == true {
|
if _, found := t.set[t.keyOf(req)]; found == true {
|
||||||
return true
|
return true
|
||||||
|
@ -65,8 +65,7 @@ func (t *CookieTracker) IsClean(req *http.Request) bool {
|
||||||
func (t *CookieTracker) Track(req *http.Request) {
|
func (t *CookieTracker) Track(req *http.Request) {
|
||||||
t.Lock()
|
t.Lock()
|
||||||
defer t.Unlock()
|
defer t.Unlock()
|
||||||
reqKey := t.keyOf(req)
|
t.set[t.keyOf(req)] = true
|
||||||
t.set[reqKey] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *CookieTracker) Expire(req *http.Request) *http.Response {
|
func (t *CookieTracker) Expire(req *http.Request) *http.Response {
|
||||||
|
|
|
@ -88,6 +88,16 @@ func (j *JSRequest) WasModified() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *JSRequest) Header(name, deflt string) string {
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
for _, h := range j.Headers {
|
||||||
|
if name == strings.ToLower(h.Name) {
|
||||||
|
return h.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deflt
|
||||||
|
}
|
||||||
|
|
||||||
func (j *JSRequest) ReadBody() string {
|
func (j *JSRequest) ReadBody() string {
|
||||||
raw, err := ioutil.ReadAll(j.req.Body)
|
raw, err := ioutil.ReadAll(j.req.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -73,6 +73,17 @@ func (j *JSResponse) WasModified() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *JSResponse) Header(name, deflt string) string {
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
for _, header := range strings.Split(j.Headers, "\n") {
|
||||||
|
parts := strings.SplitN(core.Trim(header), ":", 2)
|
||||||
|
if len(parts) == 2 && strings.ToLower(parts[0]) == name {
|
||||||
|
return parts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deflt
|
||||||
|
}
|
||||||
|
|
||||||
func (j *JSResponse) ToResponse(req *http.Request) (resp *http.Response) {
|
func (j *JSResponse) ToResponse(req *http.Request) (resp *http.Response) {
|
||||||
resp = goproxy.NewResponse(req, j.ContentType, j.Status, j.Body)
|
resp = goproxy.NewResponse(req, j.ContentType, j.Status, j.Body)
|
||||||
if j.Headers != "" {
|
if j.Headers != "" {
|
||||||
|
|
|
@ -38,7 +38,7 @@ func NewSynScanner(s *session.Session) *SynScanner {
|
||||||
waitGroup: &sync.WaitGroup{},
|
waitGroup: &sync.WaitGroup{},
|
||||||
}
|
}
|
||||||
|
|
||||||
ss.AddHandler(session.NewModuleHandler("syn.scan IP-RANGE START-PORT END-PORT", "syn.scan ([^\\s]+) (\\d+)([\\s\\d]*)",
|
ss.AddHandler(session.NewModuleHandler("syn.scan IP-RANGE [START-PORT] [END-PORT]", "syn.scan ([^\\s]+) ?(\\d+)?([\\s\\d]*)?",
|
||||||
"Perform a syn port scanning against an IP address within the provided ports range.",
|
"Perform a syn port scanning against an IP address within the provided ports range.",
|
||||||
func(args []string) error {
|
func(args []string) error {
|
||||||
if ss.Running() == true {
|
if ss.Running() == true {
|
||||||
|
@ -50,20 +50,22 @@ func NewSynScanner(s *session.Session) *SynScanner {
|
||||||
return fmt.Errorf("Error while parsing IP range '%s': %s", args[0], err)
|
return fmt.Errorf("Error while parsing IP range '%s': %s", args[0], err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ss.addresses = list.Expand()
|
|
||||||
ss.startPort = 0
|
|
||||||
ss.endPort = 0
|
|
||||||
|
|
||||||
if ss.startPort, err = strconv.Atoi(core.Trim(args[1])); err != nil {
|
|
||||||
return fmt.Errorf("Invalid START-PORT: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ss.startPort > 65535 {
|
|
||||||
ss.startPort = 65535
|
|
||||||
}
|
|
||||||
ss.endPort = ss.startPort
|
|
||||||
|
|
||||||
argc := len(args)
|
argc := len(args)
|
||||||
|
ss.addresses = list.Expand()
|
||||||
|
ss.startPort = 1
|
||||||
|
ss.endPort = 65535
|
||||||
|
|
||||||
|
if argc > 1 && core.Trim(args[1]) != "" {
|
||||||
|
if ss.startPort, err = strconv.Atoi(core.Trim(args[1])); err != nil {
|
||||||
|
return fmt.Errorf("Invalid START-PORT: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ss.startPort > 65535 {
|
||||||
|
ss.startPort = 65535
|
||||||
|
}
|
||||||
|
ss.endPort = ss.startPort
|
||||||
|
}
|
||||||
|
|
||||||
if argc > 2 && core.Trim(args[2]) != "" {
|
if argc > 2 && core.Trim(args[2]) != "" {
|
||||||
if ss.endPort, err = strconv.Atoi(core.Trim(args[2])); err != nil {
|
if ss.endPort, err = strconv.Atoi(core.Trim(args[2])); err != nil {
|
||||||
return fmt.Errorf("Invalid END-PORT: %s", err)
|
return fmt.Errorf("Invalid END-PORT: %s", err)
|
||||||
|
|
96
modules/update.go
Normal file
96
modules/update.go
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bettercap/bettercap/core"
|
||||||
|
"github.com/bettercap/bettercap/log"
|
||||||
|
"github.com/bettercap/bettercap/session"
|
||||||
|
|
||||||
|
"github.com/google/go-github/github"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateModule struct {
|
||||||
|
session.SessionModule
|
||||||
|
client *github.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUpdateModule(s *session.Session) *UpdateModule {
|
||||||
|
u := &UpdateModule{
|
||||||
|
SessionModule: session.NewSessionModule("update", s),
|
||||||
|
client: github.NewClient(nil),
|
||||||
|
}
|
||||||
|
|
||||||
|
u.AddHandler(session.NewModuleHandler("update.check on", "",
|
||||||
|
"Check latest available stable version and compare it with the one being used.",
|
||||||
|
func(args []string) error {
|
||||||
|
return u.Start()
|
||||||
|
}))
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateModule) Name() string {
|
||||||
|
return "update"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateModule) Description() string {
|
||||||
|
return "A module to check for bettercap's updates."
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateModule) Author() string {
|
||||||
|
return "Simone Margaritelli <evilsocket@protonmail.com>"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateModule) Configure() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateModule) Stop() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateModule) versionToNum(ver string) float64 {
|
||||||
|
if ver[0] == 'v' {
|
||||||
|
ver = ver[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
n := 0.0
|
||||||
|
parts := strings.Split(ver, ".")
|
||||||
|
nparts := len(parts)
|
||||||
|
|
||||||
|
// reverse
|
||||||
|
for i := nparts/2 - 1; i >= 0; i-- {
|
||||||
|
opp := nparts - 1 - i
|
||||||
|
parts[i], parts[opp] = parts[opp], parts[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, e := range parts {
|
||||||
|
ev, _ := strconv.Atoi(e)
|
||||||
|
n += float64(ev) * math.Pow10(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UpdateModule) Start() error {
|
||||||
|
return u.SetRunning(true, func() {
|
||||||
|
defer u.SetRunning(false, nil)
|
||||||
|
|
||||||
|
log.Info("Checking latest stable release ...")
|
||||||
|
|
||||||
|
if releases, _, err := u.client.Repositories.ListReleases(context.Background(), "bettercap", "bettercap", nil); err == nil {
|
||||||
|
latest := releases[0]
|
||||||
|
if u.versionToNum(core.Version) < u.versionToNum(*latest.TagName) {
|
||||||
|
u.Session.Events.Add("update.available", latest)
|
||||||
|
} else {
|
||||||
|
log.Info("You are running %s which is the latest stable version.", core.Bold(core.Version))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Error("Error while fetching latest release info from GitHub: %s", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -38,6 +38,10 @@ func NewBLE(newcb BLEDevNewCallback, lostcb BLEDevLostCallback) *BLE {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BLE) Get(id string) (dev *BLEDevice, found bool) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (b *BLE) MarshalJSON() ([]byte, error) {
|
func (b *BLE) MarshalJSON() ([]byte, error) {
|
||||||
doc := bleJSON{
|
doc := bleJSON{
|
||||||
Devices: make([]*BLEDevice, 0),
|
Devices: make([]*BLEDevice, 0),
|
||||||
|
|
|
@ -8493,6 +8493,7 @@ F88E85 Comtrend
|
||||||
607EDD Microsoft Mobile Oy
|
607EDD Microsoft Mobile Oy
|
||||||
F88096 Elsys Equipamentos Eletrônicos Ltda
|
F88096 Elsys Equipamentos Eletrônicos Ltda
|
||||||
E0B9E5 Technicolor
|
E0B9E5 Technicolor
|
||||||
|
E2B9E5 Technicolor
|
||||||
0CBF15 Genetec
|
0CBF15 Genetec
|
||||||
000B5D Fujitsu Limited
|
000B5D Fujitsu Limited
|
||||||
F4CAE5 Freebox SAS
|
F4CAE5 Freebox SAS
|
||||||
|
|
|
@ -10315,6 +10315,7 @@ var oui = map[string]string {
|
||||||
"5cf286": "Ieee Registration Authority",
|
"5cf286": "Ieee Registration Authority",
|
||||||
"001098": "Starnet Technologies",
|
"001098": "Starnet Technologies",
|
||||||
"001099": "InnoMedia",
|
"001099": "InnoMedia",
|
||||||
|
"e2b9e5": "Technicolor",
|
||||||
"24ee3a": "Chengdu Yingji Electronic Hi-tech Co",
|
"24ee3a": "Chengdu Yingji Electronic Hi-tech Co",
|
||||||
"00093f": "Double-Win Enterpirse CO.",
|
"00093f": "Double-Win Enterpirse CO.",
|
||||||
"0026c6": "Intel Corporate",
|
"0026c6": "Intel Corporate",
|
||||||
|
|
|
@ -57,7 +57,7 @@ func NewEventPool(debug bool, silent bool) *EventPool {
|
||||||
func (p *EventPool) Listen() <-chan Event {
|
func (p *EventPool) Listen() <-chan Event {
|
||||||
p.Lock()
|
p.Lock()
|
||||||
defer p.Unlock()
|
defer p.Unlock()
|
||||||
l := make(chan Event, 1)
|
l := make(chan Event, 255)
|
||||||
p.listeners = append(p.listeners, l)
|
p.listeners = append(p.listeners, l)
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,7 @@ func (p *EventPool) Add(tag string, data interface{}) {
|
||||||
select {
|
select {
|
||||||
case l <- e:
|
case l <- e:
|
||||||
default:
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "Message not sent!\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -32,6 +33,8 @@ var (
|
||||||
|
|
||||||
ErrAlreadyStarted = errors.New("Module is already running.")
|
ErrAlreadyStarted = errors.New("Module is already running.")
|
||||||
ErrAlreadyStopped = errors.New("Module is not running.")
|
ErrAlreadyStopped = errors.New("Module is not running.")
|
||||||
|
|
||||||
|
reCmdSpaceCleaner = regexp.MustCompile(`^([^\s]+)\s+(.+)$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
|
@ -254,7 +257,6 @@ func (s *Session) Close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Firewall.Restore()
|
s.Firewall.Restore()
|
||||||
s.Queue.Stop()
|
|
||||||
|
|
||||||
if *s.Options.EnvFile != "" {
|
if *s.Options.EnvFile != "" {
|
||||||
envFile, _ := core.ExpandPath(*s.Options.EnvFile)
|
envFile, _ := core.ExpandPath(*s.Options.EnvFile)
|
||||||
|
@ -480,6 +482,11 @@ func (s *Session) RunCaplet(filename string) error {
|
||||||
|
|
||||||
func (s *Session) Run(line string) error {
|
func (s *Session) Run(line string) error {
|
||||||
line = core.TrimRight(line)
|
line = core.TrimRight(line)
|
||||||
|
// remove extra spaces after the first command
|
||||||
|
// so that 'arp.spoof on' is normalized
|
||||||
|
// to 'arp.spoof on' (fixes #178)
|
||||||
|
line = reCmdSpaceCleaner.ReplaceAllString(line, "$1 $2")
|
||||||
|
|
||||||
for _, h := range s.CoreHandlers {
|
for _, h := range s.CoreHandlers {
|
||||||
if parsed, args := h.Parse(line); parsed == true {
|
if parsed, args := h.Parse(line); parsed == true {
|
||||||
return h.Exec(args, s)
|
return h.Exec(args, s)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue