From cfc6d55462a881f5997f1732e18c9dfbd577891d Mon Sep 17 00:00:00 2001
From: evilsocket
Date: Mon, 18 Aug 2025 15:25:26 +0200
Subject: [PATCH 1/7] misc: removed bogus test
---
modules/wifi/wifi_test.go | 31 -------------------------------
1 file changed, 31 deletions(-)
diff --git a/modules/wifi/wifi_test.go b/modules/wifi/wifi_test.go
index 2a580f32..afd5322c 100644
--- a/modules/wifi/wifi_test.go
+++ b/modules/wifi/wifi_test.go
@@ -518,37 +518,6 @@ 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)
From cc475ddfba538c2c1b7c7b4039aaa5bae73dff2b Mon Sep 17 00:00:00 2001
From: evilsocket
Date: Mon, 18 Aug 2025 17:08:14 +0200
Subject: [PATCH 2/7] hotfix: fixed tcp_proxy onData bug
---
modules/tcp_proxy/tcp_proxy_script.go | 76 ++++++++++---
modules/tcp_proxy/tcp_proxy_script_test.go | 118 +++++++++++++++++++++
2 files changed, 178 insertions(+), 16 deletions(-)
create mode 100644 modules/tcp_proxy/tcp_proxy_script_test.go
diff --git a/modules/tcp_proxy/tcp_proxy_script.go b/modules/tcp_proxy/tcp_proxy_script.go
index 7121a1a4..60f103ea 100644
--- a/modules/tcp_proxy/tcp_proxy_script.go
+++ b/modules/tcp_proxy/tcp_proxy_script.go
@@ -55,23 +55,67 @@ 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 {
- // thanks to @LucasParsy for his code and patience :)
- if array, ok := ret.([]interface{}); ok {
- result := make([]byte, len(array))
- for i, v := range array {
- if num, ok := v.(float64); ok && num >= 0 && num <= 255 {
- result[i] = byte(num)
- } else {
- log.Error("array element at index %d is not a valid byte value %+v", i, v)
- return nil
- }
- }
-
- return result
- } else {
- log.Error("error while casting exported value to array of interface: value = %+v error = %+v", ret, err)
- }
+ return toByteArray(ret)
}
}
return nil
}
+
+func toByteArray(ret interface{}) []byte {
+ // Handle different array types that otto.Export() might return
+ switch v := ret.(type) {
+ case []interface{}:
+ // Mixed type array
+ result := make([]byte, len(v))
+ for i, elem := range v {
+ if num, ok := toNumber(elem); ok && num >= 0 && num <= 255 {
+ result[i] = byte(num)
+ } else {
+ log.Error("array element at index %d is not a valid byte value %+v", i, elem)
+ return nil
+ }
+ }
+ return result
+ case []int64:
+ // Array of integers
+ result := make([]byte, len(v))
+ for i, num := range v {
+ 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
+ }
+ }
+ return result
+ case []float64:
+ // Array of floats
+ result := make([]byte, len(v))
+ for i, num := range v {
+ if num >= 0 && num <= 255 {
+ result[i] = byte(num)
+ } else {
+ log.Error("array element at index %d is not a valid byte value %f", i, num)
+ return nil
+ }
+ }
+ return result
+ default:
+ log.Error("unexpected array type returned from onData: %T, value = %+v", ret, ret)
+ return nil
+ }
+}
+
+// toNumber tries to convert an interface{} to a float64
+func toNumber(v interface{}) (float64, bool) {
+ switch n := v.(type) {
+ case float64:
+ return n, true
+ case int64:
+ return float64(n), true
+ case int:
+ return float64(n), true
+ default:
+ return 0, false
+ }
+}
diff --git a/modules/tcp_proxy/tcp_proxy_script_test.go b/modules/tcp_proxy/tcp_proxy_script_test.go
new file mode 100644
index 00000000..cb09b052
--- /dev/null
+++ b/modules/tcp_proxy/tcp_proxy_script_test.go
@@ -0,0 +1,118 @@
+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)
+ }
+ }
+}
From fc65cde72855a7b05e0c7903aab2b08c70e98578 Mon Sep 17 00:00:00 2001
From: evilsocket
Date: Mon, 18 Aug 2025 17:08:42 +0200
Subject: [PATCH 3/7] releasing version 2.41.3
---
core/banner.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/banner.go b/core/banner.go
index 860d1e49..5fdcebae 100644
--- a/core/banner.go
+++ b/core/banner.go
@@ -2,7 +2,7 @@ package core
const (
Name = "bettercap"
- Version = "2.41.2"
+ Version = "2.41.3"
Author = "Simone 'evilsocket' Margaritelli"
Website = "https://bettercap.org/"
)
From 42da6121131a222ea8ceda1810884733fa9a4224 Mon Sep 17 00:00:00 2001
From: evilsocket
Date: Mon, 18 Aug 2025 19:14:05 +0200
Subject: [PATCH 4/7] hotfix: hotfix 2 for tcp.proxy
---
modules/tcp_proxy/tcp_proxy_script.go | 78 +++++++---------------
modules/tcp_proxy/tcp_proxy_script_test.go | 51 ++++++++++++++
2 files changed, 75 insertions(+), 54 deletions(-)
diff --git a/modules/tcp_proxy/tcp_proxy_script.go b/modules/tcp_proxy/tcp_proxy_script.go
index 60f103ea..50956ea0 100644
--- a/modules/tcp_proxy/tcp_proxy_script.go
+++ b/modules/tcp_proxy/tcp_proxy_script.go
@@ -1,6 +1,7 @@
package tcp_proxy
import (
+ "encoding/json"
"net"
"strings"
@@ -62,60 +63,29 @@ func (s *TcpProxyScript) OnData(from, to net.Addr, data []byte, callback func(ca
}
func toByteArray(ret interface{}) []byte {
- // Handle different array types that otto.Export() might return
- switch v := ret.(type) {
- case []interface{}:
- // Mixed type array
- result := make([]byte, len(v))
- for i, elem := range v {
- if num, ok := toNumber(elem); ok && num >= 0 && num <= 255 {
- result[i] = byte(num)
- } else {
- log.Error("array element at index %d is not a valid byte value %+v", i, elem)
- return nil
- }
- }
- return result
- case []int64:
- // Array of integers
- result := make([]byte, len(v))
- for i, num := range v {
- 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
- }
- }
- return result
- case []float64:
- // Array of floats
- result := make([]byte, len(v))
- for i, num := range v {
- if num >= 0 && num <= 255 {
- result[i] = byte(num)
- } else {
- log.Error("array element at index %d is not a valid byte value %f", i, num)
- return nil
- }
- }
- return result
- default:
- log.Error("unexpected array type returned from onData: %T, value = %+v", ret, ret)
- return nil
- }
-}
+ // this approach is a bit hacky but it handles all cases
-// toNumber tries to convert an interface{} to a float64
-func toNumber(v interface{}) (float64, bool) {
- switch n := v.(type) {
- case float64:
- return n, true
- case int64:
- return float64(n), true
- case int:
- return float64(n), true
- default:
- return 0, false
+ // 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
+ }
+ }
+ return result
+ } else {
+ log.Error("failed to deserialize %+v to []float64: %v", ret, err)
+ }
+ } 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
index cb09b052..27bdc099 100644
--- a/modules/tcp_proxy/tcp_proxy_script_test.go
+++ b/modules/tcp_proxy/tcp_proxy_script_test.go
@@ -116,3 +116,54 @@ func TestOnData_ReturnsDynamicArray(t *testing.T) {
}
}
}
+
+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)
+ }
+ }
+}
From 4ec2753fad4a26096ea5c4cc11a38baaf39a3830 Mon Sep 17 00:00:00 2001
From: evilsocket
Date: Mon, 18 Aug 2025 19:15:44 +0200
Subject: [PATCH 5/7] releasing version 2.41.4
---
core/banner.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/banner.go b/core/banner.go
index 5fdcebae..1a63f0c8 100644
--- a/core/banner.go
+++ b/core/banner.go
@@ -2,7 +2,7 @@ package core
const (
Name = "bettercap"
- Version = "2.41.3"
+ Version = "2.41.4"
Author = "Simone 'evilsocket' Margaritelli"
Website = "https://bettercap.org/"
)
From 204997c8b51af7bc3c2c68ecfb232bbfcb840207 Mon Sep 17 00:00:00 2001
From: evilsocket
Date: Sat, 23 Aug 2025 14:22:11 +0200
Subject: [PATCH 6/7] misc: small fix or general refactoring i did not bother
commenting
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 299e1d78..c1ecdf39 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,10 @@
+
+
+
+
From 1001cea8f2af70fdcafae1dc08be3e52a17a7bbf Mon Sep 17 00:00:00 2001
From: evilsocket
Date: Sat, 23 Aug 2025 17:12:07 +0200
Subject: [PATCH 7/7] misc: small fix or general refactoring i did not bother
commenting
---
README.md | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/README.md b/README.md
index c1ecdf39..ed1a583b 100644
--- a/README.md
+++ b/README.md
@@ -16,9 +16,7 @@
-
-
-
+