[BUG] JARM function bypasses SOCKS5 proxy and reveals real IP
Is there an existing issue for this?
- [x] I have searched the existing issues.
Current Behavior
When performing a scan on my cloud server using Nuclei with a SOCKS5 proxy configured via the -p flag, my real IP address is observed in the server logs. Upon investigation, it was determined that the jarm function, specifically when used with the cobalt-strike-c2-jarm.yaml template, is the cause of this issue. Additionally, no network traffic appears to be routed through the configured proxy.
Command used:
nuclei.exe -u https://myserverip/ -p socks5://127.0.0.1:7890 -pi=true -vv -ts -duc -t \templates\network\jarm\c2\cobalt-strike-c2-jarm.yaml
Expected Behavior
The expected behavior is for all network traffic, including that generated by the jarm function, to be routed through the configured SOCKS5 proxy. Consequently, the scanned server's logs should show the proxy's IP address, not my real IP address.
Steps To Reproduce
- Set up a SOCKS5 proxy (e.g., on
127.0.0.1:7890). - Run the following Nuclei command targeting a personal cloud server (replace
https://myserverip/with your server's actual IP/URL):nuclei.exe -u https://myserverip/ -p socks5://127.0.0.1:7890 -pi=true -vv -ts -duc -t \templates\network\jarm\c2\cobalt-strike-c2-jarm.yaml - Monitor the access logs on
myserverip.
Environment
- OS: Windows 11
- Nuclei: v3.4.7
- Go: go1.24.1
Anything else?
The issue seems to stem from the jarm function's implementation not utilizing the globally configured SOCKS5 proxy. A potential solution involves modifying the github.com/projectdiscovery/utils/crypto/jarm/jarm.go and github.com/projectdiscovery/dsl/dsl.go packages to explicitly handle SOCKS5 proxy connections for JARM hashing when the -pi flag is used, leveraging the HTTP_PROXY environment variable.
Proposed code changes:
-
Add
Socks5WrapperDialerandCreateSOCKS5Dialertogithub.com/projectdiscovery/utils/crypto/jarm/jarm.go:type Socks5WrapperDialer struct { dialer proxy.Dialer } func (s *Socks5WrapperDialer) Dial(ctx context.Context, network, address string) (net.Conn, error) { conn, err := s.dialer.Dial(network, address) if err != nil { return nil, fmt.Errorf("failed to connect via SOCKS5 proxy: %w", err) } return conn, nil } func CreateSOCKS5Dialer(socks5ProxyURLStr string) (connpool.Dialer, error) { proxyURL, err := url.Parse(socks5ProxyURLStr) if err != nil { return nil, fmt.Errorf("failed to parse proxy URL: %v", err) } if proxyURL.Scheme != "socks5" { return nil, fmt.Errorf("unsupported proxy scheme: %s, only socks5 is supported", proxyURL.Scheme) } var auth *proxy.Auth // Extract authentication information (if present) if proxyURL.User != nil { username := proxyURL.User.Username() password, hasPassword := proxyURL.User.Password() if hasPassword { auth = &proxy.Auth{User: username, Password: password} } else { auth = &proxy.Auth{User: username} } } // Create the SOCKS5 dialer socks5ProxyDialer, err := proxy.SOCKS5("tcp", proxyURL.Host, auth, proxy.Direct) if err != nil { return nil, fmt.Errorf("failed to create SOCKS5 proxy dialer: %w", err) } return &Socks5WrapperDialer{dialer: socks5ProxyDialer}, nil } -
Modify
jarmfunction ingithub.com/projectdiscovery/dsl/dsl.go:MustAddFunction(NewWithPositionalArgs("jarm", 1, true, func(args ...interface{}) (interface{}, error) { host, ok := args[0].(string) if !ok { return nil, errors.New("invalid target") } hostname, portRaw, err := net.SplitHostPort(host) if err != nil { return nil, err } port, err := strconv.Atoi(portRaw) if err != nil { return nil, err } proxy := os.Getenv("HTTP_PROXY") if proxy == "" { proxy = os.Getenv("http_proxy") } if proxy != "" { socks5Dialer, err := jarm.CreateSOCKS5Dialer(proxy) if err != nil { return "", err } return jarm.HashWithDialer(socks5Dialer, hostname, port, 10) } return jarm.HashWithDialer(nil, hostname, port, 10) }))
@Zcentury Thanks for reporting the issue, this will be indirectly fixed upon new https://github.com/projectdiscovery/dsl release