Commit f31c7fa8 authored by Sophie Brun's avatar Sophie Brun

New upstream version 2.14

parent dcaf42df
......@@ -59,7 +59,7 @@
revision = "2ce16c963a8ac5bd6af851d4877e38701346983f"
[[projects]]
digest = "1:495dc25bbfe6025e945e3efe885801fc1aefc33d835cac453c0e36a35693d839"
digest = "1:88e0bcc18d131d663b1d1c449e91207bcc008978eb3eee7ac4a12ef9a8c8924c"
name = "github.com/evilsocket/islazy"
packages = [
"data",
......@@ -71,8 +71,8 @@
"zip",
]
pruneopts = "UT"
revision = "05aa0b30334a79a11bc2072179722d6de727490e"
version = "v1.9.2"
revision = "cbdab98bdf66f776cf87f90f51328c7b41348125"
version = "v1.9.3"
[[projects]]
branch = "master"
......@@ -108,7 +108,7 @@
version = "v1.0.0"
[[projects]]
digest = "1:65e00adfb37f64ce3c24f139bc73db70bfe45224ebaf88250eff4038e32ac9cf"
digest = "1:b23296076e13a960263285b98907623e5d45f12fc405b14da19c6afa2a113deb"
name = "github.com/google/gopacket"
packages = [
".",
......@@ -117,7 +117,7 @@
"pcapgo",
]
pruneopts = "UT"
revision = "d67ddb98d5a1b7c79a8977ec2d552e1db45eda86"
revision = "v1.1.16"
[[projects]]
digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1"
......
......@@ -57,7 +57,7 @@
[[constraint]]
name = "github.com/google/gopacket"
revision = "d67ddb98d5a1b7c79a8977ec2d552e1db45eda86"
revision = "v1.1.16"
[[constraint]]
name = "github.com/gorilla/mux"
......
......@@ -2,7 +2,7 @@ package core
const (
Name = "bettercap"
Version = "2.13.1"
Version = "2.14"
Author = "Simone 'evilsocket' Margaritelli"
Website = "https://bettercap.org/"
)
......@@ -52,6 +52,7 @@ func main() {
sess.Register(modules.NewHttpProxy(sess))
sess.Register(modules.NewHttpsProxy(sess))
sess.Register(modules.NewHttpServer(sess))
sess.Register(modules.NewHttpsServer(sess))
sess.Register(modules.NewRestAPI(sess))
sess.Register(modules.NewWOL(sess))
sess.Register(modules.NewWiFiModule(sess))
......@@ -93,14 +94,8 @@ func main() {
for sess.Active {
line, err := sess.ReadLine()
if err != nil {
if err == io.EOF {
continue
} else if err.Error() == "Interrupt" {
var ans string
fmt.Printf("Are you sure you want to quit this session? y/n ")
fmt.Scan(&ans)
if strings.ToLower(ans) == "y" {
if err == io.EOF || err.Error() == "Interrupt" {
if exitPrompt() {
sess.Run("exit")
os.Exit(0)
}
......@@ -117,3 +112,11 @@ func main() {
}
}
}
func exitPrompt() bool {
var ans string
fmt.Printf("Are you sure you want to quit this session? y/n ")
fmt.Scan(&ans)
return strings.ToLower(ans) == "y"
}
......@@ -25,62 +25,7 @@ func (s *EventsStream) viewLogEvent(e session.Event) {
e.Data.(session.LogMessage).Message)
}
func (s *EventsStream) viewWiFiEvent(e session.Event) {
if strings.HasPrefix(e.Tag, "wifi.ap.") {
ap := e.Data.(*network.AccessPoint)
vend := ""
if ap.Vendor != "" {
vend = fmt.Sprintf(" (%s)", ap.Vendor)
}
rssi := ""
if ap.RSSI != 0 {
rssi = fmt.Sprintf(" (%d dBm)", ap.RSSI)
}
if e.Tag == "wifi.ap.new" {
fmt.Fprintf(s.output, "[%s] [%s] wifi access point %s%s detected as %s%s.\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
tui.Bold(ap.ESSID()),
tui.Dim(tui.Yellow(rssi)),
tui.Green(ap.BSSID()),
tui.Dim(vend))
} else if e.Tag == "wifi.ap.lost" {
fmt.Fprintf(s.output, "[%s] [%s] wifi access point %s (%s) lost.\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
tui.Red(ap.ESSID()),
ap.BSSID())
} else {
fmt.Fprintf(s.output, "[%s] [%s] %s\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
ap.String())
}
} else if e.Tag == "wifi.client.probe" {
probe := e.Data.(WiFiProbe)
desc := ""
if probe.FromAlias != "" {
desc = fmt.Sprintf(" (%s)", probe.FromAlias)
} else if probe.FromVendor != "" {
desc = fmt.Sprintf(" (%s)", probe.FromVendor)
}
rssi := ""
if probe.RSSI != 0 {
rssi = fmt.Sprintf(" (%d dBm)", probe.RSSI)
}
fmt.Fprintf(s.output, "[%s] [%s] station %s%s is probing for SSID %s%s\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
probe.FromAddr.String(),
tui.Dim(desc),
tui.Bold(probe.SSID),
tui.Yellow(rssi))
}
}
func (s *EventsStream) viewendpointEvent(e session.Event) {
func (s *EventsStream) viewEndpointEvent(e session.Event) {
t := e.Data.(*network.Endpoint)
vend := ""
name := ""
......@@ -104,10 +49,12 @@ func (s *EventsStream) viewendpointEvent(e session.Event) {
tui.Green(t.HwAddress),
tui.Dim(vend))
} else if e.Tag == "endpoint.lost" {
fmt.Fprintf(s.output, "[%s] [%s] endpoint %s%s lost.\n",
fmt.Fprintf(s.output, "[%s] [%s] endpoint %s%s %s%s lost.\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
tui.Red(t.IpAddress),
tui.Dim(name),
tui.Green(t.HwAddress),
tui.Dim(vend))
} else {
fmt.Fprintf(s.output, "[%s] [%s] %s\n",
......@@ -205,7 +152,7 @@ func (s *EventsStream) View(e session.Event, refresh bool) {
if e.Tag == "sys.log" {
s.viewLogEvent(e)
} else if strings.HasPrefix(e.Tag, "endpoint.") {
s.viewendpointEvent(e)
s.viewEndpointEvent(e)
} else if strings.HasPrefix(e.Tag, "wifi.") {
s.viewWiFiEvent(e)
} else if strings.HasPrefix(e.Tag, "ble.") {
......
package modules
import (
"fmt"
"strings"
"github.com/bettercap/bettercap/network"
"github.com/bettercap/bettercap/session"
"github.com/evilsocket/islazy/tui"
)
func (s *EventsStream) viewWiFiApEvent(e session.Event) {
ap := e.Data.(*network.AccessPoint)
vend := ""
if ap.Vendor != "" {
vend = fmt.Sprintf(" (%s)", ap.Vendor)
}
rssi := ""
if ap.RSSI != 0 {
rssi = fmt.Sprintf(" (%d dBm)", ap.RSSI)
}
if e.Tag == "wifi.ap.new" {
fmt.Fprintf(s.output, "[%s] [%s] wifi access point %s%s detected as %s%s.\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
tui.Bold(ap.ESSID()),
tui.Dim(tui.Yellow(rssi)),
tui.Green(ap.BSSID()),
tui.Dim(vend))
} else if e.Tag == "wifi.ap.lost" {
fmt.Fprintf(s.output, "[%s] [%s] wifi access point %s (%s) lost.\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
tui.Red(ap.ESSID()),
ap.BSSID())
} else {
fmt.Fprintf(s.output, "[%s] [%s] %s\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
ap.String())
}
}
func (s *EventsStream) viewWiFiClientProbeEvent(e session.Event) {
probe := e.Data.(WiFiProbeEvent)
desc := ""
if probe.FromAlias != "" {
desc = fmt.Sprintf(" (%s)", probe.FromAlias)
} else if probe.FromVendor != "" {
desc = fmt.Sprintf(" (%s)", probe.FromVendor)
}
rssi := ""
if probe.RSSI != 0 {
rssi = fmt.Sprintf(" (%d dBm)", probe.RSSI)
}
fmt.Fprintf(s.output, "[%s] [%s] station %s%s is probing for SSID %s%s\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
probe.FromAddr.String(),
tui.Dim(desc),
tui.Bold(probe.SSID),
tui.Yellow(rssi))
}
func (s *EventsStream) viewWiFiHandshakeEvent(e session.Event) {
hand := e.Data.(WiFiHandshakeEvent)
from := hand.Station.String()
to := hand.AP.String()
what := "handshake"
if ap, found := s.Session.WiFi.Get(hand.AP.String()); found {
to = fmt.Sprintf("%s (%s)", tui.Bold(ap.ESSID()), tui.Dim(ap.BSSID()))
what = fmt.Sprintf("%s handshake", ap.Encryption)
}
fmt.Fprintf(s.output, "[%s] [%s] captured %s -> %s %s to %s\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
from,
to,
tui.Red(what),
hand.File)
}
func (s *EventsStream) viewWiFiClientEvent(e session.Event) {
ce := e.Data.(WiFiClientEvent)
ce.Client.Alias = s.Session.Lan.GetAlias(ce.Client.BSSID())
if e.Tag == "wifi.client.new" {
fmt.Fprintf(s.output, "[%s] [%s] new station %s detected for %s (%s)\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
ce.Client.String(),
tui.Bold(ce.AP.ESSID()),
tui.Dim(ce.AP.BSSID()))
} else if e.Tag == "wifi.client.lost" {
fmt.Fprintf(s.output, "[%s] [%s] station %s disconnected from %s (%s)\n",
e.Time.Format(eventTimeFormat),
tui.Green(e.Tag),
ce.Client.String(),
tui.Bold(ce.AP.ESSID()),
tui.Dim(ce.AP.BSSID()))
}
}
func (s *EventsStream) viewWiFiEvent(e session.Event) {
if strings.HasPrefix(e.Tag, "wifi.ap.") {
s.viewWiFiApEvent(e)
} else if e.Tag == "wifi.client.probe" {
s.viewWiFiClientProbeEvent(e)
} else if e.Tag == "wifi.client.handshake" {
s.viewWiFiHandshakeEvent(e)
} else if e.Tag == "wifi.client.new" || e.Tag == "wifi.client.lost" {
s.viewWiFiClientEvent(e)
} else {
fmt.Fprintf(s.output, "[%s] [%s] %v\n", e.Time.Format(eventTimeFormat), tui.Green(e.Tag), e)
}
}
......@@ -9,17 +9,13 @@ import (
"github.com/bettercap/bettercap/log"
"github.com/bettercap/bettercap/session"
"github.com/bettercap/bettercap/tls"
"github.com/evilsocket/islazy/fs"
"github.com/evilsocket/islazy/tui"
)
type HttpServer struct {
session.SessionModule
server *http.Server
certFile string
keyFile string
server *http.Server
}
func NewHttpServer(s *session.Session) *HttpServer {
......@@ -42,18 +38,6 @@ func NewHttpServer(s *session.Session) *HttpServer {
"80",
"Port to bind the http server to."))
httpd.AddParam(session.NewStringParameter("http.server.certificate",
"",
"",
"TLS certificate file, if not empty will configure this as a HTTPS server (will be auto generated if filled but not existing)."))
httpd.AddParam(session.NewStringParameter("http.server.key",
"",
"",
"TLS key file, if not empty will configure this as a HTTPS server (will be auto generated if filled but not existing)."))
tls.CertConfigToModule("http.server", &httpd.SessionModule, tls.DefaultLegitConfig)
httpd.AddHandler(session.NewModuleHandler("http.server on", "",
"Start httpd server.",
func(args []string) error {
......@@ -81,17 +65,11 @@ func (httpd *HttpServer) Author() string {
return "Simone Margaritelli <evilsocket@protonmail.com>"
}
func (httpd *HttpServer) isTLS() bool {
return httpd.certFile != "" && httpd.keyFile != ""
}
func (httpd *HttpServer) Configure() error {
var err error
var path string
var address string
var port int
var certFile string
var keyFile string
if httpd.Running() {
return session.ErrAlreadyStarted
......@@ -121,40 +99,6 @@ func (httpd *HttpServer) Configure() error {
httpd.server.Addr = fmt.Sprintf("%s:%d", address, port)
if err, certFile = httpd.StringParam("http.server.certificate"); err != nil {
return err
} else if certFile, err = fs.Expand(certFile); err != nil {
return err
}
if err, keyFile = httpd.StringParam("http.server.key"); err != nil {
return err
} else if keyFile, err = fs.Expand(keyFile); err != nil {
return err
}
if certFile != "" && keyFile != "" {
if !fs.Exists(certFile) || !fs.Exists(keyFile) {
err, cfg := tls.CertConfigFromModule("http.server", httpd.SessionModule)
if err != nil {
return err
}
log.Debug("%+v", cfg)
log.Info("Generating server TLS key to %s", keyFile)
log.Info("Generating server TLS certificate to %s", certFile)
if err := tls.Generate(cfg, certFile, keyFile); err != nil {
return err
}
} else {
log.Info("loading server TLS key from %s", keyFile)
log.Info("loading server TLS certificate from %s", certFile)
}
}
httpd.certFile = certFile
httpd.keyFile = keyFile
return nil
}
......@@ -165,14 +109,8 @@ func (httpd *HttpServer) Start() error {
return httpd.SetRunning(true, func() {
var err error
if httpd.isTLS() {
log.Info("HTTPS server starting on https://%s", httpd.server.Addr)
err = httpd.server.ListenAndServeTLS(httpd.certFile, httpd.keyFile)
} else {
log.Info("HTTP server starting on http://%s", httpd.server.Addr)
err = httpd.server.ListenAndServe()
}
if err != nil && err != http.ErrServerClosed {
log.Info("HTTP server starting on http://%s", httpd.server.Addr)
if err = httpd.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
panic(err)
}
})
......
package modules
import (
"context"
"fmt"
"net/http"
"strings"
"time"
"github.com/bettercap/bettercap/log"
"github.com/bettercap/bettercap/session"
"github.com/bettercap/bettercap/tls"
"github.com/evilsocket/islazy/fs"
"github.com/evilsocket/islazy/tui"
)
type HttpsServer struct {
session.SessionModule
server *http.Server
certFile string
keyFile string
}
func NewHttpsServer(s *session.Session) *HttpsServer {
httpd := &HttpsServer{
SessionModule: session.NewSessionModule("https.server", s),
server: &http.Server{},
}
httpd.AddParam(session.NewStringParameter("https.server.path",
".",
"",
"Server folder."))
httpd.AddParam(session.NewStringParameter("https.server.address",
session.ParamIfaceAddress,
session.IPv4Validator,
"Address to bind the http server to."))
httpd.AddParam(session.NewIntParameter("https.server.port",
"443",
"Port to bind the http server to."))
httpd.AddParam(session.NewStringParameter("https.server.certificate",
"~/.bettercap-https.cert.pem",
"",
"TLS certificate file (will be auto generated if filled but not existing)."))
httpd.AddParam(session.NewStringParameter("https.server.key",
"~/.bettercap-https.key.pem",
"",
"TLS key file (will be auto generated if filled but not existing)."))
tls.CertConfigToModule("https.server", &httpd.SessionModule, tls.DefaultLegitConfig)
httpd.AddHandler(session.NewModuleHandler("https.server on", "",
"Start https server.",
func(args []string) error {
return httpd.Start()
}))
httpd.AddHandler(session.NewModuleHandler("https.server off", "",
"Stop https server.",
func(args []string) error {
return httpd.Stop()
}))
return httpd
}
func (httpd *HttpsServer) Name() string {
return "https.server"
}
func (httpd *HttpsServer) Description() string {
return "A simple HTTPS server, to be used to serve files and scripts across the network."
}
func (httpd *HttpsServer) Author() string {
return "Simone Margaritelli <evilsocket@protonmail.com>"
}
func (httpd *HttpsServer) Configure() error {
var err error
var path string
var address string
var port int
var certFile string
var keyFile string
if httpd.Running() {
return session.ErrAlreadyStarted
}
if err, path = httpd.StringParam("https.server.path"); err != nil {
return err
}
router := http.NewServeMux()
fileServer := http.FileServer(http.Dir(path))
router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Info("(%s) %s %s %s%s", tui.Green("https"), tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path)
fileServer.ServeHTTP(w, r)
}))
httpd.server.Handler = router
if err, address = httpd.StringParam("https.server.address"); err != nil {
return err
}
if err, port = httpd.IntParam("https.server.port"); err != nil {
return err
}
httpd.server.Addr = fmt.Sprintf("%s:%d", address, port)
if err, certFile = httpd.StringParam("https.server.certificate"); err != nil {
return err
} else if certFile, err = fs.Expand(certFile); err != nil {
return err
}
if err, keyFile = httpd.StringParam("https.server.key"); err != nil {
return err
} else if keyFile, err = fs.Expand(keyFile); err != nil {
return err
}
if !fs.Exists(certFile) || !fs.Exists(keyFile) {
err, cfg := tls.CertConfigFromModule("https.server", httpd.SessionModule)
if err != nil {
return err
}
log.Debug("%+v", cfg)
log.Info("generating server TLS key to %s", keyFile)
log.Info("generating server TLS certificate to %s", certFile)
if err := tls.Generate(cfg, certFile, keyFile); err != nil {
return err
}
} else {
log.Info("loading server TLS key from %s", keyFile)
log.Info("loading server TLS certificate from %s", certFile)
}
httpd.certFile = certFile
httpd.keyFile = keyFile
return nil
}
func (httpd *HttpsServer) Start() error {
if err := httpd.Configure(); err != nil {
return err
}
return httpd.SetRunning(true, func() {
log.Info("HTTPS server starting on https://%s", httpd.server.Addr)
if err := httpd.server.ListenAndServeTLS(httpd.certFile, httpd.keyFile); err != nil && err != http.ErrServerClosed {
panic(err)
}
})
}
func (httpd *HttpsServer) Stop() error {
return httpd.SetRunning(false, func() {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
httpd.server.Shutdown(ctx)
})
}
......@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"sort"
"strings"
"time"
"github.com/bettercap/bettercap/network"
......@@ -201,6 +202,23 @@ func (d *Discovery) colNames(hasMeta bool) []string {
return colNames
}
func (d *Discovery) showStatusBar() {
d.Session.Queue.Stats.RLock()
defer d.Session.Queue.Stats.RUnlock()
parts := []string{
fmt.Sprintf("%s %s", tui.Red("↑"), humanize.Bytes(d.Session.Queue.Stats.Sent)),
fmt.Sprintf("%s %s", tui.Green("↓"), humanize.Bytes(d.Session.Queue.Stats.Received)),
fmt.Sprintf("%d pkts", d.Session.Queue.Stats.PktReceived),
}
if nErrors := d.Session.Queue.Stats.Errors; nErrors > 0 {
parts = append(parts, fmt.Sprintf("%d errs", nErrors))
}
fmt.Printf("\n%s\n\n", strings.Join(parts, " / "))
}
func (d *Discovery) Show(arg string) (err error) {
var targets []*network.Endpoint
if err, targets = d.doSelection(arg); err != nil {
......@@ -240,15 +258,7 @@ func (d *Discovery) Show(arg string) (err error) {
tui.Table(os.Stdout, colNames, rows)
d.Session.Queue.Stats.RLock()
fmt.Printf("\n%s %s / %s %s / %d pkts / %d errs\n\n",
tui.Red("↑"),
humanize.Bytes(d.Session.Queue.Stats.Sent),
tui.Green("↓"),
humanize.Bytes(d.Session.Queue.Stats.Received),
d.Session.Queue.Stats.PktReceived,
d.Session.Queue.Stats.Errors)
d.Session.Queue.Stats.RUnlock()
d.showStatusBar()
d.Session.Refresh()
......
......@@ -4,7 +4,6 @@ import (
"fmt"
"net"
"strconv"
"strings"
"sync"
"time"
......@@ -17,6 +16,8 @@ import (
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/evilsocket/islazy/fs"
"github.com/evilsocket/islazy/str"
"github.com/evilsocket/islazy/tui"
)
......@@ -35,6 +36,8 @@ type WiFiModule struct {
pktSourceChanClosed bool
deauthSkip []net.HardwareAddr
deauthSilent bool
deauthOpen bool
shakesFile string
apRunning bool
apConfig packets.Dot11ApConfig
writes *sync.WaitGroup
......@@ -94,9 +97,12 @@ func NewWiFiModule(s *session.Session) *WiFiModule {
return err
}))
w.AddHandler(session.NewModuleHandler("wifi.deauth BSSID", `wifi\.deauth ((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2}))`,
"Start a 802.11 deauth attack, if an access point BSSID is provided, every client will be deauthenticated, otherwise only the selected client. Use a broadcast BSSID (ff:ff:ff:ff:ff:ff) to iterate every access point with at least one client and start a deauth attack for each one.",
w.AddHandler(session.NewModuleHandler("wifi.deauth BSSID", `wifi\.deauth ((?:[a-fA-F0-9:]{11,})|all|\*)`,
"Start a 802.11 deauth attack, if an access point BSSID is provided, every client will be deauthenticated, otherwise only the selected client. Use 'all', '*' or a broadcast BSSID (ff:ff:ff:ff:ff:ff) to iterate every access point with at least one client and start a deauth attack for each one.",
func(args []string) error {
if args[0] == "all" || args[0] == "*" {
args[0] = "ff:ff:ff:ff:ff:ff"
}
bssid, err := net.ParseMAC(args[0])
if err != nil {
return err
......@@ -113,6 +119,10 @@ func NewWiFiModule(s *session.Session) *WiFiModule {
"false",
"If true, messages from wifi.deauth will be suppressed."))
w.AddParam(session.NewBoolParameter("wifi.deauth.open",