mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-18 15:45:26 +00:00
CheckRDPEncryption
This commit is contained in:
parent
cbf57ef889
commit
32845bccf2
26
cmd/nuclei/rdp.yaml
Normal file
26
cmd/nuclei/rdp.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
id: rdp-enc-check
|
||||
|
||||
info:
|
||||
name: RDP Enc - Detection
|
||||
author: pussycat0x
|
||||
severity: info
|
||||
metadata:
|
||||
verified: true
|
||||
max-request: 1
|
||||
shodan-query: port:"3389"
|
||||
tags: js,network,rdp,info,enum
|
||||
|
||||
javascript:
|
||||
- code: |
|
||||
let m = require('nuclei/rdp');
|
||||
let response = m.CheckRDPEncryption(Host,Port);
|
||||
Export(response);
|
||||
|
||||
args:
|
||||
Host: "{{Host}}"
|
||||
Port: "3389"
|
||||
|
||||
extractors:
|
||||
- type: dsl
|
||||
dsl:
|
||||
- response
|
||||
@ -16,12 +16,14 @@ func init() {
|
||||
gojs.Objects{
|
||||
// Functions
|
||||
"CheckRDPAuth": lib_rdp.CheckRDPAuth,
|
||||
"CheckRDPEncryption": lib_rdp.CheckRDPEncryption,
|
||||
"IsRDP": lib_rdp.IsRDP,
|
||||
|
||||
// Var and consts
|
||||
|
||||
// Objects / Classes
|
||||
"CheckRDPAuthResponse": gojs.GetClassConstructor[lib_rdp.CheckRDPAuthResponse](&lib_rdp.CheckRDPAuthResponse{}),
|
||||
"CheckRDPEncryptionResponse": gojs.GetClassConstructor[lib_rdp.RDPEncryptionResponse](&lib_rdp.RDPEncryptionResponse{}),
|
||||
"IsRDPResponse": gojs.GetClassConstructor[lib_rdp.IsRDPResponse](&lib_rdp.IsRDPResponse{}),
|
||||
},
|
||||
).Register()
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
/**
|
||||
* CheckRDPAuth checks if the given host and port are running rdp server
|
||||
* with authentication and returns their metadata.
|
||||
@ -15,7 +13,19 @@ export function CheckRDPAuth(host: string, port: number): CheckRDPAuthResponse |
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CheckRDPEncryption checks the RDP server's supported security layers and encryption levels.
|
||||
* It tests different protocols and ciphers to determine what is supported.
|
||||
* @example
|
||||
* ```javascript
|
||||
* const rdp = require('nuclei/rdp');
|
||||
* const encryption = rdp.CheckRDPEncryption('acme.com', 3389);
|
||||
* log(toJSON(encryption));
|
||||
* ```
|
||||
*/
|
||||
export function CheckRDPEncryption(host: string, port: number): RDPEncryptionResponse | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* IsRDP checks if the given host and port are running rdp server.
|
||||
@ -33,8 +43,6 @@ export function IsRDP(host: string, port: number): IsRDPResponse | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* CheckRDPAuthResponse is the response from the CheckRDPAuth function.
|
||||
* this is returned by CheckRDPAuth function.
|
||||
@ -52,7 +60,31 @@ export interface CheckRDPAuthResponse {
|
||||
Auth?: boolean,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* RDPEncryptionResponse is the response from the CheckRDPEncryption function.
|
||||
* This is returned by CheckRDPEncryption function.
|
||||
* @example
|
||||
* ```javascript
|
||||
* const rdp = require('nuclei/rdp');
|
||||
* const encryption = rdp.CheckRDPEncryption('acme.com', 3389);
|
||||
* log(toJSON(encryption));
|
||||
* ```
|
||||
*/
|
||||
export interface RDPEncryptionResponse {
|
||||
SecurityLayer: {
|
||||
NativeRDP: boolean;
|
||||
SSL: boolean;
|
||||
CredSSP: boolean;
|
||||
RDSTLS: boolean;
|
||||
CredSSPWithEarlyUserAuth: boolean;
|
||||
};
|
||||
EncryptionLevel: {
|
||||
RC4_40bit: boolean;
|
||||
RC4_56bit: boolean;
|
||||
RC4_128bit: boolean;
|
||||
FIPS140_1: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* IsRDPResponse is the response from the IsRDP function.
|
||||
@ -71,8 +103,6 @@ export interface IsRDPResponse {
|
||||
OS?: string,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ServiceRDP Interface
|
||||
*/
|
||||
|
||||
@ -39,3 +39,19 @@ func memoizedcheckRDPAuth(host string, port int) (CheckRDPAuthResponse, error) {
|
||||
|
||||
return CheckRDPAuthResponse{}, errors.New("could not convert cached result")
|
||||
}
|
||||
|
||||
func memoizedcheckRDPEncryption(host string, port int) (RDPEncryptionResponse, error) {
|
||||
hash := "checkRDPEncryption" + ":" + fmt.Sprint(host) + ":" + fmt.Sprint(port)
|
||||
|
||||
v, err, _ := protocolstate.Memoizer.Do(hash, func() (interface{}, error) {
|
||||
return checkRDPEncryption(host, port)
|
||||
})
|
||||
if err != nil {
|
||||
return RDPEncryptionResponse{}, err
|
||||
}
|
||||
if value, ok := v.(RDPEncryptionResponse); ok {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
return RDPEncryptionResponse{}, errors.New("could not convert cached result")
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package rdp
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/praetorian-inc/fingerprintx/pkg/plugins"
|
||||
@ -112,3 +113,188 @@ func checkRDPAuth(host string, port int) (CheckRDPAuthResponse, error) {
|
||||
resp.PluginInfo = pluginInfo
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
type (
|
||||
// RDPEncryptionResponse is the response from the CheckRDPEncryption function.
|
||||
// This is returned by CheckRDPEncryption function.
|
||||
// @example
|
||||
// ```javascript
|
||||
// const rdp = require('nuclei/rdp');
|
||||
// const encryption = rdp.CheckRDPEncryption('acme.com', 3389);
|
||||
// log(toJSON(encryption));
|
||||
// ```
|
||||
RDPEncryptionResponse struct {
|
||||
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
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// CheckRDPEncryption checks the RDP server's supported security layers and encryption levels.
|
||||
// It tests different protocols and ciphers to determine what is supported.
|
||||
// @example
|
||||
// ```javascript
|
||||
// const rdp = require('nuclei/rdp');
|
||||
// const encryption = rdp.CheckRDPEncryption('acme.com', 3389);
|
||||
// log(toJSON(encryption));
|
||||
// ```
|
||||
func CheckRDPEncryption(host string, port int) (RDPEncryptionResponse, error) {
|
||||
return memoizedcheckRDPEncryption(host, port)
|
||||
}
|
||||
|
||||
// @memo
|
||||
func checkRDPEncryption(host string, port int) (RDPEncryptionResponse, error) {
|
||||
resp := RDPEncryptionResponse{}
|
||||
timeout := 5 * time.Second
|
||||
|
||||
// Test different security protocols
|
||||
protocols := map[string]int{
|
||||
"NativeRDP": 0,
|
||||
"SSL": 1,
|
||||
"CredSSP": 3,
|
||||
"RDSTLS": 4,
|
||||
"CredSSPWithEarlyUserAuth": 8,
|
||||
}
|
||||
|
||||
for name, value := range protocols {
|
||||
conn, err := protocolstate.Dialer.Dial(context.TODO(), "tcp", fmt.Sprintf("%s:%d", host, port))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Test protocol
|
||||
isRDP, err := testRDPProtocol(conn, timeout, value)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test different encryption levels
|
||||
ciphers := map[string]int{
|
||||
"RC4_40bit": 1,
|
||||
"RC4_56bit": 8,
|
||||
"RC4_128bit": 2,
|
||||
"FIPS140_1": 16,
|
||||
}
|
||||
|
||||
for name, value := range ciphers {
|
||||
conn, err := protocolstate.Dialer.Dial(context.TODO(), "tcp", fmt.Sprintf("%s:%d", host, port))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Test cipher
|
||||
isRDP, err := testRDPCipher(conn, timeout, value)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// testRDPProtocol tests RDP with a specific security protocol
|
||||
func testRDPProtocol(conn net.Conn, timeout time.Duration, protocol int) (bool, error) {
|
||||
// Set connection timeout
|
||||
_ = conn.SetDeadline(time.Now().Add(timeout))
|
||||
defer func() {
|
||||
_ = conn.SetDeadline(time.Time{})
|
||||
}()
|
||||
|
||||
// Send RDP connection request with specific protocol
|
||||
// This is a simplified version - in reality you'd need to implement the full RDP protocol
|
||||
// including the negotiation phase with the specified protocol
|
||||
_, err := conn.Write([]byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, byte(protocol), 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Read response
|
||||
buf := make([]byte, 1024)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Check if response indicates RDP
|
||||
if n >= 19 && buf[0] == 0x03 && buf[1] == 0x00 && buf[2] == 0x00 {
|
||||
// For CredSSP and CredSSP with Early User Auth, we need to check for NLA support
|
||||
if protocol == 3 || protocol == 8 {
|
||||
// Check for NLA support in the response
|
||||
if n >= 19 && buf[18]&0x01 != 0 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// testRDPCipher tests RDP with a specific encryption level
|
||||
func testRDPCipher(conn net.Conn, timeout time.Duration, cipher int) (bool, error) {
|
||||
// Set connection timeout
|
||||
_ = conn.SetDeadline(time.Now().Add(timeout))
|
||||
defer func() {
|
||||
_ = conn.SetDeadline(time.Time{})
|
||||
}()
|
||||
|
||||
// Send RDP connection request with specific cipher
|
||||
// This is a simplified version - in reality you'd need to implement the full RDP protocol
|
||||
// including the negotiation phase with the specified cipher
|
||||
_, err := conn.Write([]byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, byte(cipher), 0x03, 0x00, 0x00, 0x00})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Read response
|
||||
buf := make([]byte, 1024)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Check if response indicates RDP
|
||||
if n >= 19 && buf[0] == 0x03 && buf[1] == 0x00 && buf[2] == 0x00 {
|
||||
// Check for encryption level support in the response
|
||||
if n >= 19 && buf[18]&byte(cipher) != 0 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user