diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index a9a770f0..8a44b25c 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -99,7 +99,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download Artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v4 with: pattern: release-artifacts-* merge-multiple: true diff --git a/README.md b/README.md index ed1a583b..299e1d78 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,6 @@ Tests on macOS Tests on Windows Docker Hub - This project is 100% made by humans. -

diff --git a/core/banner.go b/core/banner.go index 1a63f0c8..45c7557a 100644 --- a/core/banner.go +++ b/core/banner.go @@ -2,7 +2,7 @@ package core const ( Name = "bettercap" - Version = "2.41.4" + Version = "2.41.1" Author = "Simone 'evilsocket' Margaritelli" Website = "https://bettercap.org/" ) diff --git a/modules/api_rest/api_rest.go b/modules/api_rest/api_rest.go index b4590e18..b0c8a069 100644 --- a/modules/api_rest/api_rest.go +++ b/modules/api_rest/api_rest.go @@ -90,12 +90,12 @@ func NewRestAPI(s *session.Session) *RestAPI { "Value of the Access-Control-Allow-Origin header of the API server.")) mod.AddParam(session.NewStringParameter("api.rest.username", - "user", + "", "", "API authentication username.")) mod.AddParam(session.NewStringParameter("api.rest.password", - "pass", + "", "", "API authentication password.")) diff --git a/modules/http_server/http_server.go b/modules/http_server/http_server.go index da309d3d..25cd7802 100644 --- a/modules/http_server/http_server.go +++ b/modules/http_server/http_server.go @@ -31,20 +31,20 @@ func NewHttpServer(s *session.Session) *HttpServer { mod.AddParam(session.NewStringParameter("http.server.address", session.ParamIfaceAddress, session.IPv4Validator, - "Address to bind the HTTP server to.")) + "Address to bind the http server to.")) mod.AddParam(session.NewIntParameter("http.server.port", "80", - "Port to bind the HTTP server to.")) + "Port to bind the http server to.")) mod.AddHandler(session.NewModuleHandler("http.server on", "", - "Start HTTP server.", + "Start httpd server.", func(args []string) error { return mod.Start() })) mod.AddHandler(session.NewModuleHandler("http.server off", "", - "Stop HTTP server.", + "Stop httpd server.", func(args []string) error { return mod.Stop() })) diff --git a/modules/https_server/https_server.go b/modules/https_server/https_server.go index 2f3fd0a6..8e547fa7 100644 --- a/modules/https_server/https_server.go +++ b/modules/https_server/https_server.go @@ -35,11 +35,11 @@ func NewHttpsServer(s *session.Session) *HttpsServer { mod.AddParam(session.NewStringParameter("https.server.address", session.ParamIfaceAddress, session.IPv4Validator, - "Address to bind the HTTPS server to.")) + "Address to bind the http server to.")) mod.AddParam(session.NewIntParameter("https.server.port", "443", - "Port to bind the HTTPS server to.")) + "Port to bind the http server to.")) mod.AddParam(session.NewStringParameter("https.server.certificate", "~/.bettercap-httpd.cert.pem", @@ -54,13 +54,13 @@ func NewHttpsServer(s *session.Session) *HttpsServer { tls.CertConfigToModule("https.server", &mod.SessionModule, tls.DefaultLegitConfig) mod.AddHandler(session.NewModuleHandler("https.server on", "", - "Start HTTPS server.", + "Start https server.", func(args []string) error { return mod.Start() })) mod.AddHandler(session.NewModuleHandler("https.server off", "", - "Stop HTTPS server.", + "Stop https server.", func(args []string) error { return mod.Stop() })) diff --git a/modules/packet_proxy/packet_proxy_linux.go b/modules/packet_proxy/packet_proxy_linux.go index 9a40fcff..e69fe485 100644 --- a/modules/packet_proxy/packet_proxy_linux.go +++ b/modules/packet_proxy/packet_proxy_linux.go @@ -16,13 +16,15 @@ import ( "github.com/evilsocket/islazy/fs" ) +type hookFunc func(q *nfqueue.Nfqueue, a nfqueue.Attribute) int + type PacketProxy struct { session.SessionModule chainName string rule string queue *nfqueue.Nfqueue queueNum int - queueCb func(q *nfqueue.Nfqueue, a nfqueue.Attribute) int + queueCb hookFunc pluginPath string plugin *plugin.Plugin } @@ -149,7 +151,7 @@ func (mod *PacketProxy) Configure() (err error) { return } else if sym, err = mod.plugin.Lookup("OnPacket"); err != nil { return - } else if mod.queueCb, ok = sym.(func(q *nfqueue.Nfqueue, a nfqueue.Attribute) int); !ok { + } else if mod.queueCb, ok = sym.(hookFunc); !ok { return fmt.Errorf("Symbol OnPacket is not a valid callback function.") } diff --git a/modules/tcp_proxy/tcp_proxy_script.go b/modules/tcp_proxy/tcp_proxy_script.go index 50956ea0..fa801be5 100644 --- a/modules/tcp_proxy/tcp_proxy_script.go +++ b/modules/tcp_proxy/tcp_proxy_script.go @@ -1,7 +1,6 @@ package tcp_proxy import ( - "encoding/json" "net" "strings" @@ -56,36 +55,12 @@ func (s *TcpProxyScript) OnData(from, to net.Addr, data []byte, callback func(ca log.Error("error while executing onData callback: %s", err) return nil } else if ret != nil { - return toByteArray(ret) - } - } - return nil -} - -func toByteArray(ret interface{}) []byte { - // this approach is a bit hacky but it handles all cases - - // serialize ret to JSON - if jsonData, err := json.Marshal(ret); err == nil { - // attempt to deserialize as []float64 - var back2Array []float64 - if err := json.Unmarshal(jsonData, &back2Array); err == nil { - result := make([]byte, len(back2Array)) - for i, num := range back2Array { - if num >= 0 && num <= 255 { - result[i] = byte(num) - } else { - log.Error("array element at index %d is not a valid byte value %d", i, num) - return nil - } + array, ok := ret.([]byte) + if !ok { + log.Error("error while casting exported value to array of byte: value = %+v", ret) } - return result - } else { - log.Error("failed to deserialize %+v to []float64: %v", ret, err) + return array } - } else { - log.Error("failed to serialize %+v to JSON: %v", ret, err) } - return nil } diff --git a/modules/tcp_proxy/tcp_proxy_script_test.go b/modules/tcp_proxy/tcp_proxy_script_test.go deleted file mode 100644 index 27bdc099..00000000 --- a/modules/tcp_proxy/tcp_proxy_script_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package tcp_proxy - -import ( - "net" - "testing" - - "github.com/evilsocket/islazy/plugin" -) - -func TestOnData_NoReturn(t *testing.T) { - jsCode := ` - function onData(from, to, data, callback) { - // don't return anything - } - ` - - plug, err := plugin.Parse(jsCode) - if err != nil { - t.Fatalf("Failed to parse plugin: %v", err) - } - - script := &TcpProxyScript{ - Plugin: plug, - doOnData: plug.HasFunc("onData"), - } - - from := &net.TCPAddr{IP: net.ParseIP("192.168.1.1"), Port: 1234} - to := &net.TCPAddr{IP: net.ParseIP("192.168.1.2"), Port: 5678} - data := []byte("test data") - - result := script.OnData(from, to, data, nil) - if result != nil { - t.Errorf("Expected nil result when callback returns nothing, got %v", result) - } -} - -func TestOnData_ReturnsArrayOfIntegers(t *testing.T) { - jsCode := ` - function onData(from, to, data, callback) { - // Return modified data as array of integers - return [72, 101, 108, 108, 111]; // "Hello" in ASCII - } - ` - - plug, err := plugin.Parse(jsCode) - if err != nil { - t.Fatalf("Failed to parse plugin: %v", err) - } - - script := &TcpProxyScript{ - Plugin: plug, - doOnData: plug.HasFunc("onData"), - } - - from := &net.TCPAddr{IP: net.ParseIP("192.168.1.1"), Port: 1234} - to := &net.TCPAddr{IP: net.ParseIP("192.168.1.2"), Port: 5678} - data := []byte("test data") - - result := script.OnData(from, to, data, nil) - expected := []byte("Hello") - - if result == nil { - t.Fatal("Expected non-nil result when callback returns array of integers") - } - - if len(result) != len(expected) { - t.Fatalf("Expected result length %d, got %d", len(expected), len(result)) - } - - for i, b := range result { - if b != expected[i] { - t.Errorf("Expected byte at index %d to be %d, got %d", i, expected[i], b) - } - } -} - -func TestOnData_ReturnsDynamicArray(t *testing.T) { - jsCode := ` - function onData(from, to, data, callback) { - var result = []; - for (var i = 0; i < data.length; i++) { - result.push((data[i] + 1) % 256); - } - return result; - } - ` - - plug, err := plugin.Parse(jsCode) - if err != nil { - t.Fatalf("Failed to parse plugin: %v", err) - } - - script := &TcpProxyScript{ - Plugin: plug, - doOnData: plug.HasFunc("onData"), - } - - from := &net.TCPAddr{IP: net.ParseIP("192.168.1.1"), Port: 1234} - to := &net.TCPAddr{IP: net.ParseIP("192.168.1.2"), Port: 5678} - data := []byte{10, 20, 30, 40, 255} - - result := script.OnData(from, to, data, nil) - expected := []byte{11, 21, 31, 41, 0} // 255 + 1 = 256 % 256 = 0 - - if result == nil { - t.Fatal("Expected non-nil result when callback returns array of integers") - } - - if len(result) != len(expected) { - t.Fatalf("Expected result length %d, got %d", len(expected), len(result)) - } - - for i, b := range result { - if b != expected[i] { - t.Errorf("Expected byte at index %d to be %d, got %d", i, expected[i], b) - } - } -} - -func TestOnData_ReturnsMixedArray(t *testing.T) { - jsCode := ` - function charToInt(value) { - return value.charCodeAt() - } - - function onData(from, to, data) { - st_data = String.fromCharCode.apply(null, data) - if( st_data.indexOf("mysearch") != -1 ) { - payload = "mypayload"; - st_data = st_data.replace("mysearch", payload); - res_int_arr = st_data.split("").map(charToInt) // []uint16 - res_int_arr[0] = payload.length + 1; // first index is float64 and rest []uint16 - return res_int_arr; - } - return data; - } - ` - - plug, err := plugin.Parse(jsCode) - if err != nil { - t.Fatalf("Failed to parse plugin: %v", err) - } - - script := &TcpProxyScript{ - Plugin: plug, - doOnData: plug.HasFunc("onData"), - } - - from := &net.TCPAddr{IP: net.ParseIP("192.168.1.1"), Port: 1234} - to := &net.TCPAddr{IP: net.ParseIP("192.168.1.6"), Port: 5678} - data := []byte("Hello mysearch world") - - result := script.OnData(from, to, data, nil) - expected := []byte("\x0aello mypayload world") - - if result == nil { - t.Fatal("Expected non-nil result when callback returns array of integers") - } - - if len(result) != len(expected) { - t.Fatalf("Expected result length %d, got %d", len(expected), len(result)) - } - - for i, b := range result { - if b != expected[i] { - t.Errorf("Expected byte at index %d to be %d, got %d", i, expected[i], b) - } - } -} diff --git a/modules/ticker/ticker.go b/modules/ticker/ticker.go index 34c4c02b..e629d2f0 100644 --- a/modules/ticker/ticker.go +++ b/modules/ticker/ticker.go @@ -43,7 +43,7 @@ func NewTicker(s *session.Session) *Ticker { })) mod.AddHandler(session.NewModuleHandler("ticker off", "", - "Stop the main ticker.", + "Stop the maint icker.", func(args []string) error { return mod.Stop() })) diff --git a/modules/wifi/wifi.go b/modules/wifi/wifi.go index 2a000f4b..0cd0338f 100644 --- a/modules/wifi/wifi.go +++ b/modules/wifi/wifi.go @@ -265,8 +265,8 @@ func NewWiFiModule(s *session.Session) *WiFiModule { mod.AddHandler(probe) - channelSwitchAnnounce := session.NewModuleHandler("wifi.channel_switch_announce BSSID CHANNEL ", `wifi\.channel_switch_announce ((?:[a-fA-F0-9:]{11,}))\s+((?:[0-9]+))`, - "Start a 802.11 channel hop attack, all client will be forced to change the channel lead to connection down.", + channelSwitchAnnounce := session.NewModuleHandler("wifi.channel_switch_announce bssid channel ", `wifi\.channel_switch_announce ((?:[a-fA-F0-9:]{11,}))\s+((?:[0-9]+))`, + "Start a 802.11 channel hop attack, all client will be force to change the channel lead to connection down.", func(args []string) error { bssid, err := net.ParseMAC(args[0]) if err != nil { diff --git a/modules/wifi/wifi_test.go b/modules/wifi/wifi_test.go index afd5322c..2a580f32 100644 --- a/modules/wifi/wifi_test.go +++ b/modules/wifi/wifi_test.go @@ -518,6 +518,37 @@ func TestWiFiModuleProbe(t *testing.T) { } } +func TestWiFiModuleChannelSwitchAnnounce(t *testing.T) { + sess := createMockSession() + mod := NewWiFiModule(sess) + + // Test CSA handler + handlers := mod.Handlers() + var csaHandler session.ModuleHandler + for _, h := range handlers { + if h.Name == "wifi.channel_switch_announce bssid channel " { + csaHandler = h + break + } + } + + if csaHandler.Name == "" { + t.Fatal("CSA handler not found") + } + + // Test with valid parameters + err := csaHandler.Exec([]string{"aa:bb:cc:dd:ee:ff", "11"}) + if err == nil { + t.Error("Expected error when running CSA without running module") + } + + // Test with invalid channel + err = csaHandler.Exec([]string{"aa:bb:cc:dd:ee:ff", "999"}) + if err == nil { + t.Error("Expected error with invalid channel") + } +} + func TestWiFiModuleFakeAuth(t *testing.T) { sess := createMockSession() mod := NewWiFiModule(sess)