1 /*
2 ettercap -- dissector http and proxy -- TCP 80, 8080
3
4 Copyright (C) ALoR & NaGA
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 #include <ec.h>
23 #include <ec_file.h>
24 #include <ec_decode.h>
25 #include <ec_dissect.h>
26 #include <ec_session.h>
27 #include <ec_sslwrap.h>
28
29 /* globals */
30 #define USER 0
31 #define PASS 1
32
33 struct http_status {
34 u_char c_status;
35 #define POST_WAIT_DELIMITER 1
36 #define POST_LAST_CHANCE 2
37 #define NTLM_WAIT_RESPONSE 3
38 #define PROXY_WAIT_OK 4
39 #define PROXY_WAIT_DELIMITER 5
40 u_char c_data[150];
41 /* XXX - Manage this array dinamically (with session_destroyer) */
42 };
43
44 typedef struct {
45 u_int16 len;
46 u_int16 maxlen;
47 u_int32 offset;
48 }tSmbStrHeader;
49
50 typedef struct {
51 char ident[8];
52 u_int32 msgType;
53 }tSmbStdHeader;
54
55 typedef struct {
56 char ident[8];
57 u_int32 msgType;
58 tSmbStrHeader uDomain;
59 u_int32 flags;
60 u_int8 challengeData[8];
61 u_int8 reserved[8];
62 tSmbStrHeader emptyString;
63 u_int8 buffer[1024];
64 u_int32 bufIndex;
65 }tSmbNtlmAuthChallenge;
66
67 typedef struct {
68 char ident[8];
69 u_int32 msgType;
70 tSmbStrHeader lmResponse;
71 tSmbStrHeader ntResponse;
72 tSmbStrHeader uDomain;
73 tSmbStrHeader uUser;
74 tSmbStrHeader uWks;
75 tSmbStrHeader sessionKey;
76 u_int32 flags;
77 u_int8 buffer[1024];
78 u_int32 bufIndex;
79 }tSmbNtlmAuthResponse;
80
81 struct http_field_entry {
82 char *name;
83 SLIST_ENTRY(http_field_entry) next;
84 };
85
86 static SLIST_HEAD(, http_field_entry) http_fields[2];
87
88
89 /* protos */
90 FUNC_DECODER(dissector_http);
91 void http_init(void);
92 static void Parse_Method_Get(char *ptr, struct packet_object *po);
93 static void Parse_Method_Post(char *ptr, struct packet_object *po);
94 static void Decode_Url(char *src);
95 static int Check_CONNECT(char *ptr, struct packet_object *po);
96 static void Find_Url(char *to_parse, char **ret);
97 static void Find_Url_Referer(char *to_parse, char **ret);
98 static void Parse_Post_Payload(char *ptr, struct http_status *conn_status, struct packet_object *po);
99 static void Print_Pass(struct packet_object *po);
100 static void Get_Banner(char *ptr, struct packet_object *po);
101 static u_char Parse_Form(char *to_parse, char **ret, int mode);
102 static int Parse_Passport_Auth(char *from_here, struct packet_object *po);
103 static int Parse_NTLM_Auth(char *ptr, char *from_here, struct packet_object *po);
104 static int Parse_Basic_Auth(char *ptr, char *from_here, struct packet_object *po);
105 static int Parse_User_Agent(char *end, char *from_here, struct packet_object *po);
106 static char *unicodeToString(char *p, size_t len);
107 static void dumpRaw(char *str, unsigned char *buf, size_t len);
108 int http_fields_init(void);
109
110 #define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
111 #define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
112 #define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
113 #define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
114
115 #define GetUnicodeString(structPtr, header) unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)
116
117 /************************************************/
118
119 /*
120 * this function is the initializer.
121 * it adds the entry in the table of registered decoder
122 */
123
http_init(void)124 void __init http_init(void)
125 {
126 sslw_dissect_add("https", 443, dissector_http, SSL_ENABLED);
127 sslw_dissect_add("proxy", 8080, dissector_http, SSL_DISABLED);
128 dissect_add("http", APP_LAYER_TCP, 80, dissector_http);
129 }
130
131
FUNC_DECODER(dissector_http)132 FUNC_DECODER(dissector_http)
133 {
134 DECLARE_DISP_PTR_END(ptr, end);
135 struct ec_session *s = NULL;
136 void *ident = NULL;
137 struct http_status *conn_status;
138 char *from_here;
139
140 /* unused variable */
141 (void)end;
142 (void) DECODE_DATA;
143 (void) DECODE_DATALEN;
144 (void) DECODED_LEN;
145
146 /* skip empty packets (ACK packets) */
147 if (PACKET->DATA.len == 0)
148 return NULL;
149
150 /* XXX - This way we won't catch ProxyAuth on CONNECT */
151 if (Check_CONNECT((char*)ptr, PACKET))
152 return NULL;
153
154 /* HOOK POINT: HOOK_PROTO_HTTP */
155 hook_point(HOOK_PROTO_HTTP, PACKET);
156
157 /* Parse client requests.
158 * Check the request type first.
159 */
160 if (FROM_CLIENT("http", PACKET) || FROM_CLIENT("proxy", PACKET) || FROM_CLIENT("https", PACKET)) {
161 /* Check Proxy or WWW auth first
162 * then password in the GET or POST.
163 */
164 if ((from_here = strstr((const char*)ptr, "Authorization: Passport")) &&
165 Parse_Passport_Auth(from_here + strlen("Authorization: Passport"), PACKET));
166 else if ((from_here = strstr((const char*)ptr, ": NTLM ")) &&
167 Parse_NTLM_Auth((char*)ptr, from_here + strlen(": NTLM "), PACKET));
168 else if ((from_here = strstr((const char*)ptr, ": Basic ")) &&
169 Parse_Basic_Auth((char*)ptr, from_here + strlen(": Basic "), PACKET));
170 else if ((from_here = strstr((const char*)ptr, "User-Agent: ")) &&
171 Parse_User_Agent(end, from_here + strlen("User-Agent: "), PACKET));
172 else if (!strncmp((const char*)ptr, "GET ", 4))
173 Parse_Method_Get((char*)ptr + strlen("GET "), PACKET);
174 else if (!strncmp((const char*)ptr, "POST ", 5))
175 Parse_Method_Post((char*)ptr + strlen("POST "), PACKET);
176 else {
177 dissect_create_ident(&ident, PACKET, DISSECT_CODE(dissector_http));
178 if (session_get(&s, ident, DISSECT_IDENT_LEN) == E_SUCCESS) {
179 conn_status = (struct http_status *) s->data;
180
181 /* Are we waiting for post termination? */
182 if (conn_status->c_status == POST_WAIT_DELIMITER ||
183 conn_status->c_status == POST_LAST_CHANCE)
184 Parse_Post_Payload((char*)ptr, conn_status, PACKET);
185 }
186 SAFE_FREE(ident);
187 }
188 } else { /* Server Replies */
189 if (!strncmp((const char*)ptr, "HTTP", 4)) {
190 Get_Banner((char*)ptr, PACKET);
191
192 /* Since the server replies there's no need to
193 * wait for POST termination or client response
194 */
195 dissect_wipe_session(PACKET, DISSECT_CODE(dissector_http));
196
197 /* Check Proxy or WWW Auth (server challenge) */
198 /* XXX - Is the NTLM challenge always in the same
199 * packet as HTTP header? Otherwise put these lines
200 * out from the if (decrease performances, checks all pcks)
201 */
202 if ((from_here = strstr((const char*)ptr, ": NTLM ")))
203 Parse_NTLM_Auth((char*)ptr, from_here + strlen(": NTLM "), PACKET);
204 }
205 }
206
207 return NULL;
208 }
209
210 /* Set the SSL flag (for ssl wrapper) when the CONNECT is finished */
Check_CONNECT(char * ptr,struct packet_object * po)211 static int Check_CONNECT(char *ptr, struct packet_object *po)
212 {
213 void *ident = NULL;
214 struct ec_session *s = NULL;
215 struct http_status *conn_status = NULL;
216
217 /* If we don't activate SSL wrappers we don't need to trace CONNECT */
218 if (!EC_GBL_CONF->aggressive_dissectors || EC_GBL_OPTIONS->unoffensive || EC_GBL_OPTIONS->read)
219 return 0;
220
221 dissect_create_ident(&ident, po, DISSECT_CODE(dissector_http));
222 if (session_get(&s, ident, DISSECT_IDENT_LEN) == E_SUCCESS) {
223 conn_status = (struct http_status *) s->data;
224
225 if (FROM_SERVER("proxy", po)) {
226 if (conn_status->c_status == PROXY_WAIT_OK && !strncmp(ptr + 8, " 200 ", 5))
227 conn_status->c_status = PROXY_WAIT_DELIMITER;
228
229 if (conn_status->c_status == PROXY_WAIT_DELIMITER &&
230 (strstr(ptr, "\r\n\r\n") || (ptr[0]=='\r' && ptr[1]=='\n'))) {
231 dissect_wipe_session(po, DISSECT_CODE(dissector_http));
232 po->flags |= PO_SSLSTART;
233 SAFE_FREE(ident);
234 return 1;
235 }
236 }
237 } else if (FROM_CLIENT("proxy", po) && !strncmp(ptr, "CONNECT ", 8)) {
238 dissect_create_session(&s, po, DISSECT_CODE(dissector_http));
239 SAFE_CALLOC(s->data, 1, sizeof(struct http_status));
240 conn_status = (struct http_status *) s->data;
241 conn_status->c_status = PROXY_WAIT_OK;
242 session_put(s);
243 }
244
245 SAFE_FREE(ident);
246 if (conn_status && (conn_status->c_status == PROXY_WAIT_DELIMITER || conn_status->c_status == PROXY_WAIT_OK))
247 return 1;
248
249 return 0;
250 }
251
252 /* Get the server banner from the headers */
Get_Banner(char * ptr,struct packet_object * po)253 static void Get_Banner(char *ptr, struct packet_object *po)
254 {
255 char *start, *end;
256 u_int32 len;
257
258 /* This is the banner of the remote
259 * server and not of the proxy
260 */
261 DEBUG_MSG("http - GET BANNER");
262
263 if (FROM_SERVER("proxy", po))
264 po->DISSECTOR.banner=strdup("Proxy");
265 else {
266 /* Get the server version */
267 if ((start = strstr(ptr, "Server: ")) && (end = strstr(start, "\r"))) {
268 start += strlen("Server: ");
269 len = end - start;
270
271 if (len>0 && len<1024) {
272 SAFE_CALLOC(po->DISSECTOR.banner, len+1, sizeof(char));
273 memcpy(po->DISSECTOR.banner, start, len);
274 }
275 }
276 }
277 }
278
279
280 /* Parse Passport Authentication */
Parse_Passport_Auth(char * from_here,struct packet_object * po)281 static int Parse_Passport_Auth(char *from_here, struct packet_object *po)
282 {
283 char *token, *to_decode, *tok;
284
285 DEBUG_MSG("HTTP --> dissector http (Passport Auth)");
286
287 if (!(to_decode = strdup(from_here)))
288 return 1;
289
290 if ( (token = strstr(to_decode, "OrgURL=")) == NULL ) {
291 SAFE_FREE(to_decode);
292 return 1;
293 }
294
295 /* Catch the original URL */
296 ec_strtok(token, ",", &tok);
297 po->DISSECTOR.info = strdup(token + strlen("OrgURL="));
298 Decode_Url(po->DISSECTOR.info);
299
300 /* Catch user and password */
301 while ( (token = ec_strtok(NULL, ",", &tok)) != NULL ) {
302 if (!strncmp(token, "sign-in=", strlen("sign-in="))) {
303 po->DISSECTOR.user = strdup(token + strlen("sign-in="));
304 Decode_Url(po->DISSECTOR.user);
305 } else if (!strncmp(token, "pwd=", strlen("pwd="))) {
306 po->DISSECTOR.pass = strdup(token + strlen("pwd="));
307 Decode_Url(po->DISSECTOR.pass);
308 /* password is the last interesting field */
309 break;
310 }
311 }
312
313 Print_Pass(po);
314 SAFE_FREE(to_decode);
315 return 1;
316 }
317
318
319 /* Parse Basic Authentication for both Proxy and WWW Auth */
Parse_Basic_Auth(char * ptr,char * from_here,struct packet_object * po)320 static int Parse_Basic_Auth(char *ptr, char *from_here, struct packet_object *po)
321 {
322 int Proxy_Auth = 0;
323 char *to_decode, *tok;
324 char *user, *pass;
325
326 DEBUG_MSG("HTTP --> dissector http (Basic Auth)");
327
328 /* If it's a proxy auth and we are not interested on proxy stuff
329 * return 0, so the dissector will continue to parse GET and POST
330 */
331 /* It stands for both Proxy-Authenticate and Authorization ;) */
332 if (strstr(ptr, "Proxy-Auth") || strstr(ptr, "Proxy-auth")) {
333 if (FROM_CLIENT("proxy", po))
334 Proxy_Auth = 1;
335 else
336 return 0;
337 }
338
339 if (!(to_decode = strdup(from_here)))
340 return 1;
341
342 ec_strtok(to_decode, "\r", &tok);
343
344 char *decoded;
345 base64decode(to_decode, &decoded);
346
347 DEBUG_MSG("Clear text AUTH: %s", decoded);
348
349 /* clear text should be username:password
350 * this means that we must find the first instance of :
351 * token shoul dbe username, and decoded should just be the password
352 */
353 /* Parse the cleartext auth string */
354
355
356 pass = NULL;
357
358 user = ec_strtok(decoded, ":", &pass);
359
360 if (pass != NULL && user != NULL) {
361 po->DISSECTOR.user = strdup(user);
362 po->DISSECTOR.pass = strdup(pass);
363
364 /* Are we authenticating to the proxy or to a website? */
365 if (Proxy_Auth)
366 po->DISSECTOR.info = strdup("Proxy Authentication");
367 else
368 Find_Url(ptr, &(po->DISSECTOR.info));
369
370 Print_Pass(po);
371 }
372
373 SAFE_FREE(decoded);
374 SAFE_FREE(to_decode);
375 return 1;
376 }
377
Parse_User_Agent(char * end,char * from_here,struct packet_object * po)378 static int Parse_User_Agent(char* end, char *from_here, struct packet_object *po)
379 {
380 // find the end of the line
381 const char* line_end = (const char*)memchr(from_here, '\n', end - from_here);
382 if (line_end == NULL) {
383 return 0;
384 }
385
386 unsigned int line_length = line_end - from_here;
387 const char* comment_begin = (const char*)memchr(from_here, '(', line_length);
388 if (comment_begin == NULL || ((comment_begin + 1) >= end)) {
389 // no comments found
390 return 0;
391 }
392 ++comment_begin;
393
394 const char* comment_end = (const char*)memchr(comment_begin, ')', line_end - comment_begin);
395 if (comment_end == NULL) {
396 // couldn't find the close on the comment
397 return 0;
398 }
399
400 const char* os = NULL;
401 while (os == NULL && comment_begin != NULL) {
402 unsigned int comment_length = comment_end - comment_begin;
403 if ((comment_length > 10 && strncmp(comment_begin, "Windows NT", 10) == 0) ||
404 (comment_length > 9 && strncmp(comment_begin, "Intel Mac", 9) == 0) ||
405 (comment_length > 7 && strncmp(comment_begin, "PPC Mac", 7) == 0) ||
406 (comment_length > 10 && strncmp(comment_begin, "CPU iPhone", 10) == 0) ||
407 (comment_length > 8 && strncmp(comment_begin, "Android", 7) == 0) ||
408 (comment_length > 5 && strncmp(comment_begin, "CrOS", 4) == 0) || // Chrome OS
409 (comment_length > 5 && strncmp(comment_begin, "Linux", 5) == 0)) {
410 os = comment_begin;
411 }
412
413 if (os == NULL) {
414 comment_begin = memchr(comment_begin, ';', comment_end - comment_begin);
415 if (comment_begin != NULL && ((comment_begin + 2) < comment_end)) {
416 // skip the ; and the ' '
417 comment_begin += 2;
418 }
419 else
420 {
421 comment_begin = NULL;
422 }
423 } else {
424 const char* the_end = memchr(comment_begin, ';', comment_end - comment_begin);
425 if (the_end != NULL) {
426 comment_end = the_end;
427 }
428
429 SAFE_CALLOC(po->DISSECTOR.os, 1, (comment_end - os) + 1);
430 memcpy(po->DISSECTOR.os, os, comment_end - os);
431 po->DISSECTOR.os[comment_end - os] = 0;
432 }
433 }
434
435 // always return 0 so the main loop drops down to get/post
436 return 0;
437 }
438
439 /* Parse NTLM challenge and response for both Proxy and WWW Auth */
Parse_NTLM_Auth(char * ptr,char * from_here,struct packet_object * po)440 static int Parse_NTLM_Auth(char *ptr, char *from_here, struct packet_object *po)
441 {
442 char *to_decode, msgType, *tok;
443 tSmbStdHeader *hSmb;
444 int Proxy_Auth = 0;
445 void *ident = NULL;
446 struct ec_session *s = NULL;
447 struct http_status *conn_status;
448
449 DEBUG_MSG("HTTP --> dissector http (NTLM Auth)");
450
451 /* If it's a proxy auth and we are not interested on proxy stuff
452 * return 0, so the dissector will continue to parse GET and POST
453 */
454 /* It stands for both Proxy-Authenticate and Authorization ;) */
455 if (strstr(ptr, "Proxy-Auth") || strstr(ptr, "Proxy-auth")) {
456 if (FROM_CLIENT("proxy", po) || FROM_SERVER("proxy", po))
457 Proxy_Auth = 1;
458 else
459 return 0;
460 }
461
462 if (!(to_decode = strdup(from_here)))
463 return 1;
464
465 ec_strtok(to_decode, "\r", &tok);
466
467 char *decoded;
468 base64decode(to_decode, &decoded);
469 hSmb = (tSmbStdHeader *) decoded;
470 msgType = IVAL(&hSmb->msgType, 0);
471
472 /* msgType 2 -> Server challenge
473 * msgType 3 -> Client response
474 */
475 if (msgType==2) {
476 tSmbNtlmAuthChallenge *challenge_struct;
477
478 challenge_struct = (tSmbNtlmAuthChallenge *) decoded;
479
480 /* Create a session to remember the server challenge */
481 dissect_create_session(&s, po, DISSECT_CODE(dissector_http));
482 SAFE_CALLOC(s->data, 1, sizeof(struct http_status));
483 conn_status = (struct http_status *) s->data;
484 conn_status->c_status = NTLM_WAIT_RESPONSE;
485 dumpRaw((char*)conn_status->c_data, challenge_struct->challengeData, 8);
486 session_put(s);
487
488 } else if (msgType==3) {
489 tSmbNtlmAuthResponse *response_struct;
490 char *outstr;
491
492 /* Take the challenge from the session */
493 dissect_create_ident(&ident, po, DISSECT_CODE(dissector_http));
494 if (session_get_and_del(&s, ident, DISSECT_IDENT_LEN) == E_SUCCESS) {
495 conn_status = (struct http_status *) s->data;
496
497 /* Are we waiting for client response? */
498 /* XXX- POST Continuation may conflict with NTLM Proxy auth
499 * if the client doesn't send Proxy-Authorization in the same
500 * packet as the POST
501 */
502 if (conn_status->c_status == NTLM_WAIT_RESPONSE) {
503 /* Fill the user and passwords */
504 response_struct = (tSmbNtlmAuthResponse *) decoded;
505 po->DISSECTOR.user = strdup(GetUnicodeString(response_struct, uUser));
506 SAFE_CALLOC(po->DISSECTOR.pass, strlen(po->DISSECTOR.user) + 150, sizeof(char));
507 snprintf(po->DISSECTOR.pass, strlen(po->DISSECTOR.user) + 150, "(NTLM) %s:\"\":\"\":", po->DISSECTOR.user);
508 outstr = po->DISSECTOR.pass + strlen(po->DISSECTOR.pass);
509 dumpRaw(outstr,((unsigned char*)response_struct)+IVAL(&response_struct->lmResponse.offset,0), 24);
510 outstr[48] = ':';
511 outstr+=49;
512 dumpRaw(outstr,((unsigned char*)response_struct)+IVAL(&response_struct->ntResponse.offset,0), 24);
513 outstr[48] = ':';
514 outstr += 49;
515 strcat(po->DISSECTOR.pass, (const char*)conn_status->c_data);
516
517 /* Are we authenticating to the proxy or to a website? */
518 if (Proxy_Auth)
519 po->DISSECTOR.info = strdup("Proxy Authentication");
520 else
521 Find_Url(ptr, &(po->DISSECTOR.info));
522
523 Print_Pass(po);
524 }
525 session_free(s);
526 }
527 SAFE_FREE(ident);
528 }
529 SAFE_FREE(to_decode);
530 SAFE_FREE(decoded);
531 return 1;
532 }
533
534
535 /* Deal with POST continuation */
Parse_Post_Payload(char * ptr,struct http_status * conn_status,struct packet_object * po)536 static void Parse_Post_Payload(char *ptr, struct http_status *conn_status, struct packet_object *po)
537 {
538 char *user=NULL, *pass=NULL;
539 u_char user_res, pass_res;
540
541 DEBUG_MSG("HTTP - Parse First chance");
542
543 if (conn_status->c_status == POST_WAIT_DELIMITER)
544 if ((ptr = strstr(ptr, "\r\n\r\n"))) {
545 ptr+=4;
546 conn_status->c_status = POST_LAST_CHANCE;
547 }
548 DEBUG_MSG("HTTP - Parse Last chance");
549 if (conn_status->c_status == POST_LAST_CHANCE) {
550 DEBUG_MSG("HTTP - Parse Form");
551
552 user_res= Parse_Form(ptr, &user, USER);
553 pass_res= Parse_Form(ptr, &pass, PASS);
554 if (user_res || pass_res) {
555 po->DISSECTOR.user = user;
556 po->DISSECTOR.pass = pass;
557 po->DISSECTOR.content = strdup((const char*) ptr);
558 po->DISSECTOR.info = strdup((const char*)conn_status->c_data);
559 dissect_wipe_session(po, DISSECT_CODE(dissector_http));
560 Print_Pass(po);
561 } else {
562 SAFE_FREE(user);
563 SAFE_FREE(pass);
564 }
565 }
566 }
567
568
569 /* Parse the POST header */
Parse_Method_Post(char * ptr,struct packet_object * po)570 static void Parse_Method_Post(char *ptr, struct packet_object *po)
571 {
572 char *url = NULL;
573 struct ec_session *s = NULL;
574 struct http_status *conn_status;
575
576 DEBUG_MSG("HTTP --> dissector http (method POST)");
577
578 Find_Url_Referer(ptr, &url);
579
580 /* We create a session just in case the post was
581 * fragmented into more packets. The session will be
582 * wiped on HTTP server reply.
583 */
584 dissect_create_session(&s, po, DISSECT_CODE(dissector_http));
585 SAFE_CALLOC(s->data, 1, sizeof(struct http_status));
586 conn_status = (struct http_status *) s->data;
587 conn_status->c_status = POST_WAIT_DELIMITER;
588 strlcpy((char*)conn_status->c_data, url, sizeof(conn_status->c_data));
589 session_put(s);
590
591 Parse_Post_Payload(ptr, conn_status, po);
592
593 SAFE_FREE(url);
594 }
595
596
597 /* Search for passwords in the URL */
Parse_Method_Get(char * ptr,struct packet_object * po)598 static void Parse_Method_Get(char *ptr, struct packet_object *po)
599 {
600 char *to_parse = NULL;
601 char *delimiter = NULL;
602 char *user = NULL;
603 char *pass = NULL;
604
605 DEBUG_MSG("HTTP --> dissector http (method GET)");
606
607 /* Isolate the parameters and copy them into another string */
608 if (!(to_parse = strstr(ptr, "?")))
609 return;
610
611 if (!(to_parse = strdup(to_parse)))
612 return;
613
614 if (!(delimiter = strstr(to_parse, " HTTP")))
615 goto http_get_failure;
616
617 /* NULL terminate the newly created parameter string */
618 *delimiter = 0;
619
620 /* Let's parse the parameter list */
621 if (!Parse_Form(to_parse, &user, USER) || !Parse_Form(to_parse, &pass, PASS)) {
622 SAFE_FREE(user);
623 goto http_get_failure;
624 }
625
626 po->DISSECTOR.user = user;
627 po->DISSECTOR.pass = pass;
628
629 /* Fill the info with the URL */
630 Find_Url_Referer(ptr, &(po->DISSECTOR.info));
631
632 Print_Pass(po);
633
634 http_get_failure:
635 SAFE_FREE(to_parse);
636 }
637
638
639 /* Match users or passwords in a string */
Parse_Form(char * to_parse,char ** ret,int mode)640 static u_char Parse_Form(char *to_parse, char **ret, int mode)
641 {
642 char *q;
643 struct http_field_entry *d;
644
645 /* Strip the '?' from a GET method */
646 if (*to_parse == '?') to_parse++;
647 if (*to_parse == 0)
648 return 0;
649
650 /* Search for users or passwords */
651
652 /* Search matches between each parameter and
653 * recognized users and passwords
654 */
655
656 SLIST_FOREACH(d, &(http_fields[mode]), next) {
657 q = to_parse;
658 do {
659 if (*q == '&') q++;
660
661 if (!strncasecmp(q, d->name, strlen(d->name)) && *(q+strlen(d->name)) == '=' ) {
662
663 /* Return the value past the '=' */
664 if (!(*ret = strdup(q + strlen(d->name) + 1)))
665 return 0;
666
667 /* NULL terminate the value if it's not the last */
668 if ((q = strchr(*ret, '&')))
669 *q = 0;
670
671 Decode_Url(*ret);
672 return 1;
673 }
674 } while ( (q = strchr(q, '&')) );
675 }
676
677 return 0;
678 }
679
680
681 /* Unescape the string */
Decode_Url(char * src)682 static void Decode_Url(char *src)
683 {
684 char t[3];
685 u_int32 i, j, ch;
686
687 /* Paranoid test */
688 if (!src)
689 return;
690
691 /* NULL terminate for the strtoul */
692 t[2] = 0;
693
694 for (i=0, j=0; src[i] != 0; i++, j++) {
695 ch = (u_int32)src[i];
696 if (ch == '%' && isxdigit((u_int32)src[i + 1]) && isxdigit((u_int32)src[i + 2])) {
697 memcpy(t, src+i+1, 2);
698 ch = strtoul(t, NULL, 16);
699 i += 2;
700 }
701 src[j] = (char)ch;
702 }
703 src[j] = 0;
704 }
705
706
707 /* Gets the URL from the headers */
Find_Url_Referer(char * to_parse,char ** ret)708 static void Find_Url_Referer(char *to_parse, char **ret)
709 {
710 char *fromhere, *page=NULL, *host=NULL;
711 u_int32 len;
712 char *tok;
713
714 /* If the referer exists */
715 if ((fromhere = strstr(to_parse, "Referer: "))) {
716 if ((*ret = strdup(fromhere + strlen("Referer: "))))
717 ec_strtok(*ret, "\r", &tok);
718 } else {
719 /* Get the page from the request */
720 page = strdup(to_parse);
721 ec_strtok(page, " HTTP", &tok);
722
723 /* If the path is relative, search for the Host */
724 if ((*page=='/') && (fromhere = strstr(to_parse, "Host: "))) {
725 host = strdup( fromhere + strlen("Host: ") );
726 ec_strtok(host, "\r", &tok);
727 } else
728 host = strdup("");
729
730 len = strlen(page) + strlen(host) + 2;
731 SAFE_CALLOC(*ret, len, sizeof(char));
732 snprintf(*ret, len, "%s%s", host, page);
733
734 SAFE_FREE(page);
735 SAFE_FREE(host);
736 }
737
738 Decode_Url(*ret);
739 }
740
741
742 /* Gets the URL from the request */
Find_Url(char * to_parse,char ** ret)743 static void Find_Url(char *to_parse, char **ret)
744 {
745 char *fromhere, *page=NULL, *host=NULL;
746 u_int32 len;
747 char *tok;
748
749 if (!strncmp(to_parse, "GET ", 4))
750 to_parse += strlen("GET ");
751 else if (!strncmp(to_parse, "POST ", 5))
752 to_parse += strlen("POST ");
753 else
754 return;
755
756 /* Get the page from the request */
757 page = strdup(to_parse);
758 ec_strtok(page, " HTTP", &tok);
759
760 /* If the path is relative, search for the Host */
761 if ((*page=='/') && (fromhere = strstr(to_parse, "Host: "))) {
762 host = strdup( fromhere + strlen("Host: ") );
763 ec_strtok(host, "\r", &tok);
764 } else
765 host = strdup("");
766
767 len = strlen(page) + strlen(host) + 2;
768 SAFE_CALLOC(*ret, len, sizeof(char));
769 snprintf(*ret, len, "%s%s", host, page);
770
771 SAFE_FREE(page);
772 SAFE_FREE(host);
773
774 Decode_Url(*ret);
775 }
776
777 /* Print the passwords from the PO */
Print_Pass(struct packet_object * po)778 static void Print_Pass(struct packet_object *po)
779 {
780 char tmp[MAX_ASCII_ADDR_LEN];
781
782 if (!po->DISSECTOR.user)
783 po->DISSECTOR.user = strdup("");
784
785 if (!po->DISSECTOR.pass)
786 po->DISSECTOR.pass = strdup("");
787
788 DISSECT_MSG("HTTP : %s:%d -> USER: %s PASS: %s INFO: %s\n", ip_addr_ntoa(&po->L3.dst, tmp),
789 ntohs(po->L4.dst),
790 po->DISSECTOR.user,
791 po->DISSECTOR.pass,
792 po->DISSECTOR.info);
793
794 if (po->DISSECTOR.content)
795 DISSECT_MSG("CONTENT: %s\n\n", po->DISSECTOR.content);
796 }
797
798
799 /* Load known user/pass fields from file */
http_fields_init(void)800 int http_fields_init(void)
801 {
802 FILE *f;
803 struct http_field_entry *d;
804 char line[128];
805 char *ptr;
806 int pass_flag = USER;
807
808 /* open the file */
809 f = open_data("share", ETTER_FIELDS, FOPEN_READ_TEXT);
810 if (f == NULL) {
811 USER_MSG("Cannot open %s\n", ETTER_FIELDS);
812 return -E_INVALID;
813 }
814
815 /* load it in the list */
816 while (fgets(line, 128, f)) {
817
818 /* trim comments */
819 if ( (ptr = strchr(line, '#')) )
820 *ptr = 0;
821
822 /* trim \n */
823 if ( (ptr = strchr(line, '\n')) )
824 *ptr = 0;
825
826 /* trim ' ' */
827 if ( (ptr = strchr(line, ' ')) )
828 *ptr = 0;
829
830 /* skip empty lines */
831 if (!strlen(line))
832 continue;
833
834 /* Identify the section */
835 if(!strncmp(line, "[USER]", 6)) {
836 pass_flag = USER;
837 continue;
838 }
839
840 if(!strncmp(line, "[PASS]", 6)) {
841 pass_flag = PASS;
842 continue;
843 }
844
845 /* create the entry */
846 SAFE_CALLOC(d, 1, sizeof(struct http_field_entry));
847 d->name = strdup(line);
848
849 /* insert in the right list */
850 SLIST_INSERT_HEAD(&(http_fields[pass_flag]), d, next);
851 }
852
853 fclose(f);
854
855 return E_SUCCESS;
856 }
857
858
859 /* A little helper function */
dumpRaw(char * str,unsigned char * buf,size_t len)860 static void dumpRaw(char *str, unsigned char *buf, size_t len)
861 {
862 u_int32 i;
863
864 for (i=0; i<len; ++i, str+=2)
865 snprintf(str, 3, "%02x", buf[i]);
866 }
867
868 /* A little helper function */
unicodeToString(char * p,size_t len)869 static char *unicodeToString(char *p, size_t len)
870 {
871 u_int32 i;
872 static char buf[1024];
873
874 /* A string longer than 1024 chars???...it's a bogus packet */
875 for (i=0; i<len && i<1023; ++i) {
876 buf[i] = *p & 0x7f;
877 p += 2;
878 }
879 buf[i] = '\0';
880 return buf;
881 }
882
883 /* EOF */
884
885 // vim:ts=3:expandtab
886