@@ -3,6 +3,7 @@ package rdp
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "net"
6
7
"time"
7
8
8
9
"github.com/praetorian-inc/fingerprintx/pkg/plugins"
@@ -112,3 +113,188 @@ func checkRDPAuth(host string, port int) (CheckRDPAuthResponse, error) {
112
113
resp .PluginInfo = pluginInfo
113
114
return resp , nil
114
115
}
116
+
117
+ type (
118
+ // RDPEncryptionResponse is the response from the CheckRDPEncryption function.
119
+ // This is returned by CheckRDPEncryption function.
120
+ // @example
121
+ // ```javascript
122
+ // const rdp = require('nuclei/rdp');
123
+ // const encryption = rdp.CheckRDPEncryption('acme.com', 3389);
124
+ // log(toJSON(encryption));
125
+ // ```
126
+ RDPEncryptionResponse struct {
127
+ SecurityLayer struct {
128
+ NativeRDP bool
129
+ SSL bool
130
+ CredSSP bool
131
+ RDSTLS bool
132
+ CredSSPWithEarlyUserAuth bool
133
+ }
134
+ EncryptionLevel struct {
135
+ RC4_40bit bool
136
+ RC4_56bit bool
137
+ RC4_128bit bool
138
+ FIPS140_1 bool
139
+ }
140
+ }
141
+ )
142
+
143
+ // CheckRDPEncryption checks the RDP server's supported security layers and encryption levels.
144
+ // It tests different protocols and ciphers to determine what is supported.
145
+ // @example
146
+ // ```javascript
147
+ // const rdp = require('nuclei/rdp');
148
+ // const encryption = rdp.CheckRDPEncryption('acme.com', 3389);
149
+ // log(toJSON(encryption));
150
+ // ```
151
+ func CheckRDPEncryption (host string , port int ) (RDPEncryptionResponse , error ) {
152
+ return memoizedcheckRDPEncryption (host , port )
153
+ }
154
+
155
+ // @memo
156
+ func checkRDPEncryption (host string , port int ) (RDPEncryptionResponse , error ) {
157
+ resp := RDPEncryptionResponse {}
158
+ timeout := 5 * time .Second
159
+
160
+ // Test different security protocols
161
+ protocols := map [string ]int {
162
+ "NativeRDP" : 0 ,
163
+ "SSL" : 1 ,
164
+ "CredSSP" : 3 ,
165
+ "RDSTLS" : 4 ,
166
+ "CredSSPWithEarlyUserAuth" : 8 ,
167
+ }
168
+
169
+ for name , value := range protocols {
170
+ conn , err := protocolstate .Dialer .Dial (context .TODO (), "tcp" , fmt .Sprintf ("%s:%d" , host , port ))
171
+ if err != nil {
172
+ continue
173
+ }
174
+ defer conn .Close ()
175
+
176
+ // Test protocol
177
+ isRDP , err := testRDPProtocol (conn , timeout , value )
178
+ if err == nil && isRDP {
179
+ switch name {
180
+ case "NativeRDP" :
181
+ resp .SecurityLayer .NativeRDP = true
182
+ case "SSL" :
183
+ resp .SecurityLayer .SSL = true
184
+ case "CredSSP" :
185
+ resp .SecurityLayer .CredSSP = true
186
+ case "RDSTLS" :
187
+ resp .SecurityLayer .RDSTLS = true
188
+ case "CredSSPWithEarlyUserAuth" :
189
+ resp .SecurityLayer .CredSSPWithEarlyUserAuth = true
190
+ }
191
+ }
192
+ }
193
+
194
+ // Test different encryption levels
195
+ ciphers := map [string ]int {
196
+ "RC4_40bit" : 1 ,
197
+ "RC4_56bit" : 8 ,
198
+ "RC4_128bit" : 2 ,
199
+ "FIPS140_1" : 16 ,
200
+ }
201
+
202
+ for name , value := range ciphers {
203
+ conn , err := protocolstate .Dialer .Dial (context .TODO (), "tcp" , fmt .Sprintf ("%s:%d" , host , port ))
204
+ if err != nil {
205
+ continue
206
+ }
207
+ defer conn .Close ()
208
+
209
+ // Test cipher
210
+ isRDP , err := testRDPCipher (conn , timeout , value )
211
+ if err == nil && isRDP {
212
+ switch name {
213
+ case "RC4_40bit" :
214
+ resp .EncryptionLevel .RC4_40bit = true
215
+ case "RC4_56bit" :
216
+ resp .EncryptionLevel .RC4_56bit = true
217
+ case "RC4_128bit" :
218
+ resp .EncryptionLevel .RC4_128bit = true
219
+ case "FIPS140_1" :
220
+ resp .EncryptionLevel .FIPS140_1 = true
221
+ }
222
+ }
223
+ }
224
+
225
+ return resp , nil
226
+ }
227
+
228
+ // testRDPProtocol tests RDP with a specific security protocol
229
+ func testRDPProtocol (conn net.Conn , timeout time.Duration , protocol int ) (bool , error ) {
230
+ // Set connection timeout
231
+ _ = conn .SetDeadline (time .Now ().Add (timeout ))
232
+ defer func () {
233
+ _ = conn .SetDeadline (time.Time {})
234
+ }()
235
+
236
+ // Send RDP connection request with specific protocol
237
+ // This is a simplified version - in reality you'd need to implement the full RDP protocol
238
+ // including the negotiation phase with the specified protocol
239
+ _ , err := conn .Write ([]byte {0x03 , 0x00 , 0x00 , 0x13 , 0x0e , 0xe0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , byte (protocol ), 0x00 , 0x08 , 0x00 , 0x03 , 0x00 , 0x00 , 0x00 })
240
+ if err != nil {
241
+ return false , err
242
+ }
243
+
244
+ // Read response
245
+ buf := make ([]byte , 1024 )
246
+ n , err := conn .Read (buf )
247
+ if err != nil {
248
+ return false , err
249
+ }
250
+
251
+ // Check if response indicates RDP
252
+ if n >= 19 && buf [0 ] == 0x03 && buf [1 ] == 0x00 && buf [2 ] == 0x00 {
253
+ // For CredSSP and CredSSP with Early User Auth, we need to check for NLA support
254
+ if protocol == 3 || protocol == 8 {
255
+ // Check for NLA support in the response
256
+ if n >= 19 && buf [18 ]& 0x01 != 0 {
257
+ return true , nil
258
+ }
259
+ return false , nil
260
+ }
261
+ return true , nil
262
+ }
263
+
264
+ return false , nil
265
+ }
266
+
267
+ // testRDPCipher tests RDP with a specific encryption level
268
+ func testRDPCipher (conn net.Conn , timeout time.Duration , cipher int ) (bool , error ) {
269
+ // Set connection timeout
270
+ _ = conn .SetDeadline (time .Now ().Add (timeout ))
271
+ defer func () {
272
+ _ = conn .SetDeadline (time.Time {})
273
+ }()
274
+
275
+ // Send RDP connection request with specific cipher
276
+ // This is a simplified version - in reality you'd need to implement the full RDP protocol
277
+ // including the negotiation phase with the specified cipher
278
+ _ , err := conn .Write ([]byte {0x03 , 0x00 , 0x00 , 0x13 , 0x0e , 0xe0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x08 , byte (cipher ), 0x03 , 0x00 , 0x00 , 0x00 })
279
+ if err != nil {
280
+ return false , err
281
+ }
282
+
283
+ // Read response
284
+ buf := make ([]byte , 1024 )
285
+ n , err := conn .Read (buf )
286
+ if err != nil {
287
+ return false , err
288
+ }
289
+
290
+ // Check if response indicates RDP
291
+ if n >= 19 && buf [0 ] == 0x03 && buf [1 ] == 0x00 && buf [2 ] == 0x00 {
292
+ // Check for encryption level support in the response
293
+ if n >= 19 && buf [18 ]& byte (cipher ) != 0 {
294
+ return true , nil
295
+ }
296
+ return false , nil
297
+ }
298
+
299
+ return false , nil
300
+ }
0 commit comments