Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions cmd/nuclei/ssh.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
id: ssh-auth-methods

info:
name: SSH Auth Methods - Detection
author: Ice3man543
severity: info
description: |
SSH (Secure Shell) authentication modes are methods used to verify the identity of users and ensure secure access to remote systems. Common SSH authentication modes include password-based authentication, which relies on a secret passphrase, and public key authentication, which uses cryptographic keys for a more secure and convenient login process. Additionally, multi-factor authentication (MFA) can be employed to enhance security by requiring users to provide multiple forms of authentication, such as a password and a one-time code.
reference:
- https://nmap.org/nsedoc/scripts/ssh-auth-methods.html
metadata:
max-request: 1
shodan-query: product:"OpenSSH"
tags: js,detect,ssh,enum,network

javascript:
- pre-condition: |
isPortOpen(Host,Port);
code: |
var m = require("nuclei/ssh");
var c = m.SSHClient();
var response = c.ConnectSSHInfoMode(Host, Port);
Export(response);
args:
Host: "{{Host}}"
Port: "222,22"

extractors:
- type: json
json:
- '.UserAuth'
31 changes: 25 additions & 6 deletions pkg/protocols/javascript/js.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/projectdiscovery/utils/errkit"
iputil "github.com/projectdiscovery/utils/ip"
mapsutil "github.com/projectdiscovery/utils/maps"
sliceutil "github.com/projectdiscovery/utils/slice"
syncutil "github.com/projectdiscovery/utils/sync"
urlutil "github.com/projectdiscovery/utils/url"
)
Expand Down Expand Up @@ -133,8 +134,11 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
}

// "Port" is a special variable and it should not contains any dsl expressions
if strings.Contains(request.getPort(), "{{") {
return errkit.New("'Port' variable cannot contain any dsl expressions")
ports := request.getPorts()
for _, port := range ports {
if strings.Contains(port, "{{") {
return errkit.New("'Port' variable cannot contain any dsl expressions")
}
}

if request.Init != "" {
Expand Down Expand Up @@ -281,12 +285,26 @@ func (request *Request) GetID() string {

// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
func (request *Request) ExecuteWithResults(target *contextargs.Context, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
// Get default port(s) if specified in template
ports := request.getPorts()

for _, port := range ports {
err := request.executeWithResults(port, target, dynamicValues, previous, callback)
if err != nil {
return err
}
}

return nil
}
Comment on lines +288 to +301

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Templates without Port won't execute.

When getPorts() returns an empty slice (no Port specified in template args), the loop doesn't execute and the function returns immediately. This breaks existing JavaScript templates that don't specify a Port argument.

Apply this diff to execute once with an empty port when no ports are specified:

 func (request *Request) ExecuteWithResults(target *contextargs.Context, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
 	// Get default port(s) if specified in template
 	ports := request.getPorts()
+	if len(ports) == 0 {
+		ports = []string{""}
+	}
 
 	for _, port := range ports {
 		err := request.executeWithResults(port, target, dynamicValues, previous, callback)
 		if err != nil {
 			return err
 		}
 	}
 
 	return nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Get default port(s) if specified in template
ports := request.getPorts()
for _, port := range ports {
err := request.executeWithResults(port, target, dynamicValues, previous, callback)
if err != nil {
return err
}
}
return nil
}
func (request *Request) ExecuteWithResults(target *contextargs.Context, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
// Get default port(s) if specified in template
ports := request.getPorts()
if len(ports) == 0 {
ports = []string{""}
}
for _, port := range ports {
err := request.executeWithResults(port, target, dynamicValues, previous, callback)
if err != nil {
return err
}
}
return nil
}
🤖 Prompt for AI Agents
In pkg/protocols/javascript/js.go around lines 288 to 299, the current logic
returns immediately when request.getPorts() yields an empty slice, which
prevents templates without a Port arg from running; change the flow so that if
ports is empty you call request.executeWithResults once with an empty-string (or
zero-value) port (preserving the same target, dynamicValues, previous, callback)
and return any error; otherwise keep iterating over ports and return any error
from each call. Ensure you do not alter error handling semantics and that a
single execution occurs when no ports are specified.


// executeWithResults executes the request
func (request *Request) executeWithResults(port string, target *contextargs.Context, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
input := target.Clone()
// use network port updates input with new port requested in template file
// and it is ignored if input port is not standard http(s) ports like 80,8080,8081 etc
// idea is to reduce redundant dials to http ports
if err := input.UseNetworkPort(request.getPort(), request.getExcludePorts()); err != nil {
if err := input.UseNetworkPort(port, request.getExcludePorts()); err != nil {
gologger.Debug().Msgf("Could not network port from constants: %s\n", err)
}

Expand Down Expand Up @@ -755,13 +773,14 @@ func (request *Request) Type() templateTypes.ProtocolType {
return templateTypes.JavascriptProtocol
}

func (request *Request) getPort() string {
func (request *Request) getPorts() []string {
for k, v := range request.Args {
if strings.EqualFold(k, "Port") {
return types.ToString(v)
ports := types.ToStringSlice(strings.Split(types.ToString(v), ","))
return sliceutil.Dedupe(ports)
}
}
return ""
return []string{}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

func (request *Request) getExcludePorts() string {
Expand Down
Loading