diff --git a/README.md b/README.md index b5e33f9d..5c629da6 100644 --- a/README.md +++ b/README.md @@ -142,115 +142,7 @@ function onResponse(req, res) { ## Interactive Mode -Interactive mode allows you to start and stop modules manually on the fly, change options and apply new firewall rules on the fly, the basic commands are: - -| Command | Description | -| ------- | ------------| -| help | Display list of available commands. | -| active | Show information about active modules. | -| exit | Close the session and exit. | -| sleep SECONDS | Sleep for the given amount of seconds. | -| get NAME | Get the value of variable NAME, use * for all. | -| set NAME VALUE | Set the VALUE of variable NAME. | - -For instance you can view a list of declared variables with `get *` and set new ones, for example `set some.new.variable some-value`, for a list of every module and its parameters, issue the `help` command: - - 192.168.1.0/24 > 192.168.1.17 ยป help - - Basic commands: - - help : Display list of available commands. - active : Show information about active modules. - exit : Close the session and exit. - sleep SECONDS : Sleep for the given amount of seconds. - get NAME : Get the value of variable NAME, use * for all. - set NAME VALUE : Set the VALUE of variable NAME. - - ARP Spoofer - Keep spoofing selected hosts on the network. - - arp.spoof on : Start ARP spoofer. - arp.spoof off : Stop ARP spoofer. - - Parameters - - arp.spoof.targets : IP addresses to spoof. (default=) - - - Events Stream - Print events as a continuous stream. - - events.stream on : Start events stream. - events.stream off : Stop events stream. - events.clear : Clear events stream. - - Parameters - - events.stream.filter : If filled, filter events by this prefix type. (default=) - - - HTTP Proxy - A full featured HTTP proxy that can be used to inject malicious contents into webpages, all HTTP traffic will be redirected to it. - - http.proxy on : Start HTTP proxy. - http.proxy off : Stop HTTP proxy. - - Parameters - - http.port : HTTP port to redirect when the proxy is activated. (default=80) - http.proxy.address : Address to bind the HTTP proxy to. (default=) - http.proxy.port : Port to bind the HTTP proxy to. (default=8080) - http.proxy.script : Path of a proxy JS script. (default=) - - - Network Prober - Keep probing for new hosts on the network by sending dummy UDP packets to every possible IP on the subnet. - - net.probe on : Start network hosts probing in background. - net.probe off : Stop network hosts probing in background. - - Parameters - - net.probe.throttle : If greater than 0, probe packets will be throttled by this value in milliseconds. (default=10) - - - Network Recon - Read periodically the ARP cache in order to monitor for new hosts on the network. - - net.recon on : Start network hosts discovery. - net.recon off : Stop network hosts discovery. - net.show : Show current hosts list. - - Network Sniffer - Sniff packets from the network. - - net.sniffer stats : Print sniffer session configuration and statistics. - net.sniffer on : Start network sniffer in background. - net.sniffer off : Stop network sniffer in background. - - Parameters - - net.sniffer.regexp : If filled, only packets matching this regular expression will be considered. (default=) - net.sniffer.output : If set, the sniffer will write captured packets to this file. (default=) - net.sniffer.verbose : Print captured packets to screen. (default=true) - net.sniffer.local : If true it will consider packets from/to this computer, otherwise it will skip them. (default=false) - net.sniffer.filter : BPF filter for the sniffer. (default=not arp) - - - REST API - Expose a RESTful API. - - api.rest on : Start REST API server. - api.rest off : Stop REST API server. - - Parameters - - api.rest.address : Address to bind the API REST server to. (default=) - api.rest.port : Port to bind the API REST server to. (default=8083) - api.rest.username : API authentication username. (default=) - api.rest.certificate : API TLS certificate. (default=~/.bettercap-ng.api.rest.certificate.pem) - api.rest.key : API TLS key (default=~/.bettercap-ng.api.rest.key.pem) - api.rest.password : API authentication password. (default=) +Interactive mode allows you to start and stop modules manually on the fly, change options and apply new firewall rules on the fly, to show the help menu type `help`, you can have module specific help by using `help module-name`. ## License diff --git a/modules/api_rest.go b/modules/api_rest.go index e3ed287e..b50d9b83 100644 --- a/modules/api_rest.go +++ b/modules/api_rest.go @@ -84,7 +84,7 @@ type JSSessionResponse struct { } func (api *RestAPI) Name() string { - return "REST API" + return "api.rest" } func (api *RestAPI) Description() string { diff --git a/modules/arp_spoof.go b/modules/arp_spoof.go index af6eeaf4..37d0dba9 100644 --- a/modules/arp_spoof.go +++ b/modules/arp_spoof.go @@ -53,7 +53,7 @@ func (p *ArpSpoofer) OnSessionEnded(s *session.Session) { } func (p ArpSpoofer) Name() string { - return "ARP Spoofer" + return "arp.spoof" } func (p ArpSpoofer) Description() string { diff --git a/modules/events_stream.go b/modules/events_stream.go index f9452a04..3b9e4cea 100644 --- a/modules/events_stream.go +++ b/modules/events_stream.go @@ -47,7 +47,7 @@ func NewEventsStream(s *session.Session) *EventsStream { } func (s EventsStream) Name() string { - return "Events Stream" + return "events.stream" } func (s EventsStream) Description() string { diff --git a/modules/http_proxy.go b/modules/http_proxy.go index 5f9c4427..511b65c7 100644 --- a/modules/http_proxy.go +++ b/modules/http_proxy.go @@ -115,7 +115,7 @@ func NewHttpProxy(s *session.Session) *HttpProxy { } func (p *HttpProxy) Name() string { - return "HTTP Proxy" + return "http.proxy" } func (p *HttpProxy) Description() string { diff --git a/modules/net_probe.go b/modules/net_probe.go index d12dbe6a..9d40c0d6 100644 --- a/modules/net_probe.go +++ b/modules/net_probe.go @@ -40,7 +40,7 @@ func NewProber(s *session.Session) *Prober { } func (p Prober) Name() string { - return "Network Prober" + return "net.probe" } func (p Prober) Description() string { diff --git a/modules/net_recon.go b/modules/net_recon.go index 396e1882..57f3af8c 100644 --- a/modules/net_recon.go +++ b/modules/net_recon.go @@ -49,7 +49,7 @@ func NewDiscovery(s *session.Session) *Discovery { } func (d Discovery) Name() string { - return "Network Recon" + return "net.recon" } func (d Discovery) Description() string { diff --git a/modules/net_sniff.go b/modules/net_sniff.go index fd1e5bd3..34b7c458 100644 --- a/modules/net_sniff.go +++ b/modules/net_sniff.go @@ -165,7 +165,7 @@ func NewSniffer(s *session.Session) *Sniffer { } func (s Sniffer) Name() string { - return "Network Sniffer" + return "net.sniff" } func (s Sniffer) Description() string { diff --git a/session/session.go b/session/session.go index 16630421..86a24695 100644 --- a/session/session.go +++ b/session/session.go @@ -6,6 +6,7 @@ import ( "os" "os/signal" "os/user" + "sort" "strings" "syscall" @@ -76,6 +77,15 @@ func New() (*Session, error) { return s, nil } +func (s *Session) Module(name string) (err error, mod Module) { + for _, m := range s.Modules { + if m.Name() == name { + return nil, m + } + } + return fmt.Errorf("Module %s not found", name), mod +} + func (s *Session) setupInput() error { var err error @@ -138,6 +148,11 @@ func (s *Session) Register(mod Module) error { func (s *Session) Start() error { var err error + // make sure modules are always sorted by name + sort.Slice(s.Modules, func(i, j int) bool { + return s.Modules[i].Name() < s.Modules[j].Name() + }) + net.OuiInit() if s.Interface, err = net.FindInterface(*s.Options.InterfaceName); err != nil { diff --git a/session/session_core_handlers.go b/session/session_core_handlers.go index 2e6b5e95..55467ddf 100644 --- a/session/session_core_handlers.go +++ b/session/session_core_handlers.go @@ -2,7 +2,6 @@ package session import ( "fmt" - "sort" "strconv" "strings" "time" @@ -11,26 +10,46 @@ import ( ) func (s *Session) helpHandler(args []string, sess *Session) error { - fmt.Println() - fmt.Printf("Basic commands:\n\n") - for _, h := range s.CoreHandlers { - fmt.Printf(" "+core.Bold("%"+strconv.Itoa(s.HelpPadding)+"s")+" : %s\n", h.Name, h.Description) + filter := "" + if len(args) == 2 { + filter = args[1] } - sort.Slice(s.Modules, func(i, j int) bool { - return s.Modules[i].Name() < s.Modules[j].Name() - }) + if filter == "" { + fmt.Println() + fmt.Printf(core.Bold("MAIN COMMANDS\n\n")) + for _, h := range s.CoreHandlers { + fmt.Printf(" "+core.Yellow("%"+strconv.Itoa(s.HelpPadding)+"s")+" : %s\n", h.Name, h.Description) + } + + fmt.Printf(core.Bold("\nMODULES\n")) + + for _, m := range s.Modules { + status := "" + if m.Running() { + status = core.Green("running") + } else { + status = core.Red("not running") + } + fmt.Printf(" "+core.Yellow("%"+strconv.Itoa(s.HelpPadding)+"s")+" > %s\n", m.Name(), status) + } + + fmt.Println() + + } else { + err, m := s.Module(filter) + if err != nil { + return err + } - for _, m := range s.Modules { fmt.Println() status := "" if m.Running() { - status = core.Green("active") + status = core.Green("running") } else { - status = core.Red("not active") + status = core.Red("not running") } - fmt.Printf("%s [%s]\n", m.Name(), status) - fmt.Println(core.Dim(m.Description()) + "\n") + fmt.Printf("%s (%s): %s\n\n", core.Yellow(m.Name()), status, core.Dim(m.Description())) for _, h := range m.Handlers() { fmt.Printf(h.Help(s.HelpPadding)) } @@ -132,6 +151,11 @@ func (s *Session) registerCoreHandlers() { "Display list of available commands.", s.helpHandler)) + s.CoreHandlers = append(s.CoreHandlers, NewCommandHandler("help MODULE", + "^(help|\\?) (.+)$", + "Show module specific help.", + s.helpHandler)) + s.CoreHandlers = append(s.CoreHandlers, NewCommandHandler("active", "^active$", "Show information about active modules.",