From cbe879c145c14dd4e960dd1a02afaabc6db7020d Mon Sep 17 00:00:00 2001 From: Mzack9999 Date: Wed, 29 Oct 2025 15:42:07 +0400 Subject: [PATCH 1/3] improving lua script with args and values --- cmd/integration-test/javascript.go | 33 ++++++++++++ .../javascript/redis-lua-script.yaml | 27 ++++++++++ pkg/js/generated/ts/redis.ts | 7 ++- pkg/js/libs/redis/redis.go | 51 +++++++++++++++++-- 4 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 integration_tests/protocols/javascript/redis-lua-script.yaml diff --git a/cmd/integration-test/javascript.go b/cmd/integration-test/javascript.go index 6e99b7f844..dafa60a7a7 100644 --- a/cmd/integration-test/javascript.go +++ b/cmd/integration-test/javascript.go @@ -12,6 +12,7 @@ import ( var jsTestcases = []TestCaseInfo{ {Path: "protocols/javascript/redis-pass-brute.yaml", TestCase: &javascriptRedisPassBrute{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }}, + {Path: "protocols/javascript/redis-lua-script.yaml", TestCase: &javascriptRedisLuaScript{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }}, {Path: "protocols/javascript/ssh-server-fingerprint.yaml", TestCase: &javascriptSSHServerFingerprint{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }}, {Path: "protocols/javascript/net-multi-step.yaml", TestCase: &networkMultiStep{}}, {Path: "protocols/javascript/net-https.yaml", TestCase: &javascriptNetHttps{}}, @@ -70,6 +71,38 @@ func (j *javascriptRedisPassBrute) Execute(filePath string) error { return multierr.Combine(errs...) } +type javascriptRedisLuaScript struct{} + +func (j *javascriptRedisLuaScript) Execute(filePath string) error { + if redisResource == nil || pool == nil { + // skip test as redis is not running + return nil + } + tempPort := redisResource.GetPort("6379/tcp") + finalURL := "localhost:" + tempPort + defer purge(redisResource) + errs := []error{} + for i := 0; i < defaultRetry; i++ { + results := []string{} + var err error + _ = pool.Retry(func() error { + //let ssh server start + time.Sleep(3 * time.Second) + results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug) + return nil + }) + if err != nil { + return err + } + if err := expectResultsCount(results, 1); err == nil { + return nil + } else { + errs = append(errs, err) + } + } + return multierr.Combine(errs...) +} + type javascriptSSHServerFingerprint struct{} func (j *javascriptSSHServerFingerprint) Execute(filePath string) error { diff --git a/integration_tests/protocols/javascript/redis-lua-script.yaml b/integration_tests/protocols/javascript/redis-lua-script.yaml new file mode 100644 index 0000000000..f52c276b1e --- /dev/null +++ b/integration_tests/protocols/javascript/redis-lua-script.yaml @@ -0,0 +1,27 @@ +id: redis-lua-script + +info: + name: Redis RunLuaScript - Detect + author: DhiyaneshDK + severity: info + +javascript: + - code: | + const redis = require('nuclei/redis'); + // First call: Set a key-value pair using ARGV + const setResult = redis.RunLuaScript(Host, Port, Password, 'return redis.call("set", ARGV[1], ARGV[2])', [], ['testkey', 'testvalue']); + log(to_json(setResult)); + + // Second call: Retrieve the value we just set + const getResult = redis.RunLuaScript(Host, Port, Password, 'return redis.call("get", ARGV[1])', [], ['testkey']); + log(to_json(getResult)); + + args: + Host: "{{Host}}" + Port: "6379" + Password: "" + + matchers: + - type: dsl + dsl: + - "success == true" diff --git a/pkg/js/generated/ts/redis.ts b/pkg/js/generated/ts/redis.ts index fbab318363..2d7c4879c1 100755 --- a/pkg/js/generated/ts/redis.ts +++ b/pkg/js/generated/ts/redis.ts @@ -61,10 +61,13 @@ export function IsAuthenticated(host: string, port: number): boolean | null { * @example * ```javascript * const redis = require('nuclei/redis'); - * const result = redis.RunLuaScript('acme.com', 6379, 'password', 'return redis.call("get", KEYS[1])'); + * // Old signature (backwards compatible) - keys and args are optional + * const result = redis.RunLuaScript('acme.com', 6379, 'password', 'return redis.call("ping")'); + * // New signature with keys and args + * const result = redis.RunLuaScript('acme.com', 6379, 'password', 'return redis.call("get", KEYS[1])', ['mykey'], []); * ``` */ -export function RunLuaScript(host: string, port: number, password: string, script: string): any | null { +export function RunLuaScript(host: string, port: number, password: string, script: string, keys?: string[] | any, args?: string[] | any): any | null { return null; } diff --git a/pkg/js/libs/redis/redis.go b/pkg/js/libs/redis/redis.go index 84b96d86b3..694f8a6313 100644 --- a/pkg/js/libs/redis/redis.go +++ b/pkg/js/libs/redis/redis.go @@ -175,9 +175,12 @@ func isAuthenticated(executionId string, host string, port int) (bool, error) { // @example // ```javascript // const redis = require('nuclei/redis'); -// const result = redis.RunLuaScript('acme.com', 6379, 'password', 'return redis.call("get", KEYS[1])'); +// // Old signature (backwards compatible) - keys and args are optional +// const result = redis.RunLuaScript('acme.com', 6379, 'password', 'return redis.call("ping")'); +// // New signature with keys and args +// const result = redis.RunLuaScript('acme.com', 6379, 'password', 'return redis.call("get", KEYS[1])', ['mykey'], []); // ``` -func RunLuaScript(ctx context.Context, host string, port int, password string, script string) (interface{}, error) { +func RunLuaScript(ctx context.Context, host string, port int, password string, script string, keys interface{}, args interface{}) (interface{}, error) { executionId := ctx.Value("executionId").(string) if !protocolstate.IsHostAllowed(executionId, host) { // host is not valid according to network policy @@ -199,8 +202,48 @@ func RunLuaScript(ctx context.Context, host string, port int, password string, s return "", err } - // Get Redis server info - infoCmd := client.Eval(context.Background(), script, []string{}) + // Convert interface{} to []string for keys (handle backwards compatibility) + keysSlice := []string{} + if keys != nil { + switch v := keys.(type) { + case []string: + keysSlice = v + case []interface{}: + // Convert []interface{} to []string (from JavaScript arrays) + keysSlice = make([]string, 0, len(v)) + for _, item := range v { + if s, ok := item.(string); ok { + keysSlice = append(keysSlice, s) + } + } + } + } + + // Convert interface{} to []string for args (handle backwards compatibility) + argsSlice := []string{} + if args != nil { + switch v := args.(type) { + case []string: + argsSlice = v + case []interface{}: + // Convert []interface{} to []string (from JavaScript arrays) + argsSlice = make([]string, 0, len(v)) + for _, item := range v { + if s, ok := item.(string); ok { + argsSlice = append(argsSlice, s) + } + } + } + } + + // Convert []string args to []interface{} for Eval + argsInterface := make([]interface{}, len(argsSlice)) + for i, arg := range argsSlice { + argsInterface[i] = arg + } + + // Execute the Lua script with keys and args + infoCmd := client.Eval(context.Background(), script, keysSlice, argsInterface...) if infoCmd.Err() != nil { return "", infoCmd.Err() From b1cd543843670bcfc11bf98080e883930fc42763 Mon Sep 17 00:00:00 2001 From: Mzack9999 Date: Fri, 28 Nov 2025 21:47:27 +0400 Subject: [PATCH 2/3] fixing comments --- cmd/integration-test/javascript.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/integration-test/javascript.go b/cmd/integration-test/javascript.go index 34bae3140c..51028d82d9 100644 --- a/cmd/integration-test/javascript.go +++ b/cmd/integration-test/javascript.go @@ -55,7 +55,7 @@ func (j *javascriptRedisPassBrute) Execute(filePath string) error { results := []string{} var err error _ = pool.Retry(func() error { - //let ssh server start + // let redis server start time.Sleep(3 * time.Second) results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug) return nil @@ -87,7 +87,7 @@ func (j *javascriptRedisLuaScript) Execute(filePath string) error { results := []string{} var err error _ = pool.Retry(func() error { - //let ssh server start + // let redis server start time.Sleep(3 * time.Second) results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug) return nil @@ -119,7 +119,7 @@ func (j *javascriptSSHServerFingerprint) Execute(filePath string) error { results := []string{} var err error _ = pool.Retry(func() error { - //let ssh server start + // let ssh server start time.Sleep(3 * time.Second) results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug) return nil @@ -152,7 +152,7 @@ func (j *javascriptOracleAuthTest) Execute(filePath string) error { results := []string{} var err error _ = pool.Retry(func() error { - //let ssh server start + // let oracle server start time.Sleep(3 * time.Second) results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug) return nil @@ -184,7 +184,7 @@ func (j *javascriptVncPassBrute) Execute(filePath string) error { results := []string{} var err error _ = pool.Retry(func() error { - //let ssh server start + // let vnc server start time.Sleep(3 * time.Second) results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug) return nil From 921b3d3b95aadda84d4c0d8028769ab384a81db1 Mon Sep 17 00:00:00 2001 From: Mzack9999 Date: Fri, 28 Nov 2025 21:49:21 +0400 Subject: [PATCH 3/3] keys to string --- pkg/js/libs/redis/redis.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/js/libs/redis/redis.go b/pkg/js/libs/redis/redis.go index 694f8a6313..eadf778957 100644 --- a/pkg/js/libs/redis/redis.go +++ b/pkg/js/libs/redis/redis.go @@ -209,12 +209,9 @@ func RunLuaScript(ctx context.Context, host string, port int, password string, s case []string: keysSlice = v case []interface{}: - // Convert []interface{} to []string (from JavaScript arrays) keysSlice = make([]string, 0, len(v)) for _, item := range v { - if s, ok := item.(string); ok { - keysSlice = append(keysSlice, s) - } + keysSlice = append(keysSlice, fmt.Sprintf("%v", item)) } } }