Skip to content

CheckRDPEncryption function#6204

Merged
Mzack9999 merged 3 commits intodevfrom
RDP-Enc-func
Sep 25, 2025
Merged

CheckRDPEncryption function#6204
Mzack9999 merged 3 commits intodevfrom
RDP-Enc-func

Conversation

@pussycat0x
Copy link
Contributor

@pussycat0x pussycat0x commented May 1, 2025

Proposed changes

Detect RDP encryption using CheckRDPEncryption()

javascript:
  - code: |
      let m = require('nuclei/rdp');
      let response = m.CheckRDPEncryption(Host,Port);
      Export(response);

Checklist

  • Pull request is created against the dev branch
  • All checks passed (lint, unit/integration/regression tests etc.) with my changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Summary by CodeRabbit

  • New Features
    • Added the ability to probe an RDP server and report supported security layers (e.g., native RDP, SSL, CredSSP, TLS) and detailed encryption levels/cipher support.
    • Added caching for RDP encryption checks to speed up repeated queries and reduce duplicate network tests.

@auto-assign auto-assign bot requested a review from dogancanbakir May 1, 2025 12:56
@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 1, 2025

Walkthrough

Adds RDP probing: a new RDPEncryptionResponse type and CheckRDPEncryption(ctx, host, port) that actively probes RDP security layers and cipher strengths, plus a memoized wrapper memoizedcheckRDPEncryption(executionId, host, port) to cache probe results.

Changes

Cohort / File(s) Change Summary
RDP probing logic
pkg/js/libs/rdp/rdp.go
Added RDPEncryptionResponse type and CheckRDPEncryption(ctx context.Context, host string, port int) public API; implemented probing (checkRDPEncryption, testRDPProtocol, testRDPCipher) that performs TCP connects, sends probe packets, and interprets responses to populate security layer and encryption flags.
Memoization wrapper
pkg/js/libs/rdp/memo.rdp.go
Added memoizedcheckRDPEncryption(executionId string, host string, port int) that builds a cache key and delegates to protocolstate.Memoizer.Do to return cached or freshly computed RDPEncryptionResponse.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant RDPpkg as RDP package
    participant Memoizer
    participant Target as RDP Server

    Caller->>RDPpkg: CheckRDPEncryption(ctx, host, port)
    RDPpkg->>Memoizer: Do("checkRDPEncryption", executionId, host, port)
    alt cache hit
        Memoizer-->>RDPpkg: cached RDPEncryptionResponse
    else cache miss
        Memoizer-->>RDPpkg: callback -> checkRDPEncryption()
        RDPpkg->>Target: TCP connect + probe (protocol/cipher)
        Target-->>RDPpkg: probe responses
        RDPpkg->>RDPpkg: analyze -> RDPEncryptionResponse
        RDPpkg-->>Memoizer: store RDPEncryptionResponse
        Memoizer-->>RDPpkg: stored
    end
    RDPpkg-->>Caller: RDPEncryptionResponse
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I hop the nets at dusk and dawn,
I tap each port from lawn to lawn.
I test the ciphers, note each layer,
Then stash results safe with care.
A rabbit's cache — quick, quiet, keen. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly identifies the primary change introduced by the pull request, namely the addition of the CheckRDPEncryption function, and does so concisely without extraneous detail. It directly reflects the content of the diff and will be understandable to anyone scanning the project history.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch RDP-Enc-func

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pussycat0x pussycat0x linked an issue May 1, 2025 that may be closed by this pull request
@pussycat0x
Copy link
Contributor Author

Debug Data

./nuclei -u 127.0.0.1  -t rdp.yaml

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.4.2

                projectdiscovery.io

[INF] Current nuclei version: v3.4.2 (latest)
[INF] Current nuclei-templates version: v10.2.0 (latest)
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 268
[INF] Templates loaded for current scan: 1
[WRN] Loading 1 unsigned templates for scan. Use with caution.
[INF] Targets loaded for current scan: 1
[rdp-enc-check] [javascript] [info] 127.0.0.1:3389 ["{\n  "SecurityLayer": {\n    "NativeRDP": false,\n    "SSL": true,\n    "CredSSP": false,\n    "RDSTLS": true,\n    "CredSSPWithEarlyUserAuth": false\n  },\n  "EncryptionLevel": {\n    "RC4_40bit": false,\n    "RC4_56bit": false,\n    "RC4_128bit": false,\n    "FIPS140_1": false\n  }\n}"]

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
pkg/js/libs/rdp/memo.rdp.go (1)

43-57: Memoization logic looks solid – tiny opportunity for naming consistency

Behaviour mirrors the existing memoizedcheckRDPAuth implementation and should work as-is.
If you ever touch this file again, consider renaming all three helpers to memoizedCheckXYZ (capital C) for camel-case consistency, but this is definitely non-blocking.

pkg/js/libs/rdp/rdp.go (3)

127-140: Add JSON tags to keep the public JS API stable

toJSON() in the usage examples will currently serialise fields as NativeRDP, RC4_40bit, … which is fine, but any future refactor (e.g. renaming fields) could silently break templates.
Explicit JSON tags make the contract crystal-clear and avoid surprises.

-       SecurityLayer struct {
-           NativeRDP                bool
-           SSL                      bool
-           CredSSP                  bool
-           RDSTLS                   bool
-           CredSSPWithEarlyUserAuth bool
-       }
-       EncryptionLevel struct {
-           RC4_40bit  bool
-           RC4_56bit  bool
-           RC4_128bit bool
-           FIPS140_1  bool
-       }
+       SecurityLayer struct {
+           NativeRDP                bool `json:"native_rdp"`
+           SSL                      bool `json:"ssl"`
+           CredSSP                  bool `json:"credssp"`
+           RDSTLS                   bool `json:"rdstls"`
+           CredSSPWithEarlyUserAuth bool `json:"credssp_early_user_auth"`
+       } `json:"security_layer"`
+       EncryptionLevel struct {
+           RC4_40bit  bool `json:"rc4_40bit"`
+           RC4_56bit  bool `json:"rc4_56bit"`
+           RC4_128bit bool `json:"rc4_128bit"`
+           FIPS140_1  bool `json:"fips140_1"`
+       } `json:"encryption_level"`

194-201: Hard-coded magic numbers deserve named constants

Using integers 0,1,3,4,8 for protocols and 1,8,2,16 for ciphers makes the code error-prone.
Defining constants (or even slices of structs) improves readability and prevents accidental duplication.


229-243: Missing ingress‐egress validation & packet crafting disclaimer

The simplified TPDU you craft ([]byte{0x03,0x00,…}) may not trigger deterministic behaviour across all RDP implementations and could create false negatives.
Consider adding comments that this is heuristic-only and, if possible, move the magic slice into a const baseConnectionRequest = [...]byte{…} for maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbf57ef and 32845bc.

⛔ Files ignored due to path filters (3)
  • cmd/nuclei/rdp.yaml is excluded by !**/*.yaml
  • pkg/js/generated/go/librdp/rdp.go is excluded by !**/generated/**
  • pkg/js/generated/ts/rdp.ts is excluded by !**/generated/**
📒 Files selected for processing (2)
  • pkg/js/libs/rdp/memo.rdp.go (1 hunks)
  • pkg/js/libs/rdp/rdp.go (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Tests (macOS-latest)
  • GitHub Check: Tests (windows-latest)
  • GitHub Check: Tests (ubuntu-latest)

@pussycat0x pussycat0x self-assigned this May 1, 2025
@ehsandeep
Copy link
Member

@dogancanbakir any blockers on this? We can merge it with any required changes to get it ready.

@Mzack9999 Mzack9999 self-requested a review September 12, 2025 19:25
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
pkg/js/libs/rdp/rdp.go (3)

132-156: Stabilize marshaling surface (optional)

Consider adding explicit json tags and/or named nested types to future‑proof the JS/JSON shape and avoid accidental field renames.


243-281: Heuristic protocol negotiation is fragile

These magic‑byte writes/reads risk false positives and version variance. Prefer leveraging fingerprintx’s RDP negotiation primitives (as used in DetectRDP/DetectRDPAuth) to probe security layers, or extend that lib to expose needed signals.


282-316: Cipher probing via raw bytes is brittle

Same concern as above; consider a library‑backed negotiation to derive supported encryption levels reliably.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32845bc and 61bd082.

⛔ Files ignored due to path filters (1)
  • pkg/js/generated/go/librdp/rdp.go is excluded by !**/generated/**
📒 Files selected for processing (2)
  • pkg/js/libs/rdp/memo.rdp.go (1 hunks)
  • pkg/js/libs/rdp/rdp.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/js/libs/rdp/memo.rdp.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Format Go code using go fmt
Run static analysis with go vet

Files:

  • pkg/js/libs/rdp/rdp.go
🧬 Code graph analysis (1)
pkg/js/libs/rdp/rdp.go (1)
pkg/js/generated/ts/rdp.ts (2)
  • CheckRDPEncryption (26-28)
  • RDPEncryptionResponse (73-87)
🪛 GitHub Check: Lint
pkg/js/libs/rdp/rdp.go

[failure] 218-218:
undefined: protocolstate.Dialer (typecheck)


[failure] 185-185:
undefined: protocolstate.Dialer

🪛 GitHub Actions: 🔨 Tests
pkg/js/libs/rdp/rdp.go

[error] 185-185: undefined: protocolstate.Dialer (golangci-lint: undefined symbol in rdp.go line 185)

🔇 Additional comments (3)
pkg/js/libs/rdp/rdp.go (3)

6-6: Import looks correct

"net" is needed for net.Conn in helpers; no issues.


184-206: Fix compile error and fd leak in protocol loop

  • protocolstate.Dialer is undefined (pipeline failure).
  • defer conn.Close() inside loop leaks fds until function exit.

Apply this diff:

-	for name, value := range protocols {
-		conn, err := protocolstate.Dialer.Dial(context.TODO(), "tcp", fmt.Sprintf("%s:%d", host, port))
+	for name, value := range protocols {
+		conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", target)
 		if err != nil {
 			continue
 		}
-		defer conn.Close()
-
-		// Test protocol
-		isRDP, err := testRDPProtocol(conn, timeout, value)
+		// Test protocol
+		isRDP, err := testRDPProtocol(conn, timeout, value)
+		_ = conn.Close()
 		if err == nil && isRDP {
 			switch name {
 			case "NativeRDP":
 				resp.SecurityLayer.NativeRDP = true
 			case "SSL":
 				resp.SecurityLayer.SSL = true
 			case "CredSSP":
 				resp.SecurityLayer.CredSSP = true
 			case "RDSTLS":
 				resp.SecurityLayer.RDSTLS = true
 			case "CredSSPWithEarlyUserAuth":
 				resp.SecurityLayer.CredSSPWithEarlyUserAuth = true
 			}
 		}
 	}

As per coding guidelines


217-238: Same issues in cipher loop: undefined dialer and fd leak

Use Fastdialer and close immediately after testing.

Apply this diff:

-	for name, value := range ciphers {
-		conn, err := protocolstate.Dialer.Dial(context.TODO(), "tcp", fmt.Sprintf("%s:%d", host, port))
+	for name, value := range ciphers {
+		conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", target)
 		if err != nil {
 			continue
 		}
-		defer conn.Close()
-
-		// Test cipher
-		isRDP, err := testRDPCipher(conn, timeout, value)
+		// Test cipher
+		isRDP, err := testRDPCipher(conn, timeout, value)
+		_ = conn.Close()
 		if err == nil && isRDP {
 			switch name {
 			case "RC4_40bit":
 				resp.EncryptionLevel.RC4_40bit = true
 			case "RC4_56bit":
 				resp.EncryptionLevel.RC4_56bit = true
 			case "RC4_128bit":
 				resp.EncryptionLevel.RC4_128bit = true
 			case "FIPS140_1":
 				resp.EncryptionLevel.FIPS140_1 = true
 			}
 		}
 	}

As per coding guidelines

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61bd082 and cb2d931.

⛔ Files ignored due to path filters (1)
  • pkg/js/generated/ts/rdp.ts is excluded by !**/generated/**
📒 Files selected for processing (2)
  • pkg/js/libs/rdp/memo.rdp.go (1 hunks)
  • pkg/js/libs/rdp/rdp.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Format Go code using go fmt
Run static analysis with go vet

Files:

  • pkg/js/libs/rdp/rdp.go
  • pkg/js/libs/rdp/memo.rdp.go
🧬 Code graph analysis (2)
pkg/js/libs/rdp/rdp.go (2)
pkg/js/generated/ts/rdp.ts (2)
  • CheckRDPEncryption (26-28)
  • RDPEncryptionResponse (73-86)
pkg/protocols/common/protocolstate/state.go (1)
  • GetDialersWithId (39-45)
pkg/js/libs/rdp/memo.rdp.go (3)
pkg/js/libs/rdp/rdp.go (1)
  • RDPEncryptionResponse (165-178)
pkg/js/generated/ts/rdp.ts (1)
  • RDPEncryptionResponse (73-86)
pkg/protocols/common/protocolstate/memoizer.go (1)
  • Memoizer (7-7)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Tests (windows-latest)
  • GitHub Check: Tests (macOS-latest)
  • GitHub Check: Tests (ubuntu-latest)
🔇 Additional comments (1)
pkg/js/libs/rdp/memo.rdp.go (1)

43-57: Memoization wiring matches existing pattern

The new memoizedcheckRDPEncryption sticks to the existing Memoizer.Do convention and cleanly wraps checkRDPEncryption; looks good.

@Mzack9999
Copy link
Member

@CodeRabbit resolve

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 25, 2025

✅ Actions performed

Comments resolved.

@Mzack9999 Mzack9999 merged commit f8f89bb into dev Sep 25, 2025
21 checks passed
@Mzack9999 Mzack9999 deleted the RDP-Enc-func branch September 25, 2025 23:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] ... RDP Encryption Enumeration

3 participants