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