/*
    ettercap -- dissector HTTP Authorization: Basic -- TCP 80 8080

    Copyright (C) 2001  ALoR <alor@users.sourceforge.net>, NaGA <crwm@freemail.it>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

    $Id: ec_dissector_http.c,v 1.20 2003/07/07 10:39:52 lordnaga Exp $
*/

#include "include/ec_main.h"

#include <ctype.h>

#include "include/ec_dissector.h"
#include "include/ec_inet_structures.h"


#define USER 1
#define PASS 2


// global selector
int ProxyAuth;

// protos

FUNC_DISSECTOR(Dissector_http_proxy);
FUNC_DISSECTOR(Dissector_http);
FUNC_DISSECTOR(Dissector_proxy);

int parse_form(char *to_parse, char *ret, char mode);
void decode_url(char *src);
static char *unicodeToString(char *p, size_t len);
void dumpRaw(char *str, unsigned char *buf, size_t len);

#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)

#define GetUnicodeString(structPtr, header) unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)

typedef struct
{
   u_int16 len;
   u_int16 maxlen;
   u_int32 offset;
}tSmbStrHeader;

typedef struct
{
   char 	ident[8];
   u_int32	msgType;
}tSmbStdHeader;

typedef struct
{
   char			ident[8];
   u_int32		msgType;
   tSmbStrHeader	uDomain;
   u_int32		flags;
   u_int8		challengeData[8];
   u_int8		reserved[8];
   tSmbStrHeader	emptyString;
   u_int8		buffer[1024];
   u_int32		bufIndex;
}tSmbNtlmAuthChallenge;

typedef struct
{
    char 		ident[8];
    u_int32		msgType;
    tSmbStrHeader	lmResponse;
    tSmbStrHeader	ntResponse;
    tSmbStrHeader	uDomain;
    tSmbStrHeader	uUser;
    tSmbStrHeader	uWks;
    tSmbStrHeader	sessionKey;
    u_int32		flags;
    u_int8		buffer[1024];
    u_int32		bufIndex;
}tSmbNtlmAuthResponse;

// --------------------------------------

FUNC_DISSECTOR(Dissector_http)
{
    ProxyAuth=0;
    return ( Dissector_http_proxy( data, data_to_ettercap, sniff_data_to_ettercap, Conn_Mode, SERV_PORT ) );
}

FUNC_DISSECTOR(Dissector_proxy)
{
    ProxyAuth=1;
    return ( Dissector_http_proxy( data, data_to_ettercap, sniff_data_to_ettercap, Conn_Mode, SERV_PORT ) );
}

FUNC_DISSECTOR(Dissector_http_proxy)
{

   TCP_header *tcp;
   u_char *payload;
   char *fromhere = NULL;
   char collector[MAX_DATA*6];
   ONLY_CONNECTION;

   tcp = (TCP_header *) data;

   //if (ntohs(tcp->source) == SERV_PORT) return 0;     // skip server messages...
   if (data_to_ettercap->datalen == 0) return 0;      // no data...

   payload = (char *)((int)tcp + tcp->doff * 4);

   memset(collector, 0, sizeof(collector));
   memcpy(collector, payload, data_to_ettercap->datalen);

   /*
    *    NTLM Authorization
    *
    */

   if ( (fromhere = strstr(collector, ": NTLM ")) && ((!strstr(collector, "Proxy-Authenticate: NTLM ") && !strstr(collector, "Proxy-authorization: NTLM ")) || ProxyAuth))
   {
      char *to_be_decoded;
      char *decoded;
      char challenge[25];
      tSmbStdHeader *HSmb;
      char msgType;

      strtok(fromhere, "\r");
      to_be_decoded = strdup( fromhere+strlen(": NTLM "));

      decoded = strdup(to_be_decoded); // allocate the memory...

      Dissector_base64decode(decoded, to_be_decoded);
      HSmb = (tSmbStdHeader *) decoded;
      msgType = IVAL(&HSmb->msgType, 0);

      if (msgType==2)
      {
         tSmbNtlmAuthChallenge *challenge_struct;

         challenge_struct = (tSmbNtlmAuthChallenge *) decoded;
	  		memset(challenge,0,sizeof(challenge));
	  		dumpRaw(challenge, challenge_struct->challengeData, 8);
         Dissector_StateMachine_SetStatus(data_to_ettercap, 1, challenge);
      }
      else if (msgType==3)
      {
	  		char *outstr;
         tSmbNtlmAuthResponse  *response_struct;

	  		if (Dissector_StateMachine_GetStatus(data_to_ettercap, challenge)==1)
	  		{
	  		   response_struct  = (tSmbNtlmAuthResponse *) decoded;

	  		   snprintf(data_to_ettercap->user, sizeof(data_to_ettercap->user), "%s\n", GetUnicodeString(response_struct, uUser));
	  		   sprintf(data_to_ettercap->pass, "\n");
	  		   outstr = data_to_ettercap->info;
	  		   sprintf(outstr, "LC 2.5 FORMAT: \"USER\":3:");
	  		   strcat(outstr, challenge);
	  		   strcat(outstr, ":");
	  		   outstr+=( strlen("LC 2.5 FORMAT: \"USER\":3:") + 17 );
     		        dumpRaw(outstr,((unsigned char*)response_struct)+IVAL(&response_struct->lmResponse.offset,0), 24);
     		        outstr[48] = ':';
	  		   outstr+=49;
	  		   dumpRaw(outstr,((unsigned char*)response_struct)+IVAL(&response_struct->ntResponse.offset,0), 24);
     		        outstr[48] = '\n';
	  		   outstr[49] = 0;
	  		   Dissector_StateMachine_SetStatus(data_to_ettercap, 0, NULL);
	  		}
      }

      free(to_be_decoded);
      free(decoded);

      return 0;
   }

   /*
    *    HTTP Authorization
    *
    */


   if ( ( (fromhere = strstr(collector, "Authorization: Basic")) && !strstr(collector,"Proxy-Authorization: Basic")) || 
        ( (fromhere = strstr(collector, "Proxy-authorization: Basic")) && ProxyAuth) ||
	( (fromhere = strstr(collector, "Proxy-Authorization: Basic")) && ProxyAuth))
   {
      char user[sizeof(data_to_ettercap->user)-5] = "";
      char pass[sizeof(data_to_ettercap->pass)-5] = "";
      char *decoded;
      char *to_be_decoded;
      char *token;
      char *page = NULL;
      char *host = NULL;

      DEBUG_MSG("\tDissector_HTTP -- Authorization -- ");

      if (strstr(collector, "GET"))
      {
         page = strdup( strstr(collector, "GET") + strlen("GET ") );
         strtok(page, " HTTP");
         decode_url(page);
      }
      else if (strstr(collector, "POST"))
      {
         page = strdup( strstr(collector, "POST") + strlen("POST ") );
         strtok(page, " HTTP");
         decode_url(page);
      }

      if (strstr(collector, "Host:"))
      {
         host = strdup( strstr(collector, "Host:") + strlen("Host: ") );
         strtok(host, "\r");
         decode_url(host);
      }

      strtok(fromhere, "\r");
      if (!strncmp(fromhere, "Authorization: Basic", 20))
         to_be_decoded = strdup( fromhere+strlen("Authorization: Basic ") );
      else
         to_be_decoded = strdup( fromhere+strlen("Proxy-authorization: Basic ") );

      decoded = strdup(to_be_decoded); // allocate the memory...

      Dissector_base64decode(decoded, to_be_decoded);

      DEBUG_MSG("\tDissector_HTTP - decoding - [%s] [%s]", to_be_decoded, decoded);

      if ( (token = strsep(&decoded, ":")) != NULL)
      {
         strlcpy(user, token, 20);
         strcat(user, "\n");
         decode_url(user);
         strlcat(data_to_ettercap->user, user, sizeof(data_to_ettercap->user));

         if ( (token = strsep(&decoded, ":")) != NULL)
         {
            strlcpy(pass, token, 20);
            strcat(pass, "\n");
            decode_url(pass);
            strlcat(data_to_ettercap->pass, pass, sizeof(data_to_ettercap->pass));
         }
      }

      if (!ProxyAuth)
         snprintf(data_to_ettercap->info, sizeof(data_to_ettercap->info), "http://%s%s\n", host, page);
      else
         snprintf(data_to_ettercap->info, sizeof(data_to_ettercap->info), "%s\n", page);

      DEBUG_MSG("\tDissector_HTTP -- [%s][%s]", host, page);

      free(page);
      free(host);
      free(to_be_decoded);
      free(decoded);

      return 0;
   }


   /*
    *    <FORM> parsing, try to find user and pass from <form> tag
    *
    */

   if (!strncmp(collector, "GET ", 4) && (fromhere = strstr(collector, "?")))
   {
      char *to_parse = NULL;
      char *page = NULL;
      char *host = NULL;
      char *url = NULL;
      char *q;
      char user[sizeof(data_to_ettercap->user)-5];
      char pass[sizeof(data_to_ettercap->pass)-5];
      size_t len;

      //DEBUG_MSG("\tDissector_HTTP %d -- method GET -- \n\n%s\n\n", SERV_PORT, collector);
      DEBUG_MSG("\tDissector_HTTP %d -- method GET -- ", SERV_PORT);

      to_parse = strdup(fromhere);
      if ((q = strstr(to_parse, "HTTP")))
         *q = 0;     // get only the parameters...
      else
         return 0;

      if (parse_form(to_parse, user, USER) && parse_form(to_parse, pass, PASS))
      {
         decode_url(user);
         strlcpy(data_to_ettercap->user, user, sizeof(data_to_ettercap->user));
         decode_url(pass);
         strlcpy(data_to_ettercap->pass, pass, sizeof(data_to_ettercap->pass));

         if ((fromhere = strstr(collector, "Referer:")))    // if exist the referer
         {
            url = strdup(fromhere + strlen("Referer: "));
            strtok(url, "\r\n");
            DEBUG_MSG("\tDissector_HTTP -- referer: [%s]", url);
         }
         else                                               // get the page from other header
         {
            if ((fromhere = strstr(collector, "GET")))
            {
               page = strdup( fromhere + strlen("GET ") );
               strtok(page, " HTTP");
            }
            else
               page = strdup("/unknown");

            if ((fromhere = strstr(collector, "Host:")))
            {
               host = strdup( fromhere + strlen("Host: ") );
               strtok(host, "\r\n");
            }
            else
               host = strdup("http://unknown");

            len = strlen(page)+strlen(host)+2;
            url = realloc(url, len);
            if (url == NULL)
               ERROR_MSG("realloc()");
            url[len-1]='\0';
            snprintf(url, len, "%s%s", host, page);

            free(page);
            free(host);
            DEBUG_MSG("\tDissector_HTTP -- host + page : [%s]", url);
         }

         //DEBUG_MSG("\tDissector_HTTP -- after page [%s]", url);

         decode_url(url);
         snprintf(data_to_ettercap->info, sizeof(data_to_ettercap->info), "%s\n", url);
         free(url);
      }
      free(to_parse);
      return 0;
   }



   if (!strncmp(collector, "POST ", 5))
   {
      char *to_parse = NULL;
      char *page = NULL;
      char *host = NULL;
      char *url = NULL;
      char user[sizeof(data_to_ettercap->user)-5];
      char pass[sizeof(data_to_ettercap->pass)-5];
      size_t len;

      //DEBUG_MSG("\tDissector_HTTP %d -- method POST -- \n\n%s\n\n", SERV_PORT, collector);
      DEBUG_MSG("\tDissector_HTTP %d -- method POST -- ", SERV_PORT);

      if ((fromhere = strstr(collector, "Referer:")))    // if exist the referer
      {
         url = strdup(fromhere + strlen("Referer: "));
         strtok(url, "\r\n");
         DEBUG_MSG("\tDissector_HTTP -- referer: [%s]", url);
      }
      else                                               // get the page from other header
      {
         if ((fromhere = strstr(collector, "POST")))
         {
            page = strdup( fromhere + strlen("POST ") );
            strtok(page, " HTTP");
         }
         else page = strdup("/unknown");

         if ((fromhere = strstr(collector, "Host:")))
         {
            host = strdup( fromhere + strlen("Host: ") );
            strtok(host, "\r\n");
         }
         else host = strdup("http://unknown");

         len = strlen(page)+strlen(host)+2;
         url = realloc(url, len);
         if (url == NULL)
           ERROR_MSG("realloc()");
         url[len-1] = '\0';
         snprintf(url, len, "%s%s", host, page);
         free(page);
         free(host);
         DEBUG_MSG("\tDissector_HTTP -- host + page : [%s]", url);
      }

      //DEBUG_MSG("\tDissector_HTTP -- after page [%s]", url);

      if (strstr(collector, "User-Agent: Mozilla") && !strstr(collector, "MSIE")
          && !strstr(collector,"Opera"))                                            // if user-agent is Netscape
      {                                                                             // it posts the data in the
                                                                                    // second packet, so we set
         DEBUG_MSG("\tDissector_HTTP -- method POST -- mozilla");                   // the state to catch them
                                                                                    // later
         Dissector_StateMachine_SetStatus(data_to_ettercap, 1, NULL);
         decode_url(url);
         snprintf(data_to_ettercap->info, sizeof(data_to_ettercap->info), "%s\n", url);
         free(url);
	 		url = NULL;
         //return 0;
      }

      //DEBUG_MSG("\tDissector_HTTP -- after netscape");

      if (!strstr(collector, "application/x-www-form-urlencoded"))
         return 0;

      to_parse = strstr(collector, "\r\n\r\n");
      if (to_parse == NULL)
         return 0;
      else
         to_parse += 4;

      //DEBUG_MSG("\tDissector_HTTP -- after to_parse -- [%s]", to_parse);

      if (parse_form(to_parse, user, USER) && parse_form(to_parse, pass, PASS))
      {
         decode_url(user);
         strlcpy(data_to_ettercap->user, user, sizeof(data_to_ettercap->user));
         decode_url(pass);
         strlcpy(data_to_ettercap->pass, pass, sizeof(data_to_ettercap->pass));
         if (url)
	 		{
	    		decode_url(url);
            snprintf(data_to_ettercap->info, sizeof(data_to_ettercap->info), "%s\n", url);
            free(url);
         }
      }
      return 0;
   }



   if (Dissector_StateMachine_GetStatus(data_to_ettercap, NULL) >= 1)   // Netscape
   {
      char *to_parse;
      char user[sizeof(data_to_ettercap->user)-5];
      char pass[sizeof(data_to_ettercap->pass)-5];


      DEBUG_MSG("\tDissector_HTTP %d -- mozilla -- second packet", SERV_PORT);
/*
      if (Dissector_StateMachine_GetStatus(data_to_ettercap, NULL) == 1)
      {
         if (!strstr(collector, "Content-type: application/x-www-form-urlencoded"))
         {
            Dissector_StateMachine_SetStatus(data_to_ettercap, 0, NULL);
            return 0;
         }
         Dissector_StateMachine_SetStatus(data_to_ettercap, 2, NULL);
      }
*/

      if (Dissector_StateMachine_GetStatus(data_to_ettercap, NULL) == 2)
         Dissector_StateMachine_SetStatus(data_to_ettercap, 0, NULL);
      else if (strstr(collector,"\r\n\r\n"))
         Dissector_StateMachine_SetStatus(data_to_ettercap, 2, NULL);

      if ((to_parse = strstr(collector, "\r\n\r\n")))
         to_parse += 4;
      else
         to_parse = collector;

      //DEBUG_MSG("\tDissector_HTTP - Mozilla - [%s]", to_parse);

      if (parse_form(to_parse, user, USER) && parse_form(to_parse, pass, PASS))
      {
         decode_url(user);
         strlcat(data_to_ettercap->user, user, sizeof(data_to_ettercap->user));
         decode_url(pass);
         strlcat(data_to_ettercap->pass, pass, sizeof(data_to_ettercap->pass));
         Dissector_StateMachine_SetStatus(data_to_ettercap, 0, NULL);
      }
      return 0;
   }

   return 0;
}



int parse_form(char *to_parse, char *ret, char mode)
{
   char *user_field[] = {"user", "email", "username", "userid", "login",
                         "form_loginname", "loginname", "pop_login",
                         "uid", "id", "user_id", "screenname", "uname",
                         "ulogin", "acctname", "account", "member",
                         "mailaddress", "membername", "login_username",
                         "uin", ""};

   char *pass_field[] = {"pass", "password", "passwd", "form_pw", "pw",
                         "userpassword", "pwd", "upassword", "login_password",
                         "passwort", "passwrd", ""};

   char **ptr;
   int i;
   char *tmp = NULL;
   char *var = NULL;
   char *q = tmp;

   decode_url(to_parse);

   if (to_parse[0] == '?') to_parse++;    // strip the '?' from a GET method

	if (!strncmp(to_parse, " ", 1)) return 0;

   tmp = strdup(to_parse);

   ptr = user_field;
   if (mode == PASS)
      ptr = pass_field;

   //DEBUG_MSG("\tHTTP_dissector -- parse_form -- [%s]", to_parse);

   for (i=0; strcmp(ptr[i], ""); i++)
   {
      q = tmp;
      do
      {
         if (*q == '&') q++;
         if (!strncasecmp(q, ptr[i], strlen(ptr[i])) && *(q+strlen(ptr[i])) == '=' )
         {
            if (!strsep(&q, "=") || !(q=strsep(&q, "&")))
            {
               free(tmp);
               return 0;
            }
            var = strdup(q);
            snprintf(ret, 25, "%s\n", var);
            ret[24] = 0;
            free(var);
            free(tmp);
            return 1;
         }
      }
      while ( (q = strchr(q, '&')) );
   }

   free(tmp);
   return 0;
}


void decode_url(char *src)
{
   char t[3];
   int i, j, ch;

   memset(t, 0, sizeof(t));

   for (i = 0, j = 0; src[i] != '\0'; i++, j++)
   {
      ch = src[i];
      if (ch == '%' && isxdigit((int)src[i + 1]) && isxdigit((int)src[i + 2]))
      {
         strlcpy(t, src+i+1, 3);
         ch = strtoul(t, NULL, 16);
         i += 2;
      }
      src[j] = ch;
   }
   src[j] = '\0';
}

static char *unicodeToString(char *p, size_t len)
{
   int i;
   static char buf[1024];

   for (i=0; i<len && i<1023; ++i)
   {
      buf[i] = *p & 0x7f;
      p += 2;
   }
   buf[i] = '\0';
   return buf;
}

void dumpRaw(char *str, unsigned char *buf, size_t len)
{
   int i;

	for (i=0; i<len; ++i, str+=2)
		sprintf(str, "%02x", buf[i]);
}

/* EOF */

// vim:ts=3:expandtab

