/*
    ettercap -- dissector SMB (Server Message Block) -- TCP 139

    Copyright (C) 2003  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_smb.c,v 1.9 2003/04/16 11:14:24 lordnaga Exp $
*/

#include "include/ec_main.h"

#include <errno.h>

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

#define PLAIN_TEXT 1
#define WAITING_CHALLENGE 2
#define WAITING_RESPONSE 3
#define WAITING_ENCRYPT 4

typedef struct {
   u_char  proto[4];
   u_char  cmd;
   u_char  err[4];
   u_char  flags1;
   u_short flags2;
   u_short pad[6];
   u_short tid, pid, uid, mid;
} SMB_header;

typedef struct {
   u_char  mesg;
   u_char  flags;
   u_short len;
} NetBIOS_header;

// protos

FUNC_DISSECTOR(Dissector_smb);
void GetUser(char *user, char *dest, int len);
void GetBinaryE(unsigned char *binary, unsigned char *dest, int len);

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

void GetUser(char *user, char *dest, int len)
{
     char Unicode=1;
     int i=0;
     
     if (user[1]==0) Unicode=2; // Does anyone uses 2 chars users?
                                // I think it's unicode
          
     for(;;)
     {
           *dest = *user;
           if (*user==0 || i>=22 || len<=0) 
	   {
	       *dest = 0;
	       break;
	   }
	   dest++; i++;
	   len-=Unicode;
	   user+=Unicode;	    
     }
     strcat(dest, "\n");
}

void GetBinaryE(unsigned char *binary, unsigned char *dest, int blen)
{
   char dummy[5];
   for (; blen>0; blen--)
   {	
       sprintf( dummy, "%02X", *binary);
       binary++;
       strcat(dest, dummy);
   }
}

FUNC_DISSECTOR(Dissector_smb)
{

   TCP_header *tcp;
   u_char *payload;
   SMB_header *smb;
   NetBIOS_header *NetBIOS;
   u_char *ptr;
   char schallenge[512];
   ONLY_CONNECTION;

   tcp = (TCP_header *) data;

   payload = (char *)((int)tcp + tcp->doff * 4);
   NetBIOS = (NetBIOS_header *)payload;
   smb = (SMB_header *)(NetBIOS + 1);

   if (memcmp(smb->proto, "\xffSMB", 4) != 0)  return 0;  // it isn't SMB

   ptr = (u_char *)(smb + 1);
   
   // Negotiate Protocol Response
   if (smb->cmd == 0x72 && data_to_ettercap->source_port == SERV_PORT &&
       Dissector_StateMachine_GetStatus(data_to_ettercap, NULL) == 0)
   {   
      // Security Mode
      if (!(ptr[3] & 2))    // ...010 (encrypted)  ...000 (plaintext)
         Dissector_StateMachine_SetStatus(data_to_ettercap, PLAIN_TEXT, NULL);
      else
      {
         ptr += (*ptr)*2; // Last Word Field
         if (*ptr!=0) // Encryption Key Len
	 {
	    ptr += 3; // Got to Blob
	    snprintf(data_to_ettercap->info, sizeof(data_to_ettercap->info), "LC 2.5 FORMAT: \"USER\":3:");
            GetBinaryE(ptr, data_to_ettercap->info, 8);
	    strcat (data_to_ettercap->info, ":");
	    Dissector_StateMachine_SetStatus(data_to_ettercap, WAITING_ENCRYPT, NULL);
	 }
	 else
	 {
            Dissector_StateMachine_SetStatus(data_to_ettercap, WAITING_CHALLENGE, NULL);
         }
      }
   }
   
   // Session SetUp 
   if (smb->cmd == 0x73)
   {      
     if (data_to_ettercap->dest_port == SERV_PORT) // Client Packets
     { 
      if (Dissector_StateMachine_GetStatus(data_to_ettercap, NULL) == PLAIN_TEXT ) 
      {      
         short pwlen, unilen;
         char *Blob;
	 
	 Blob = ptr;
	 Blob += ( (*ptr)*2 + 3 );
        
	 ptr += 15;
         pwlen = ptohs(ptr);        // ANSI password len
         ptr += 2;
         unilen = ptohs(ptr);       // UNICODE password len
         
         if (pwlen > 0) 
	 //{	
	     strlcpy(data_to_ettercap->pass, Blob, sizeof(data_to_ettercap->pass)-2);
             strcat(data_to_ettercap->pass, "\n");  // don't forget it !!   datadecode needs it !!
	 //}
	 
         GetUser(Blob+pwlen+unilen, data_to_ettercap->user, 200);
         Dissector_StateMachine_SetStatus(data_to_ettercap, 0, NULL);
      }      
      else if (Dissector_StateMachine_GetStatus(data_to_ettercap, schallenge) == WAITING_RESPONSE)
      {
         char *Blob;
         // Jump the Words
         ptr += ( (*ptr)*2 + 3 );
	 
	 // Jump ID String
	 if ( (ptr = (char *)memmem(ptr, 128, "NTLMSSP", 8)) == NULL) return 0; 
	 Blob = ptr;
	 ptr = strchr(ptr, 0) + 1;
	 
	 if (*ptr == 3) 
	 {
 	     int LM_Offset, LM_Len, NT_Offset, NT_Len, User_Offset, User_Len;
             ptr += 4;
	     LM_Len = *(u_int16 *)ptr;
	     ptr += 4;
	     LM_Offset = *(u_int32 *)ptr;
	     ptr += 4;
	     NT_Len = *(u_int16 *)ptr;
	     ptr += 4;
             NT_Offset = *(u_int32 *)ptr;
	     ptr += 12;
	     User_Len = *(u_int16 *)ptr;
	     ptr += 4;
	     User_Offset = *(u_int32 *)ptr;
	
	     if (NT_Len!=24)
	     {
	        Dissector_StateMachine_SetStatus(data_to_ettercap, WAITING_CHALLENGE, NULL);     
	        return 0;
	     }
	          
	     GetUser(Blob+User_Offset, data_to_ettercap->user, User_Len);
             	 
	     snprintf(data_to_ettercap->info, 60, "LC 2.5 FORMAT: \"USER\":3:%s:", schallenge);	   
	     
	     if (LM_Len == 24)
	         GetBinaryE(Blob+LM_Offset, data_to_ettercap->info, 24);
	     else 
	         strcat (data_to_ettercap->info, "000000000000000000000000000000000000000000000000");
		 
	     strcat (data_to_ettercap->info, ":");     
             GetBinaryE(Blob+NT_Offset, data_to_ettercap->info, 24);
	     strcat (data_to_ettercap->info, "\n");
	     
	     sprintf(data_to_ettercap->pass, "\n");
        
	     Dissector_StateMachine_SetStatus(data_to_ettercap, 0, NULL);
	 }
      }
      else if (Dissector_StateMachine_GetStatus(data_to_ettercap, NULL) == WAITING_ENCRYPT)
      {
         char *Blob;
	 
	 Blob = ptr;
	 Blob += ( (*ptr)*2 + 3 );

	 GetBinaryE(Blob, data_to_ettercap->info, 24);
	 strcat (data_to_ettercap->info, ":");
         GetBinaryE(Blob+24, data_to_ettercap->info, 24);
	 strcat (data_to_ettercap->info, "\n");
	 GetUser(Blob+49, data_to_ettercap->user, 200);
             
	 sprintf(data_to_ettercap->pass, "\n");
         Dissector_StateMachine_SetStatus(data_to_ettercap, 0, NULL);
      }
     }
     else // Server Packets
     {
      if (Dissector_StateMachine_GetStatus(data_to_ettercap, NULL) == WAITING_CHALLENGE)
      {
         ptr += ( (*ptr)*2 + 3 );
	 if ( (ptr = (char *)memmem(ptr, 128, "NTLMSSP", 8)) == NULL) return 0;
	 ptr = strchr(ptr, 0) + 1;
	  
	 if (*ptr == 2) 
	 {
	   ptr +=16; 
	   schallenge[0]=0;
	   GetBinaryE(ptr, schallenge, 8);	   
	   Dissector_StateMachine_SetStatus(data_to_ettercap, WAITING_RESPONSE, schallenge);
	 }
	 
      }
     }
   }     
   return 0;     
}


/* EOF */

// vim:ts=3:expandtab

