Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/js/libs/rdp/rdp.go
2851 views
1
package rdp
2
3
import (
4
"context"
5
"fmt"
6
"net"
7
"strconv"
8
"time"
9
10
"github.com/praetorian-inc/fingerprintx/pkg/plugins"
11
"github.com/praetorian-inc/fingerprintx/pkg/plugins/services/rdp"
12
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
13
)
14
15
type (
16
// IsRDPResponse is the response from the IsRDP function.
17
// this is returned by IsRDP function.
18
// @example
19
// ```javascript
20
// const rdp = require('nuclei/rdp');
21
// const isRDP = rdp.IsRDP('acme.com', 3389);
22
// log(toJSON(isRDP));
23
// ```
24
IsRDPResponse struct {
25
IsRDP bool
26
OS string
27
}
28
)
29
30
// IsRDP checks if the given host and port are running rdp server.
31
// If connection is successful, it returns true.
32
// If connection is unsuccessful, it returns false and error.
33
// The Name of the OS is also returned if the connection is successful.
34
// @example
35
// ```javascript
36
// const rdp = require('nuclei/rdp');
37
// const isRDP = rdp.IsRDP('acme.com', 3389);
38
// log(toJSON(isRDP));
39
// ```
40
func IsRDP(ctx context.Context, host string, port int) (IsRDPResponse, error) {
41
executionId := ctx.Value("executionId").(string)
42
return memoizedisRDP(executionId, host, port)
43
}
44
45
// @memo
46
func isRDP(executionId string, host string, port int) (IsRDPResponse, error) {
47
resp := IsRDPResponse{}
48
49
dialer := protocolstate.GetDialersWithId(executionId)
50
if dialer == nil {
51
return IsRDPResponse{}, fmt.Errorf("dialers not initialized for %s", executionId)
52
}
53
54
timeout := 5 * time.Second
55
conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", fmt.Sprintf("%s:%d", host, port))
56
if err != nil {
57
return resp, err
58
}
59
defer func() {
60
_ = conn.Close()
61
}()
62
63
server, isRDP, err := rdp.DetectRDP(conn, timeout)
64
if err != nil {
65
return resp, err
66
}
67
if !isRDP {
68
return resp, nil
69
}
70
resp.IsRDP = true
71
resp.OS = server
72
return resp, nil
73
}
74
75
type (
76
// CheckRDPAuthResponse is the response from the CheckRDPAuth function.
77
// this is returned by CheckRDPAuth function.
78
// @example
79
// ```javascript
80
// const rdp = require('nuclei/rdp');
81
// const checkRDPAuth = rdp.CheckRDPAuth('acme.com', 3389);
82
// log(toJSON(checkRDPAuth));
83
// ```
84
CheckRDPAuthResponse struct {
85
PluginInfo *plugins.ServiceRDP
86
Auth bool
87
}
88
)
89
90
// CheckRDPAuth checks if the given host and port are running rdp server
91
// with authentication and returns their metadata.
92
// If connection is successful, it returns true.
93
// @example
94
// ```javascript
95
// const rdp = require('nuclei/rdp');
96
// const checkRDPAuth = rdp.CheckRDPAuth('acme.com', 3389);
97
// log(toJSON(checkRDPAuth));
98
// ```
99
func CheckRDPAuth(ctx context.Context, host string, port int) (CheckRDPAuthResponse, error) {
100
executionId := ctx.Value("executionId").(string)
101
return memoizedcheckRDPAuth(executionId, host, port)
102
}
103
104
// @memo
105
func checkRDPAuth(executionId string, host string, port int) (CheckRDPAuthResponse, error) {
106
resp := CheckRDPAuthResponse{}
107
108
dialer := protocolstate.GetDialersWithId(executionId)
109
if dialer == nil {
110
return CheckRDPAuthResponse{}, fmt.Errorf("dialers not initialized for %s", executionId)
111
}
112
timeout := 5 * time.Second
113
conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", fmt.Sprintf("%s:%d", host, port))
114
if err != nil {
115
return resp, err
116
}
117
defer func() {
118
_ = conn.Close()
119
}()
120
121
pluginInfo, auth, err := rdp.DetectRDPAuth(conn, timeout)
122
if err != nil {
123
return resp, err
124
}
125
if !auth {
126
return resp, nil
127
}
128
resp.Auth = true
129
resp.PluginInfo = pluginInfo
130
return resp, nil
131
}
132
133
type (
134
SecurityLayer string
135
)
136
137
const (
138
SecurityLayerNativeRDP = "NativeRDP"
139
SecurityLayerSSL = "SSL"
140
SecurityLayerCredSSP = "CredSSP"
141
SecurityLayerRDSTLS = "RDSTLS"
142
SecurityLayerCredSSPWithEarlyUserAuth = "CredSSPWithEarlyUserAuth"
143
)
144
145
type (
146
EncryptionLevel string
147
)
148
149
const (
150
EncryptionLevelRC4_40bit = "RC4_40bit"
151
EncryptionLevelRC4_56bit = "RC4_56bit"
152
EncryptionLevelRC4_128bit = "RC4_128bit"
153
EncryptionLevelFIPS140_1 = "FIPS140_1"
154
)
155
156
type (
157
// RDPEncryptionResponse is the response from the CheckRDPEncryption function.
158
// This is returned by CheckRDPEncryption function.
159
// @example
160
// ```javascript
161
// const rdp = require('nuclei/rdp');
162
// const encryption = rdp.CheckRDPEncryption('acme.com', 3389);
163
// log(toJSON(encryption));
164
// ```
165
RDPEncryptionResponse struct {
166
// Protocols
167
NativeRDP bool
168
SSL bool
169
CredSSP bool
170
RDSTLS bool
171
CredSSPWithEarlyUserAuth bool
172
173
// EncryptionLevels
174
RC4_40bit bool
175
RC4_56bit bool
176
RC4_128bit bool
177
FIPS140_1 bool
178
}
179
)
180
181
// CheckRDPEncryption checks the RDP server's supported security layers and encryption levels.
182
// It tests different protocols and ciphers to determine what is supported.
183
// @example
184
// ```javascript
185
// const rdp = require('nuclei/rdp');
186
// const encryption = rdp.CheckRDPEncryption('acme.com', 3389);
187
// log(toJSON(encryption));
188
// ```
189
func CheckRDPEncryption(ctx context.Context, host string, port int) (RDPEncryptionResponse, error) {
190
executionId := ctx.Value("executionId").(string)
191
return memoizedcheckRDPEncryption(executionId, host, port)
192
}
193
194
// @memo
195
func checkRDPEncryption(executionId string, host string, port int) (RDPEncryptionResponse, error) {
196
dialer := protocolstate.GetDialersWithId(executionId)
197
if dialer == nil {
198
return RDPEncryptionResponse{}, fmt.Errorf("dialers not initialized for %s", executionId)
199
}
200
resp := RDPEncryptionResponse{}
201
defaultTimeout := 5 * time.Second
202
203
// Test different security protocols
204
protocols := map[SecurityLayer]int{
205
SecurityLayerNativeRDP: 0,
206
SecurityLayerSSL: 1,
207
SecurityLayerCredSSP: 3,
208
SecurityLayerRDSTLS: 4,
209
SecurityLayerCredSSPWithEarlyUserAuth: 8,
210
}
211
212
for name, value := range protocols {
213
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
214
defer cancel()
215
conn, err := dialer.Fastdialer.Dial(ctx, "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
216
if err != nil {
217
continue
218
}
219
defer func() {
220
_ = conn.Close()
221
}()
222
223
// Test protocol
224
isRDP, err := testRDPProtocol(conn, value)
225
if err == nil && isRDP {
226
switch SecurityLayer(name) {
227
case SecurityLayerNativeRDP:
228
resp.NativeRDP = true
229
case SecurityLayerSSL:
230
resp.SSL = true
231
case SecurityLayerCredSSP:
232
resp.CredSSP = true
233
case SecurityLayerRDSTLS:
234
resp.RDSTLS = true
235
case SecurityLayerCredSSPWithEarlyUserAuth:
236
resp.CredSSPWithEarlyUserAuth = true
237
}
238
}
239
}
240
241
// Test different encryption levels
242
ciphers := map[EncryptionLevel]int{
243
EncryptionLevelRC4_40bit: 1,
244
EncryptionLevelRC4_56bit: 8,
245
EncryptionLevelRC4_128bit: 2,
246
EncryptionLevelFIPS140_1: 16,
247
}
248
249
for encryptionLevel, value := range ciphers {
250
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
251
defer cancel()
252
conn, err := dialer.Fastdialer.Dial(ctx, "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
253
if err != nil {
254
continue
255
}
256
defer func() {
257
_ = conn.Close()
258
}()
259
260
// Test cipher
261
isRDP, err := testRDPCipher(conn, value)
262
if err == nil && isRDP {
263
switch encryptionLevel {
264
case EncryptionLevelRC4_40bit:
265
resp.RC4_40bit = true
266
case EncryptionLevelRC4_56bit:
267
resp.RC4_56bit = true
268
case EncryptionLevelRC4_128bit:
269
resp.RC4_128bit = true
270
case EncryptionLevelFIPS140_1:
271
resp.FIPS140_1 = true
272
}
273
}
274
}
275
276
return resp, nil
277
}
278
279
// testRDPProtocol tests RDP with a specific security protocol
280
func testRDPProtocol(conn net.Conn, protocol int) (bool, error) {
281
// Send RDP connection request with specific protocol
282
// This is a simplified version - in reality you'd need to implement the full RDP protocol
283
// including the negotiation phase with the specified protocol
284
_, err := conn.Write([]byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, byte(protocol), 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00})
285
if err != nil {
286
return false, err
287
}
288
289
// Read response
290
buf := make([]byte, 1024)
291
n, err := conn.Read(buf)
292
if err != nil {
293
return false, err
294
}
295
296
// Check if response indicates RDP
297
if n >= 19 && buf[0] == 0x03 && buf[1] == 0x00 && buf[2] == 0x00 {
298
// For CredSSP and CredSSP with Early User Auth, we need to check for NLA support
299
if protocol == 3 || protocol == 8 {
300
// Check for NLA support in the response
301
if n >= 19 && buf[18]&0x01 != 0 {
302
return true, nil
303
}
304
return false, nil
305
}
306
return true, nil
307
}
308
309
return false, nil
310
}
311
312
// testRDPCipher tests RDP with a specific encryption level
313
func testRDPCipher(conn net.Conn, cipher int) (bool, error) {
314
// Send RDP connection request with specific cipher
315
// This is a simplified version - in reality you'd need to implement the full RDP protocol
316
// including the negotiation phase with the specified cipher
317
_, err := conn.Write([]byte{0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, byte(cipher), 0x03, 0x00, 0x00, 0x00})
318
if err != nil {
319
return false, err
320
}
321
322
// Read response
323
buf := make([]byte, 1024)
324
n, err := conn.Read(buf)
325
if err != nil {
326
return false, err
327
}
328
329
// Check if response indicates RDP
330
if n >= 19 && buf[0] == 0x03 && buf[1] == 0x00 && buf[2] == 0x00 {
331
// Check for encryption level support in the response
332
if n >= 19 && buf[18]&byte(cipher) != 0 {
333
return true, nil
334
}
335
return false, nil
336
}
337
338
return false, nil
339
}
340
341