-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathhydra-rdp.c
More file actions
270 lines (246 loc) · 9.03 KB
/
Copy pathhydra-rdp.c
File metadata and controls
270 lines (246 loc) · 9.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/*
This module is using freerdp3 lib
Tested on:
- Windows 7 pro SP1
- Windows 10 pro build 1809
- Windows Server 2016 build 1607
*/
#include "hydra-mod.h"
extern hydra_option hydra_options;
extern const unsigned char HYDRA_EXIT[5];
#ifndef LIBFREERDP
void dummy_rdp() { printf("\n"); }
#else
#include <freerdp/freerdp.h>
#include <freerdp/version.h>
/* RDP security protocols selected during the X.224 negotiation
* (see [MS-RDPBCGR] 2.2.1.2.1). They are defined in a private FreeRDP header
* (libfreerdp/core/nego.h), so the values we need are redefined here.
* Only NLA/CredSSP (PROTOCOL_HYBRID*) validates the supplied credentials during
* the connection handshake. Without it an AuthenticationOnly connect succeeds
* for any credentials, which is the root cause of the xrdp false positives in
* issue #923. */
#ifndef PROTOCOL_HYBRID
#define PROTOCOL_HYBRID 0x00000002
#endif
#ifndef PROTOCOL_HYBRID_EX
#define PROTOCOL_HYBRID_EX 0x00000008
#endif
freerdp *instance = 0;
BOOL rdp_connect(char *server, int32_t port, char *domain, char *login, char *password) {
int32_t err = 0;
rdpSettings *settings = instance->context->settings;
settings->Username = login;
settings->Password = password;
settings->IgnoreCertificate = TRUE;
if (password[0] == 0)
settings->AuthenticationOnly = FALSE;
else
settings->AuthenticationOnly = TRUE;
settings->ServerHostname = server;
settings->ServerPort = port;
settings->Domain = domain;
#if FREERDP_VERSION_MAJOR == 2
settings->MaxTimeInCheckLoop = 100;
#endif
// freerdp timeout format is microseconds -> default:15000
settings->TcpConnectTimeout = hydra_options.waittime * 1000;
settings->TlsSecLevel = 0;
freerdp_connect(instance);
err = freerdp_get_last_error(instance->context);
return err;
}
/* Client program */
int32_t start_rdp(char *ip, int32_t port, unsigned char options, char *miscptr, FILE *fp) {
char *empty = "";
char *login, *pass;
char server[64];
char domain[256];
int32_t login_result = 0;
memset(domain, 0, sizeof(domain));
if (strlen(login = hydra_get_next_login()) == 0)
login = empty;
if (strlen(pass = hydra_get_next_password()) == 0)
pass = empty;
strncpy(server, hydra_address2string(ip), sizeof(server) - 1);
if ((miscptr != NULL) && (strlen(miscptr) > 0)) {
strncpy(domain, miscptr, sizeof(domain) - 1);
domain[sizeof(domain) - 1] = 0;
}
login_result = rdp_connect(server, port, domain, login, pass);
if (debug)
hydra_report(stderr, "[DEBUG] rdp reported %08x\n", login_result);
switch (login_result) {
case 0:
// login success
hydra_report_found_host(port, ip, "rdp", fp);
hydra_completed_pair_found();
break;
case 0x00020009:
case 0x00020014:
case 0x00020015:
// login failure
hydra_completed_pair();
break;
case 0x0002000f:
/* ERRCONNECT_LOGON_FAILURE = wrong credentials. Keep trying other
* passwords for this user instead of skipping the user entirely. */
hydra_completed_pair();
break;
case 0x0002000d:
hydra_report(stderr,
"[%d][rdp] account on %s might be valid but account not "
"active for remote desktop: login: %s password: %s, "
"continuing attacking the account.\n",
port, hydra_address2string_beautiful(ip), login, pass);
hydra_completed_pair();
break;
case 0x00020006:
case 0x00020008:
case 0x0002000c:
// cannot establish rdp connection, either the port is not opened or it's
// not rdp
return 3;
default:
if (verbose) {
hydra_report(stderr, "[ERROR] freerdp: %s (0x%.8x)\n", freerdp_get_last_error_string(login_result), login_result);
}
return login_result;
}
if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0)
return 2;
return 1;
}
void service_rdp(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE *fp, int32_t port, char *hostname) {
int32_t run = 1, next_run = 1;
int32_t myport = PORT_RDP;
int32_t __first_rdp_connect = 1;
if (port != 0)
myport = port;
hydra_register_socket(sp);
if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0)
return;
while (1) {
next_run = 0;
switch (run) {
case 1: /* run the cracking function */
if (__first_rdp_connect != 0)
__first_rdp_connect = 0;
else
sleep(hydra_options.conwait);
next_run = start_rdp(ip, myport, options, miscptr, fp);
if (next_run == 1 && hydra_options.conwait)
sleep(hydra_options.conwait);
break;
case 2: /* clean exit */
freerdp_disconnect(instance);
freerdp_free(instance);
hydra_child_exit(0);
return;
case 3: /* connection error case */
hydra_report(stderr, "[ERROR] freerdp: %s\n", "The connection failed to establish.");
freerdp_free(instance);
hydra_child_exit(1);
return;
default:
hydra_child_exit(2);
}
run = next_run;
}
}
int32_t service_rdp_init(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE *fp, int32_t port, char *hostname) {
// called before the childrens are forked off, so this is the function
// which should be filled if initial connections and service setup has to be
// performed once only.
//
// return codes:
// 0 all OK
// 1 skip target without generating an error
// 2 skip target because of protocol problems
// 3 skip target because its unreachable
// -1 error, hydra will exit, so print a good error message here
int32_t err;
UINT32 selected;
char server[64];
char domain[256];
char probe_login[] = "hydra";
char probe_pass[] = "hydra";
rdpSettings *settings;
freerdp *probe;
// Disable freerdp output
wLog *root = WLog_GetRoot();
WLog_SetStringLogLevel(root, "OFF");
/* hydra can only verify RDP credentials when the server enforces NLA/CredSSP:
* only then are the credentials validated during the connection handshake.
* Without NLA (e.g. xrdp, or a Windows host with NLA disabled) the server
* defers authentication to an in-session login, so any connect succeeds and
* every login looks valid (issue #923). Probe the negotiated security layer
* once here with throwaway credentials (the protocol is negotiated before
* authentication is attempted), and skip the target if NLA is absent instead
* of reporting false positives. */
probe = freerdp_new();
if (probe == NULL || freerdp_context_new(probe) == FALSE) {
hydra_report(stderr, "[ERROR] freerdp init failed\n");
return -1;
}
settings = probe->context->settings;
memset(server, 0, sizeof(server));
memset(domain, 0, sizeof(domain));
strncpy(server, hydra_address2string(ip), sizeof(server) - 1);
if (miscptr != NULL && strlen(miscptr) > 0) {
strncpy(domain, miscptr, sizeof(domain) - 1);
domain[sizeof(domain) - 1] = 0;
}
settings->Username = probe_login;
settings->Password = probe_pass;
settings->Domain = domain;
settings->ServerHostname = server;
settings->ServerPort = port;
settings->IgnoreCertificate = TRUE;
settings->AuthenticationOnly = TRUE;
#if FREERDP_VERSION_MAJOR == 2
settings->MaxTimeInCheckLoop = 100;
#endif
settings->TcpConnectTimeout = hydra_options.waittime * 1000;
settings->TlsSecLevel = 0;
freerdp_connect(probe);
err = freerdp_get_last_error(probe->context);
selected = settings->SelectedProtocol;
freerdp_disconnect(probe);
freerdp_free(probe);
if (err == 0x00020006 || err == 0x00020008 || err == 0x0002000c) {
// cannot establish rdp connection, port closed or not rdp
hydra_report(stderr, "[ERROR] could not connect to rdp://%s:%d\n",
hydra_address2string_beautiful(ip), port);
return 3;
}
/* NLA/CredSSP (PROTOCOL_HYBRID*) was negotiated only if the corresponding bit
* is set; anything else (plain RDP or TLS) means credentials are not checked
* during connect, so hydra would report false positives. */
if (!(selected & (PROTOCOL_HYBRID | PROTOCOL_HYBRID_EX))) {
hydra_report(stderr,
"[ERROR] %s does not enforce NLA/CredSSP for RDP; credentials "
"cannot be verified (every login would be a false positive). "
"Skipping this target. Enable NLA on the target, or verify "
"credentials interactively, to scan it.\n",
hydra_address2string_beautiful(ip));
return 1;
}
// NLA is available, set up the instance the cracking children will use
instance = freerdp_new();
if (instance == NULL || freerdp_context_new(instance) == FALSE) {
hydra_report(stderr, "[ERROR] freerdp init failed\n");
return -1;
}
return 0;
}
void usage_rdp(const char *service) {
printf("Module rdp is optionally taking the windows domain name.\n"
"For example:\nhydra rdp://192.168.0.1/firstdomainname -l john -p "
"doe\n"
"Note: hydra can only verify RDP credentials on targets that enforce\n"
"NLA/CredSSP. Targets without NLA (e.g. xrdp, or Windows with NLA\n"
"disabled) defer authentication to an in-session login and are\n"
"reported as not verifiable instead of being brute forced.\n\n");
}
#endif