RAW SOCKET Programming Ing. Mauricio Mena Cort´es koitoer 27 de junio de 2009
1
´Indice general 1. Prefacio 1.1. A quien lo lea:
. . . . . . . . . . . . . . . . . . . . . . . . . .
2. Conocimientos b´ asicos 2.1. Requerimientos del sistema 2.2. Modelo OSI . . . . . . . . . 2.2.1. Capa 1: F´ısica . . . 2.2.2. Capa 2: Enlace . . . 2.2.3. Capa 3: Red . . . . 2.2.4. Capa 4: Transporte 2.2.5. Capa 5: Sesi´on . . . 2.2.6. Capa 6: Presentaci´on 2.2.7. Capa 7: Aplicaci´on .
5 5
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
7 7 7 8 8 9 12 14 14 14
3. RAW SOCKET ?? 3.1. Introducci´on . . . . . . . . . . . . 3.2. Funciones importantes . . . . . . . 3.2.1. socket . . . . . . . . . . . . 3.2.2. sendto . . . . . . . . . . . . 3.2.3. recvfrom . . . . . . . . . . . 3.2.4. getsockopt && setsocketopt 3.3. Algunas estrcuturas importantes . 3.3.1. Estructura ifreq . . . . . . . 3.4. Un ejemplo para empezar . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
16 16 17 17 17 18 18 19 19 21
. . . . . . .
. . . . . . . . . .
. . . . . . . . .
4. Sniffer 28 4.1. SNIFFER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 4.1.1. PROMISC MODE ?? . . . . . . . . . . . . . . . . . . 28 2
´INDICE GENERAL
3
4.2. ksniffer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 4.2.1. Compilaci´on y Ejecuci´on . . . . . . . . . . . . . . . . 31 4.3. Sniffer mejorado. . . . . . . . . . . . . . . . . . . . . . . . . . 31 5. Implantar Funcionalidades 5.1. Modificaciones . . . . . 5.1.1. A˜ nadimos UDP . 5.1.2. A˜ nadimos ICMP 5.1.3. A˜ nadimos DHCP 5.1.4. A˜ nadimos ARP . 6. Conclusi´ on 6.1. Problemas principales 6.2. Tutoriales futuros . . 6.3. Ideas Finales . . . . . 6.4. Agradecimientos . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
42 42 42 43 44 51
. . . .
54 54 54 54 55
´Indice de figuras 2.1. 2.2. 2.3. 2.4. 2.5. 2.6.
Ethernet (Header) IP (Header) . . . . ICMP (Header) . . TCP (Header) . . . UDP (Header) . . . Modelo OSI . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
9 10 10 12 14 15
3.1. Ejecuci´on captada por IPTraf del c´odigo bajado de internet y como vemos no funciona . . . . . . . . . . . . . . . . . . . . . 21 3.2. Ejecuci´on captada por Wireshark . . . . . . . . . . . . . . . . 27 4.1. Empaquetado en modelo OSI . . . . . . . . . . . . . . . . . . 32 5.1. Header ICMP . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 5.2. Ejecucion del sniffer, Protocolo DHCP . . . . . . . . . . . . . 50 5.3. Ejecuci´on del sniffer, Protocolo ARP . . . . . . . . . . . . . . 53
4
Parte 1 Prefacio 1.1.
A quien lo lea:
En este tutorial tratar´e de explicar y plasmar mediante algunos ejemplos propios y algunos otros corregidos que obtuve de la red, la forma y funcionalidad que se puede tener al programar con RAW SOCKET, pero vamos, ni siquiera he definido que es un RAW SOCKET, en este caso su traducci´on a nuestro lenguaje es ”socket crudo”, mucha gente se podr´a preguntar por que la palabra crudo, esto se debe a que este tipo de sockets trabajan sin estar ligados a un protocolo de comunicaciones, es decir, podemos darle el sabor(flavor) que necesitemos, esto en programaci´on lo podemos traducir como darle la funcionalidad que nostros deseamos. Estos sockets nos permiten el acceso a los protocolos de comunicaciones, con la posibilidad de hacer uso o no de protocolos de capa 3 y/o 4, y por lo tanto d´andonos el acceso a los protocolos directamente y a la informaci´on que recide en ellos. El uso de sockets de este tipo nos va a permitir la implementaci´on de nuevos protocolos, y por qu´e no decirlo, la modificaci´on de los ya existentes. Cabe mencionar que en esta ocasi´on, pondr´e en el tutorial la documentaci´on de algunas estructuras de datos y funciones que nos ayudar´an a crear y entender el uso de los sockets crudos, a´ un asi tampoco pretendo explicar ni entrar a detalle en el modelo OSI, el cual nos servir´a s´olo como referencia para entender un poco m´as del funcionamiento de los sockets, aunque s´ı le dedicar´e una secci´on a lo que considero m´as importante del modelo al trabajar con estos sockets.
5
PARTE 1. PREFACIO
6
Bueno espero el tutorial sea claro, conciso y les sirva para empezar a entender un poco m´as acerca de la programaci´on de sockets crudos, empezemos.
Parte 2 Conocimientos b´ asicos 2.1.
Requerimientos del sistema
Primero que nada todo este manual est´a orientado a sistemas linux - unix, como el anterior tutorial. La distribuci´on que se use no tendr´a por qu´e importar, ya que en realidad lo que se necesitar´a es tener instalado
1. GCC S´ı, s´olo necesitaremos el compilador de GNU, ya que en esta ocasi´on todas las definiciones y funciones se van a hallar en el propio sistema de linux, normalmente en la carpeta /usr/include/net, /usr/include/netinet y /usr/include/linux, las cuales son cargadas al sistema en una instalaci´on normal del sistema. Tambi´en nos podremos auxiliar del archivo /etc/protocol, para el conocimiento de los protocolos y sus abreviaciones.
2.2.
Modelo OSI
El modelo de capas OSI (Open System Interconection) es uno de los pilares b´asicos para el desarollo de las redes actuales y es completamente aplicable a redes de tipo TCP/IP, fue creado en 1984 por ISO, con el fin de estandarizar el proceso de creaci´on de nuevos tipos de redes de inform´atica. 7
´ PARTE 2. CONOCIMIENTOS BASICOS
8
Lo que en realidad hace el modelo OSI es dividir, a modo de referencia, cualquier sistema de red en capas diferenciadas entre s´ı, para comprender de forma m´as gr´afica la funcionalidad de cada una de ellas.
2.2.1.
Capa 1: F´ısica
Esta capa es la encargada de mover los bits entre los diferentes dispositivos, da las especificaciones el´ectricas, mec´anicas y los requerimientos con respecto a voltajes, intensidades, cables, pines, modulaciones para una transmisi´on exitosa de la informaci´on, con lo que se tienen interfaces que pueden estar activadas o desactivadas, esta capa nos provee de la topolog´ıa f´ısica de la red, por lo que en este tutorial no haremos uso de ella.
2.2.2.
Capa 2: Enlace
Despu´es de la demodulaci´on de la se˜ nal, esta capa es la encargada de revisar las alteraciones que esta pudo haber sufrido en el medio, esta capa trabaja con tramas, permite encontrar diversos errores en las mismas, se le suele conocer como MAC (Media Access Control). En esta capa act´ ua el LLC (Logic Link Control), y se trabaja con direcciones f´ısicas (MAC ADDRESS) de las NIC (Network Interface Control), Switches y Conmutadores. El PDU que se maneja es trama (frame), controla el framing, la notificaci´on de errores, la topolog´ıa de red y el principal est´andar de esta capa es el IEEE-802. ETHERNET #include < i f e t h e r . h> struct e t h h d r { unsigned char h d e s t [ ETH ALEN ] ; /∗ d e s t i n a t i o n e t h addr ∗/ unsigned char h s o u r c e [ ETH ALEN ] ; /∗ s o u r c e e t h e r addr ∗/ unsigned short h p r o t o ; /∗ p a c k e t t y p e ID f i e l d ∗/ };
´ PARTE 2. CONOCIMIENTOS BASICOS
9
Figura 2.1: Ethernet (Header)
2.2.3.
Capa 3: Red
Capa encargada de encaminar datos al destino, eligiendo la mejor ruta, en esta capa trabajan los protocolos de ruteo. El PDU (Data Unit) que se maneja es el paquete, y el principal protocolo que trabaja en esta capa es IP (Internet protocol), aunque no debemos de olvidar que tambi´en trabajan ICMP (Internet Common Message Protocol), ARP (Address Resolution Protocol), RARP (Reverse Address Resolution Protocol), PPTP (Point-to-point Tunneling Protocol), entre otros. IP #include
struct i p h d r { #i f d e f i n e d ( LITTLE ENDIAN BITFIELD ) u8 ihl :4 , version : 4 ; # e l i f d e f i n e d ( BIG ENDIAN BITFIELD ) u8 version :4 , ihl :4; #e l s e #e r r o r ” P l e a s e f i x ” #e n d i f u8 tos ; u16 tot len ; u16 id ;
´ PARTE 2. CONOCIMIENTOS BASICOS
Figura 2.2: IP (Header) u16 frag off ; u8 ttl ; u8 protocol ; u16 check ; u32 saddr ; u32 daddr ; /∗The o p t i o n s s t a r t h e r e . ∗/ };
ICMP
Figura 2.3: ICMP (Header)
10
´ PARTE 2. CONOCIMIENTOS BASICOS
struct icmphdr { u i n t 8 t type ; /∗ message t y p e ∗/ u i n t 8 t code ; /∗ t y p e sub−code ∗/ u i n t 1 6 t checksum ; union { struct { u int16 t id ; u i n t 1 6 t sequence ; } echo ; /∗ echo datagram ∗/ u int32 t gateway ; /∗ gateway a d d r e s s ∗/ struct { u int16 t unused ; u i n t 1 6 t mtu ; } frag ; /∗ p a t h mtu d i s c o v e r y ∗/ } un ; }; #define ICMP ECHOREPLY /∗ Echo Reply #define ICMP DEST UNREACH /∗ D e s t i n a t i o n U n r e a c h a b l e #define ICMP SOURCE QUENCH /∗ Source Quench #define ICMP REDIRECT /∗ R e d i r e c t ( change r o u t e ) #define ICMP ECHO /∗ Echo R e q u e s t #define ICMP TIME EXCEEDED /∗ Time Exceeded #define ICMP PARAMETERPROB /∗ Parameter Problem #define ICMP TIMESTAMP /∗ Timestamp R e q u e s t #define ICMP TIMESTAMPREPLY /∗ Timestamp Reply
0 ∗/ 3 ∗/ 4 ∗/ 5 ∗/ 8 ∗/ 11 ∗/ 12 ∗/ 13 ∗/ 14 ∗/
11
´ PARTE 2. CONOCIMIENTOS BASICOS
12
Figura 2.4: TCP (Header) #define ICMP INFO REQUEST /∗ I n f o r m a t i o n R e q u e s t #define ICMP INFO REPLY /∗ I n f o r m a t i o n Reply #define ICMP ADDRESS /∗ Address Mask R e q u e s t #define ICMP ADDRESSREPLY /∗ Address Mask Reply #define NR ICMP TYPES
2.2.4.
15 ∗/ 16 ∗/ 17 ∗/ 18 ∗/ 18
Capa 4: Transporte
En esta capa, se tienen dos modos de conexi´on, orientado a conexi´on y no orientado a conexi´on y principalmente hacemos uso de TCP y UDP, estos protocolos se encargan de dar la fin de secuencia, segmentaci´on y reensamble de datos al stream de datos, esta es la capa que nos provee la conexi´on l´ogica ente los host, puede o no proveer de circuitos virtuales a la par de correcci´on de errores en la transmisi´on. En este caso el PDU de la capa 4 es el segmento. TCP struct t c p h d r { u short th sport ; /∗ s o u r c e p o r t ∗/
´ PARTE 2. CONOCIMIENTOS BASICOS u short th dport ; /∗ d e s t i n a t i o n p o r t ∗/ tcp seq th seq ; /∗ s e q u e n c e number ∗/ tcp seq th ack ; /∗ acknowledgement number ∗/ #i f BYTE ORDER == LITTLE ENDIAN u char th x2 : 4 , /∗ ( unused ) ∗/ th off :4; /∗ d a t a o f f s e t ∗/ #e n d i f #i f BYTE ORDER == BIG ENDIAN u char t h o f f : 4 , /∗ d a t a o f f s e t ∗/ th x2 : 4 ; /∗ ( unused ) ∗/ #e n d i f u char t h f l a g s ; #d e f i n e TH FIN 0 x01 #d e f i n e TH SYN 0 x02 #d e f i n e TH RST 0 x04 #d e f i n e TH PUSH 0 x08 #d e f i n e TH ACK 0 x10 #d e f i n e TH URG 0 x20 u short th win ; /∗ window ∗/ u s h o r t th sum ; /∗ checksum ∗/ u short th urp ; /∗ u r g e n t p o i n t e r ∗/ };
UDP struct udphdr { u int16 t source ; u int16 t dest ; u int16 t len ; u i n t 1 6 t check ; }; #endif #define SOL UDP
17
13
´ PARTE 2. CONOCIMIENTOS BASICOS
14
Figura 2.5: UDP (Header) /∗ s o c k o p t l e v e l f o r UDP ∗/
2.2.5.
Capa 5: Sesi´ on
Encargada de la separaci´on de datos de diferentes aplicaciones, asi como del control de di´alogo, configuraciones de administraci´on, t´ermino de sesiones entre la capa de presentaci´on y maneja los conceptos de comunicaciones simplex, halfduplex o fullduplex.
2.2.6.
Capa 6: Presentaci´ on
Presenta los datos, se encarga del cifrado de los datos, adem´as de ser la encargada de presentar los formatos de codificaci´on, maneja las operaciones multimedia, la translaci´on de los datos y formato de c´odigo, tambi´en se encarga de la compresi´on Entre los cuales est´an (ASCII, EBDIC)
2.2.7.
Capa 7: Aplicaci´ on
Da una interfaz al usuario, encargado de funciones de archivos, mensaje, servidores, bases de datos, para los cuales maneja diferentes patrones de comunicaciones y recursos para la comunicaciones. Entre los principales est´an SSH, FTP, HTTP.
´ PARTE 2. CONOCIMIENTOS BASICOS
Figura 2.6: Modelo OSI
15
Parte 3 RAW SOCKET 3.1.
Introducci´ on
Cuando nosotros trabajamos con rawsocket, perdemos y ganamos diferentes caracter´ısticas, entre las m´as improtantes destacan: 1. Los sockets raw son un nivel abstracto sobre la trama de red, de hecho son m´as abstractos que los sockets que ya conocemos que son ´ltimos un caso esSOCK STREAM y SOCK DGRAM, al ser estos u pec´ıfico de los sockets crudos. 2. Al usar sockets crudos, tenemos una p´erdida de fiabilidad con respecto al TCP, ya que no se incluye por defecto al usar socket crudo. 3. No hay puertos; s´ı, incre´ıble pero cierto, aunque muchas veces dijimos que un socket = direcci´on IP + un puerto, ahora desmentimos en parte eso, ya que en los sockets crudos es el kernel el encargado de pasar la informaci´on de un cierto protocolo a todos los sockets que est´en escuchando el mismo protocolo, no hay conexiones de red virtuales como tal, es decir, no hay puertos. 4. Comunicaciones sin est´andar, ya que uno lo debe de generar, al escribir un servidor tendremos que escribir el cliente, ya que no es un est´andar y no cualquier programa entender´a lo que nosotros estamos diciendo. 5. Si se hace uso de protocolos ya existentes, se tienen que rellenar los campos (headers) manualmente, ya que el kernel no lo hace autom´aticamente. 16
PARTE 3. RAW SOCKET ??
17
6. Por u ´ltimo debemos de tener en cuenta que cualquier programa que haga uso de los sockets crudos, se debe ejecutar con permisos de root.
3.2.
Funciones importantes
En este mundo de los sockets y con respecto a la programaci´on de los sockets crudos tenemos ciertas funciones que nos ayudar´an a crearlos y usarlos, por lo que pongo un listado de las que considero mas importantes y algunos detalles o par´ametros m´as usados.
3.2.1.
socket
#include <s y s / t y p e s . h> #include <s y s / s o c k e t . h> int s o c k e t ( int domain , int type , int p r o t o c o l ) ;
Donde el dominio que se usar´a es el PF INET, el tipo de socket es SOCK RAW, y protocol es el protocolo a usar con este socket que se est´a creando. Una lista de los protocolos es la siguiente: enum( IPPROTO IP = 0 , /∗TCP dummy p r o t o c o l ∗/ IPPROTO ICMP = 0 , /∗ICMP p r o t o c o l ∗/ IPPROTO TCP = 0 , /∗TCP p r o t o c o l ∗/ IPPROTO UDP = 0 , /∗UDP p r o t o c o l ∗/ IPPROTO IPV6 = 0 , /∗ IPv6 p r o t o c o l ∗/ IPPROTO RAW = 0 , /∗RAW p r o t o c o l ∗/ );
3.2.2.
sendto
#include <s y s / t y p e s . h> #include <s y s / s o c k e t . h> int s e n d t o ( int s , const void ∗msg , int l e n , unsigned int f l a g s , const struct s o c k a d d r ∗ to , int t o l e n ) ;
Como primer par´ametro se indica el descriptor del socket. El segundo par´ametro es un puntero a los datos que se van a enviar. El tercer par´ametro indica el n´ umero de bytes que se van a enviar. En el cuarto par´ametro van las banderas que pueden ser :
PARTE 3. RAW SOCKET ??
18
1. 0, send funciona igual que write. 2. MSG OOB, indica env´ıo de datos urgentes. 3. MSG DONROUTE, hace que se ignoren los mecanismos de enrutamiento. Para el cuarto par´ametro se tiene una estructura de tipo sockaddr, que se completa con la direcci´on y puerto del destino del mensaje Por u ´ltimo en el quinto par´ametro se env´ıa el tama˜ no de la estrcutura sockaddr
3.2.3.
recvfrom
#include <s y s / t y p e s . h> #include <s y s / s o c k e t . h> int r e c v f r o m ( int s , void ∗ buf , int l e n , unsigned int f l a g s , struct s o c k a d d r ∗ from , int f r o m l e n ) ;
Como primer par´ametro se indica el descriptor del socket. El segundo par´ametro es un punteo a donde se van almacenar los datos recibidos. El tercer par´ametro indica el tamano de este buffer. En el cuarto par´ametro van las banderas que pueden ser : 1. MSG PEEK, permite acceso a los datos sin eliminarlos del buffer. 2. MSG OOB, indica recepci´on de datos urgentes. 3. MSG WAITALL, hace que la operacion de lectura se bloquee hasta el llenado total del buffer Para el quinto par´ametro se tiene una estrcutura de tipo sockaddr, que nos permite tener acceso a la informaci´on de quien envio el paquete En el sexto y ultimo par´ametro se envia el tama˜ no de la estructura sockaddr
3.2.4.
getsockopt && setsocketopt
Funciones importantes que nos permiten modificar el comportamiento de un socket.
PARTE 3. RAW SOCKET ??
19
#include <s y s / t y p e s . h> #include <s y s / s o c k e t . h> int g e t s o c k o p t ( int s , int l e v e l , int opname , void ∗ o p t v a l , int optlen ) ; int s e t s o c k o p t ( int s , int l e v e l , int opname , const void ∗ o p t v a l , int o p t l e n ) ;
Como primer par´ametro se indica el descriptor del socket. El segundo par´ametro indica la capa o el nivel de protocolo en la que se har´a el cambio El tercer par´ametro indica la opci´on que queremos modificar En el cuarto par´ametro se indica el valor con el que se desea modificar. Para el quinto par´ametro se tiene el tama˜ no de la variable referenciada a modificar. IPPROTO_IP - IP_OPTIONS IPPROTO_IP - IP_HDRINCL IPPROTO_TCP - TCP_MAXSEG IPPROTO_TCP - TCP_NODELAY SOL_SOCKET SOL_SOCKET SOL_SOCKET SOL_SOCKET SOL_SOCKET SOL_SOCKET SOL_SOCKET SOL_SOCKET SOL_SOCKET
3.3. 3.3.1.
-
SO_BROADCAST /Env´ ıo de broadcast SO_DEBUG SO_DONTROUTE SO_ERROR SO_KEEPALIVE /Mantener viva la conexi´ on SO_LINGER /Env´ ıo al desconexi´ on SO_REUSEADDR / Reuso de direcci´ on SO_TYPE / Obtenci´ on del tipo de socket BINDTODEVICE /Enlazar socket con dispositvo
Algunas estrcuturas importantes Estructura ifreq
#include <s y s / i o c t l . h> #include struct i f r e q { char i f r n a m e [ IFNAMSIZ ] ; /∗ I n t e r f a c e name ∗/ union {
PARTE 3. RAW SOCKET ?? struct struct struct struct struct short int int int struct char char char ∗
20
sockaddrifr addr ; sockaddrifr dstaddr ; sockaddrifr broadaddr ; sockaddrifr netmask ; sockaddrifr hwaddr ; ifr flags ; ifr ifindex ; ifr metric ; ifr mtu ; ifmapifr map ; i f r s l a v e [ IFNAMSIZ ] ; i f r n e w n a m e [ IFNAMSIZ ] ; ifr data ;
}; }; struct i f c o n f { int i f c l e n ; /∗ s i z e o f b u f f e r ∗/ union { char ∗ i f c b u f ; /∗ b u f f e r a d d r e s s ∗/ struct i f r e q ∗ i f c r e q ; /∗ a r r a y o f s t r u c t u r e s ∗/ }; };
Para m´as informaci´on recomiendo esta p´agina http://linux.about.com/library/cmd/blcmdl7 netdevice.htm subsectionEstructura sockaddr ll struct s o c k a d d r l l { unsigned short s l l f a m i l y ; /∗ Always AF PACKET ∗/ unsigned short s l l p r o t o c o l ; /∗ P h y s i c a l l a y e r p r o t o c o l ∗/ int sll ifindex ; /∗ I n t e r f a c e number ∗/ unsigned short s l l h a t y p e ; /∗ Header t y p e ∗/ unsigned char sll pkttype ; /∗ P a ck e t t y p e ∗/ unsigned char sll halen ; /∗ Length o f a d d r e s s ∗/ unsigned char sll addr [8]; };
/∗ P h y s i c a l l a y e r a d d r e s s ∗/
PARTE 3. RAW SOCKET ??
21
Figura 3.1: Ejecuci´on captada por IPTraf del c´odigo bajado de internet y como vemos no funciona
3.4.
Un ejemplo para empezar
Cuando empec´e en este tema de los sockets crudos, me encontr´e con un ejemplo el cual considero el d´ıa de hoy es muy bueno para poder explicar e iniciarse con los raw sockets, seguramente personas que hayan estado en contacto con este tema lo han de ver visto en internet, donde muchas personas ya se consideran hackers XD al correr este ejemplo, pero les tengo una mala noticia, el ejemplo como tal tiene fallas y si buscan realizar un ataque SYN FLOOD como mencionan se puede hacer, si tienen un router enfrente fallar´a lamentablemente, pero en este documento he corregido los errores (TCP bogus header at least 20 length, Checksum offload, TCP header error offset), pero vamos lo incluyo, ya que lo considero totalmente u ´til para el inicio de este tema.
PARTE 3. RAW SOCKET ??
22
Lamentablemente al correrlo tendr´an que hacer el checksum manualmente del TCP header (el cual consta de la suma del pseudoheader TCP + header TCP + datos) al menos que se ocupen los mismos datos que yo manejo en el ejemplo, ya que si cambian la IP origen o destino se tendr´a que volver a realizar; no incluyo una funci´on que lo realice automa´aticamente, ya que como tal no lo considero necesario para fines de este manual. #include <s t d i o . h> #include <s t r i n g . h> #include /∗ L i b r e r´ı a de l o s s o c k e t s ∗/ #include <s y s / s o c k e t . h> #include /∗ Para o b t e n e r d a t o s de capa 3 ∗/ #include /∗ Para o b t e n e r d a t o s de capa 4 ∗/ /∗ Usaremos l a e s t r u c t u r a BSD para TCP hdr ∗/ #define FAVOR BSD #include #include /∗ Puerto a l c u a l s e va a e n v i a r e l p a q u e t e ∗/ #define P 22 int i =0; /∗ Recordemos que a l no t e n e r e l s t a c k TCP/IP ∗/ /∗ implementado tendremos que h a c e r e l checksum ∗/ /∗ manualmente con ayuda de e s t a f u n c i ´ o n ∗/ unsigned short csum ( unsigned short ∗ buf , int nwords ) { unsigned long sum ; f o r ( sum = 0 ; nwords > 0 ; nwords−−) sum += ∗ buf++; sum = ( sum >> 1 6 ) + ( sum & 0 x f f f f ) ; sum += ( sum >> 1 6 ) ; return ˜sum ; }
int main ( int argc , char ∗∗ argv ) { int one = 1 ; const int ∗ v a l = &one ; p r i n t f ( ” I n i c i a m o s e n v´ıo de p a q u e t e s \n” ) ; /∗ Creamos e l s o c k e t crudo , e l c u a l implementar´ a TCP/IP ∗/
PARTE 3. RAW SOCKET ??
23
int s = s o c k e t ( PF INET , SOCK RAW, IPPROTO TCP) ; /∗ Creamos un b u f f e r que c o n t e n d r ´ a l a s c a b e c e r a s , IP y TCP ∗/ /∗ adem´ a s d e l p a y l o a d ∗/ char datagram [ 4 0 9 6 ] ; /∗En e s t e c a s o iremos d e l p r o t o c o l o m´ as b a j o a l m´ as a l t o por l o que empezaremos con IP , a l c r e a r una e s t u c t u r a i p ∗/ struct i p ∗ i p h = ( struct i p ∗ ) datagram ; /∗ Usaremos una e s t u c t u r a de s o c k e t para e l e n v´ıo de p a q u e t e s ∗/ struct s o c k a d d r i n s i n ; /∗ Usaremos l a f a m i l i a INET a l t e n e r que s a l i r por l a r e d ∗/ s i n . s i n f a m i l y = AF INET ; /∗ Se e s c o g e un p u e r t o d e s t i n o a l que s e e n v i a r ´ an l o s paquetes ∗/ s i n . s i n p o r t = h t o n s (P) ; /∗ Escogemos l a IP d e s t i n o de n u e s t r o s p a q u e t e s ∗/ sin . sin addr . s addr = inet addr (” 132.248.59.1 ”) ; /∗Ponemos e l b u f f e r con l o s h e a d e r s en c e r o ∗/ memset ( datagram , 0 , 4 0 9 6 ) ; /∗ Hasta e s t a p a r t e podr´ a n p e n s a r que no hemos hecho diferente ya que s e usa una e s t r u c t u r a s o c k a d d r i n para e l e g i r todo p a r e c e s e r l o mismo , p ero ahora tendremos e l c o n t r o l campos de l a s c a b e c e r a s IP y TCP, para e n v i a r l o s por l a r e d /∗ Por l o que empezamos a r e l l e n a r l o s manualmente ∗/
nada destino y de l o s ∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/ /∗ HEADER IP ∗/ iph−>i p h l = 5 ; /∗ Se e s c o g e l a v e r s i ´ o n de IPv4 ∗/ iph−>i p v = 4 ; /∗ Se e s c o g e e l Type o f S e r v i c e ∗/ iph−>i p t o s = 0 ; /∗ Se da l a l o n g i t u d de l a c a b e c e r a IP ∗/ iph−>i p l e n = s i z e o f ( struct i p ) + s i z e o f ( struct t c p h d r ) ;
PARTE 3. RAW SOCKET ??
24
p r i n t f ( ” Esta e s l a l o n g i t u d i p l e n %d \n” , iph−>i p l e n ) ; /∗ I d e n t i f i c a d o r d e l p a q u e t e ∗/ iph−>i p i d = h t o n l ( 5 4 3 2 1 ) ; /∗ Se da e l o f f s e t d e l p a q u e t e ∗/ iph−>i p o f f = 0 ; /∗ Ponemos e l t i m e t o l i v e ∗/ iph−> i p t t l = 2 5 5 ; /∗ Se e s o c g e e l p r o t o c o l o a u s a r ∗/ iph−>i p p = 6 ; // 6 a l s e r TCP / e t c / p r o t o c o l /∗ Moment´ a neamente pones e l checksum a c e r o ∗/ iph−>ip sum = 0 ; /∗ Se e s c o g e l a i p o r i g e n , s´ı c l a r o pondremos l a que queramos XD ∗/ /∗ Pero s i queremos s a l i r por l a red , e l p r o x y ISP no permitir´ a cualquier direcci´ o n en e s t e campo ∗/ iph−>i p s r c . s a d d r = i n e t a d d r ( ” 1 9 2 . 1 6 8 . 1 . 7 0 ” ) ; /∗ Se d e f i n e l a i p d e s t i n o mediante l a e s t r u c t u r a d e f i n i d a a n t e r i o r m e n t e ∗/ iph−>i p d s t . s a d d r = s i n . s i n a d d r . s a d d r ; /∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/ /∗ HEADER TCP ∗/ /∗ Ahora crearemos l a e s t r u t u r a TCP ∗/ struct t c p h d r ∗ tcph = ( struct t c p h d r ∗ ) ( datagram + iph−> i p h l ∗4 ) ; p r i n t f ( ” Esta e s l a l o n g i t u d s t r u c t i p %d \n” , s i z e o f ( ∗ i p h ) ) ; p r i n t f ( ” Esta e s l a l o n g i t u d s t r u c t t c p h d r %d \n” , s i z e o f ( ∗ tcph ) ) ; /∗ Se da e l p u e r t o o r i g e n d e l p a q u e t e ∗/ tcph−>t h s p o r t = h t o n s ( 4 5 5 2 1 ) ; /∗ Se da e l p u e r t o d e s t i n o d e l p a q u e t e ∗/ tcph−>t h d p o r t = h t o n s (P) ; /∗ Se da e l n´ u mero de s e c u e n c i a d e l p a q u e t e ∗/ tcph−>t h s e q = random ( ) ; /∗ N´ umero de l a s e c u e n c i a ACK ∗/ tcph−>t h a c k = 0 x00000000 ; tcph−>t h x 2 = 0 ; /∗ Se da e l o f f s e t de l a c a b e c e r a TCP ( 5 ∗ 4 ) ∗/ tcph−>t h o f f = 5 ; /∗ Ponemos para l a p e t i c i ´ o n de una c o n e x i ´ o n ∗/ tcph−>t h f l a g s = TH SYN ; /∗ Indicamos e l tama˜ n o de l a v e n t a n a ∗/ tcph−>t h w i n = 0 x 0 1 8 f ; /∗ S i ponemos e l checksum TCP a c e r o aunque d i g a n que e l s t a c k l o r e l l e n a en l o p e r s o n a l no me f u n c i o n ´ o , por
PARTE 3. RAW SOCKET ??
25
l o que t u v e que h a c e r e l checksum ∗/ checksum c o r r e c t o ∗/ tcph−>th sum = 0 x 6 0 f a ; tcph−>t h u r p = 0 ;
/∗ Se da e l checksum d e l p a q u e t e y s e i n c l u y e en e l campo ∗/ iph−>ip sum = csum ( ( unsigned short ∗ ) datagram , iph−>i p l e n >> 1 ) ; p r i n t f ( ”Checksum i p %x \n” , iph−>ip sum ) ; /∗ Al u s a r IP HDRINCL l e decimos que estamos i n c l u y e n d o e l h e a d e r IP en e l p a q u e t e ∗/ i f ( s e t s o c k o p t ( s , IPPROTO IP , IP HDRINCL , val , s i z e o f ( one ) ) < 0) p r i n t f ( ” E r r o r : No s e m o d i f i c ´o e l s o c k e t \n” ) ; while ( i !=10) { i ++; i f ( s e n d t o ( s , datagram , ( iph−>i p l e n ) , 0 , ( struct s o c k a d d r ∗ ) &s i n , s i z e o f ( s i n ) ) < 0 ) p r i n t f ( ” Paquete no s e ha podido e n v i a r \n” ) ; else p r i n t f ( ” Paquete e n v i a d o \n” ) ; } return 0 ; }
root@koitoerdp:~/Tutorial raw-sockets# gcc injection.c -o injection root@koitoerdp:~/Tutorial raw-sockets# ./injection Iniciamos env´ ıo de paquetes Esta es la longitud ip_len 40 Esta es la longitud struct ip 20 Esta es la longitud struct tcphdr 20 Checksum ip 1294 Paquete enviado Paquete enviado Paquete enviado Paquete enviado Paquete enviado
PARTE 3. RAW SOCKET ??
26
Paquete enviado Paquete enviado Paquete enviado Paquete enviado Paquete enviado root@koitoerdp:~/Tutorial raw-sockets#
En este caso vemos que al lanzar la ejecuci´on se mandan paquetes TCP SYNC, para el inicio del HANDSHAKE, al puerto 22 de una m´aquina remota, la cual nos reponde con un SYNC+ACK, por las diez veces que mandamos ese paquete, pero si nos fijamos en la imag´en del sniffer, nuestra m´aquina la 192.168.1.70, env´ıa un RST, que es un Reset Connection al no haber proceso alguno que se encarge de los paquetes reci´en recibidos, ya que como tal s´olo mandamos los diez SYNC, nunca esperamos respuesta. Como vemos, es un programa que nos permite poner directamente los campos de los headers, TCP e IP, con lo que corroboramos que podemos tener el control de los protocolos ya existentes, en este caso debemos de tener en cuenta que si quisieramos atacar algun host, cambiando nuestra IP, para que no nos detecten, muchas veces nuestro ISP, no permitir´a que este tipo de peticiones salgan a internet, debido a que el mismo reconoce que no son propias de su configuraci´on, aunque si estudiamos un poco el tipo de direcciones IP, que maneja esto si ser´a posible.
PARTE 3. RAW SOCKET ??
Figura 3.2: Ejecuci´on captada por Wireshark
27
Parte 4 Un sniffer para comenzar Despu´es de programar un poco, tenemos listo un sniffer, que nos permite analizar la informaci´on contenida en ciertos protocolos, en este caso si se desea el an´alisis de otro protocolo, simplemente tendremos que realizar una inclusi´on del desglose del protocolo en el lugar correcto como lo hare mas adelante.
4.1.
SNIFFER
Primero que nada,¿qu´e es un sniffer?, bueno es un programa de captura de tramas, que se usa con diversos fines, como pueden ser el an´alisis de protocolos, la gesti´on de las redes, fines maliciosos XD, an´alisis de fallos, detecci´on de posibles ataques o intrusos, o como simple medidor de tr´afico.
4.1.1.
PROMISC MODE ??
Es una configuraci´on de la tarjeta de red, la cual nos permite pasar a nivel de aplicaci´on todos los paquetes recibidos sean o no para nosotros, por lo que podremos escuchar todo el tr´afico que llegue a nuestra tarjeta, que pudiese ser m´ınimo si hablamos de una computadora o host, pero puede llegar a ser ciertamente alto si activamos este modo en un gateway de salida de una LAN, o en medio de una red WI-FI. Para activar este modo de la tarjeta debemos de tener permisos de administrador. root@koitoerdp:~# ifconfig eth0 promisc root@koitoerdp:~# ifconfig 28
PARTE 4. SNIFFER eth0
29
Link encap:Ethernet HWaddr 00:40:f4:a5:8c:5a inet addr:192.168.1.70 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::240:f4ff:fea5:8c5a/64 Scope:Link UP BROADCAST RUNNING PROMISC MULTICAST MTU:1500 Metric:1 RX packets:2511 errors:0 dropped:0 overruns:0 frame:0 TX packets:1328 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:238408 (238.4 KB) TX bytes:218862 (218.8 KB) Interrupt:19 Base address:0xc400
Como se aprecia la palabra PROMISC aparece marcando la interfaz XD. Para quitarla del modo promiscuo, s´olo la reiniciamos,para esto debemos tener cuidado ya que si estamos conectados remotamente al reiniciar la interfaz, nos desconectar´a. Para la detecci´on de tarjetas en modo promiscuo dentro de nuestra red, tenemos varias opciones, que se dividen en dos tipos, el primero checar manualmente cada tarjeta de red para ver si est´a en modo promiscuo, suena dif´ıcil verdad, bueno entonces podemos crear un demonio el cual nos permita saber cuando una tarjeta cambie a modo promiscuo, esto simplemente lo haremos leyendo el /var/log/message, donde queda huella cuando una interfaz hace uso de este modo May 2 device May 2 device May 2 device May 2 device
17:02:00 koitoerdp kernel: [17157.272110] lo entered promiscuous mode 17:02:04 koitoerdp kernel: [17161.113065] lo left promiscuous mode 17:11:16 koitoerdp kernel: [17712.772099] eth0 entered promiscuous mode 17:11:56 koitoerdp kernel: [17752.564435] eth0 left promiscuous mode
Pero vamos si lo borra, lo cual es dif´ıcil al menos que se tenga la contrase˜ na de root, pues s´olo nos queda hacer uso de diversas t´ecnicas para encontrar tarjetas en modo promiscuo, que pueden ser por medio del env´ıo de paquetes ARP o el uso de antisniffers como Antisnif o Sentinel. Para esto tambi´en encontr´e en internet, un buen programa que se llama neped.c, que se encarga de la identificaci´on de un host con su tarjeta en modo promiscuo a trav´es del simple env´ıo de paquetes ARP a m´aquinas inexistentes. Considero que
PARTE 4. SNIFFER
30
echarle un vistazo al c´odigo puede ser en este momento un tanto d´ıficil, pero al final de este tutorial puede ser bastante did´actico, para ver y corroborar lo aprendido.
4.2.
ksniffer
Muy bien, es hora de programar un sniffer sencillo, que capture el tr`afico TCP que pasa por nuestra interfaz, entonces empecemos. #include #include #include #include #include #include #include #include
<s t d i o . h> < f c n t l . h> <s y s / s o c k e t . h>
int main ( ) { /∗ Creamos e l s o c k e t crudo , e l c u a l s ´ o l o va a capturar e l t r ´ a f i c o de p a q u e t e s TCP, como l o indica l a opci´ o n IPPROTO TCP ∗/ int f d = s o c k e t ( PF INET , SOCK RAW, IPPROTO TCP) ; /∗ Ser´ a n u e s t r o b u f f e r de c a p t u r a ∗/ char b u f f e r [ 8 1 9 2 ] ; int i =0 ; int b y t e s = 0 ; /∗ Entramos a un c i c l o i n f i n i t o que nos p e r m i t e i r c a p t u r a n d o y mostrando e l t r ´ a f i c o , en e s t e c a s o usamos read , ya que estamos t r a b a j a n d o con e l p r o t o c o l o TCP ∗/ while ( ( b y t e s = r e a d ( fd , b u f f e r , 8 1 9 2 ) ) > 0 ) { /∗ Una v e z c a p t u r a d o l o mostramos a im pr es i´ on , e s t o l o hacemos s e n ˜ a l a n d o donde i n i c i a e s t a i n f o r m a c i ´ on , l o cual e x p l i c a r ´e un poco m´ as a d e l a n t e ∗/ p r i n t f ( ” Paquete c a p t u r a d o %s \n” , b u f f e r+s i z e o f ( struct i p h d r )+s i z e o f ( struct t c p h d r ) ) ; p r i n t f ( ” Contenido : \n” ) ; p r i n t f ( ” Hexadecimal \n” ) ; f o r ( i = 0 ; i < b y t e s ; i ++) p r i n t f ( ” %x” , b u f f e r [ i ] ) ; p r i n t f ( ” \ n E n t e n d i b l e \n” ) ; f o r ( i = 0 ; i < b y t e s ; i ++) p r i n t f ( ” %c ” , b u f f e r [ i ] ) ;
PARTE 4. SNIFFER
31
p r i n t f ( ”\ n S i g u i e n t e −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− \n” ) ; } }
4.2.1.
Compilaci´ on y Ejecuci´ on
gcc Sniffer.c -o SnifferSimple ./SnifferSimple Paquete capturado Contenido : Hexadecimal 450028ffffffb616400ffffff806ffffffc0ffffffddffffffc0 ffffffa8145ffffffc0ffffffa81468ffffffb3016ffffffc3d6 e2affffff831dffffffbbffffffa65010fffffffa4fffffffb8f fffffe300 Entendible [CARACTERES OMITIDOS] Siguiente -------------------------------------Si como lo podemos apreciar ya tenemos nuestro gran sniffer, pero me dir´an que no se entiende nada jajaja, pues claro s´olo estamos capturando los paquetes jam´as los ordenamos y obtenemos los datos de ellos, asi que esa ser´a nuestra siguiente tarea, lo que cabe resaltar en este ejemplo es el uso de las estructuras que previamente habiamos platicado.
4.3.
Sniffer mejorado.
Algo que tenemos que recordar, que es tan simple, pero a la vez es lo m´as importante al momento de obtener la informaci´on u ´til en un sniffer, es la forma en la que se est´a recibiendo y enviando la informaci´on, recordemos que tenemos capas del modelo OSI, por lo que tenemos en la red un paquete, que por decirlo de alguna manera esta empaquetado, esto se ve como se muestra en la siguiente figura Entonces como vemos en la figura lo primero que llega siempre es el Header de la capa de enlace, despues viene el NH (Network header) header
PARTE 4. SNIFFER
32
Figura 4.1: Empaquetado en modelo OSI de red, despu´es el TH (transport header) header de la capa de transporte, despu´es los header de sesi´on, presentaci´on y por u ´ltimo vienen los datos que contiene. Y si es as´ı como llega, entonces ser´a la forma que nosotros usaremos para ir leyendo y ordenando los datos, es importante tener en cuenta que recibiremos con recvfrom(), funci´on que previamente vimos que nos permite almacenar en un buffer, por lo que la informaci´on almacenada en ese buffer, ser´a rescatable a trav´es de un apuntador. Ahora para decirle al apuntador de donde a donde llega la informaci´on de cierto header, lo que ocuparemos ser´an las estructuras antes vistas, de los diferentes headers. Haciendo una analog´ıa, tenemos un buffer de tama˜ no X, la estructura que describe el header de la capa de enlace supongamos que son Y bytes, obviamente si el paquete recibido es v´alido X tiene que ser mayor que Y, entonces diremos que los Y primeros bytes de X corresponden a la capa de enlace. Despu´es sabemos que en la capa de red el protocolo usado tiene un header de P bytes, ¿d´onde terminar´ıa este header de la capa de red? , bueno pues la respuesta es sencilla, si el header de red es de P bytes, primero que nada empezari´ıa en (Y + 1) bytes a partir del inicio del paquete, y por lo
PARTE 4. SNIFFER
33
tanto tendr´ıa su fin en ( Y + P ) bytes. En este caso ¿c´omo sabemos cu´anto valdr´ıa X, Y, P y dem´as ?, pues con ayuda de la funci´on sizeof() sobre las estructuras que sabemos que se manejan en las diferentes capas del modelo OSI. Recordemos que en un arreglo de caracteres por ejemplo char mybuffer[1000], el inicio se puede indicar con mybuffer, o &mybuffer[0], con lo que apuntamos a la primera posici´on de todo el buffer, entonces si queremos movernos para captar el siguiente header o la informaci´on lo hacemos de la siguiente forma: buffer + sizeof( struct ethhdr) +sizeof( struct iphdr) + sizeof(struct tcphdr) Tenemos que en este caso primero apuntamos al inicio del paquete despu´es movemos el apuntador n lugares dependiendo de la suma del header ethernet + header ip + header tcp, por lo cual estaremos al inicio de la informaci´on que era nuestro objetivo, obviamente si leyeron bien, no podemos decir del todo que es la informaci´on como tal, ya que siguen diferentes headers y despu´es ahora si va la informaci´on. Entonces sabiendo esto s´olo les recordar´e una cosa, nosotros cuando creamos un socket crudo podemos definirle que protocolo usaremos, si le ponemos IPPROTO TCP, no nos llegar´a el header ethernet como en el primer ejemplo paso, pero tampoco nos llegar´a informaci´on UDP, ARP, ICMP, RARP y dem´as, entonces recordemos lo que mencione antes, que el kernel se encarga de subir la informaci´on a los sockets que esten escuchando cierto tipo de protocolo, asi que si estamos escuchando solo tr´afico TCP pues no recibiremos mas que eso, pero no se preocupen si queremos estudiar todos los protocolos y todo el tr´afico s´olo pondremos ETH P ALL, y lo haremos XD , pero recuerden que si usamos esta constante recibiremos TODO !!!! el tr´afico, por lo que nuestro sniffer capturar´a mucha informaci´on,y dif´ıcilmente podremos encontrar o ver lo que necesitamos, por lo que el uso de esta constante lo dejo a su criterio. Aunque cabe mencionar que m´as adelante en este tutorial, se har´a uso de la constante para que les ense˜ ne la forma de recibir protocolos de capa 3 y 4. Muy bien, creo que ha sido una buena introducci´on, asi que vamos al c´odigo. /∗ Programa s n i f f e r 1 . c ∗/ /∗ Compilado en Linux k o i t o e r s v 2.6.27 −14 − g e n e r i c i 6 8 6 GNU/ Linux ∗/ /∗ #1 SMP Wed Apr 15 1 8 : 5 9 : 1 6 UTC 2009 ∗/
PARTE 4. SNIFFER
#include<s t d i o . h> #include<s t r i n g . h> #include<s t d l i b . h> /∗ L i b r e r´ı a de l o s s o c k e t s ∗/ #include<s y s / s o c k e t . h> #include #include #include<e r r n o . h> /∗ L i b r e r´ı a de l o s s o c k e t s ∗/ #include<s y s / i o c t l . h> /∗ L i b r e r´ı a de c o n t r o l de i n t e r f a c e s ∗/ #include /∗ L i b r e r´ı a de l o s p a q u e t e s e t h e r n e t ∗/ #include /∗ L i b r e r´ı a de l o s p a q u e t e s i p ∗/ #include /∗ L i b r e r´ı a de l o s p a q u e t e s t c p ∗/ #include /∗ L i b r e r´ı a de d e f i n i c i o n e s de p r o t o c o l o s ∗/ #include /∗ L i b r e r´ı a para d e c o d i f i c a r u n s i g n e d char ∗/ #include void h e a d e r ( ) ; int obtenerData ( unsigned char ∗ , int ) ; int obtenerHTCP ( unsigned char ∗ , int ) ; void obtenerHIP ( unsigned char ∗ , int ) ; void o b t e n e r H E t h e r n e t ( unsigned char ∗ , int ) ; int s o c k e t i f ( char ∗ , int , int ) ; void impresionHex ( unsigned char ∗ , int ) ; void impresionASCII ( unsigned char ∗ , int ) ; void impresionFormatoIP ( unsigned char ∗ , int ) ; int main ( int argc , char ∗∗ argv ) { /∗ Nuestro f u t u r o r a w s o c k e t ∗/ int r s o c k ; int l e n ; /∗ N´ umero de p a q u e t e s a r e c i b i r ∗/ int p a q u e t e s ; /∗ Bandera para l a i m p r e s i ´ o n o no de d a t o s ∗/ int v a l i d a c i o n =0; int p a c k e t = 0 ; /∗ B u f f e r de l e c t u r a de l a i n f o r m a c i ´ o n r e c i b i d a ∗/
34
PARTE 4. SNIFFER
35
unsigned char p b u f f e r [ 2 0 4 8 ] ; /∗ E s t r u c t u r a que l i g a r ´ a e l s o c k e t con l a i n t e r f a z ∗/ struct s o c k a d d r l l p i n f o ; /∗ Definimos tamano d e l b u f f e r ∗/ int p s i z e = s i z e o f ( p i n f o ) ; i f ( a r g c !=3) { p r i n t f ( ”Uso %s \n” , argv [ 0 ] ) ; e x i t ( −1) ; } /∗ Se c r e a un s o c k e t crudo para p r o t o c o l o IP ∗/ r s o c k = c r e a S o c k e t ( ETH P IP ) ; /∗ Se i n i c i a e l p r o c e s o ∗/ header ( ) ; /∗ Se une e l s o c k e t a un i n t e r f a z de l a m´ a quina ∗/ s o c k e t i f ( argv [ 1 ] , r s o c k , ETH P IP ) ; /∗ Decimos e l n´ u mero de p a q u e t e s a c a p t u r a r ∗/ p a q u e t e s = a t o i ( argv [ 2 ] ) ; /∗ Empezamos l a c a p t u r a de n n´ u mero de p a q u e t e s ∗/ while ( paquetes −−){ /∗ Recibimos p a q u e t e s a t r a v ´e s d e l s o c k e t crudo d e l p r o t o c o l o IP ∗/ /∗ Y l o s pasamos l o s d a t o s a l b u f f e r , adem´ a s de su informaci´ o n a l a e s t r u c t u r a p i n f o ∗/ i f ( ( l e n = r e c v f r o m ( r s o c k , p b u f f e r , 2 0 4 8 , 0 , ( struct s o c k a d d r ∗ )&p i n f o , &p s i z e ) ) == −1){ p e r r o r ( ”Ha habido un e r r o r en l a c a p t u r a ” ) ; e x i t ( −1) ; } else { p r i n t f ( ”−−−−−−−− Paquete Capturado No . %d −−−−−−−−−−−− \n” , p a c k e t++) ; /∗ Una v e z c a p t u r a d o obtendremos l a i n f o r m a c i o n ∗/ /∗ Obtenemos e l h e a d e r e t h e r n e t capa 2 ∗/ obtenerHEthernet ( p b u f f e r , len ) ; /∗ Obtenemos e l h e a d e r i p capa 3 ∗/ obtenerHIP ( p b u f f e r , l e n ) ; /∗ Obtenemos e l h e a d e r t c p capa 4 ∗/ v a l i d a c i o n = obtenerHTCP ( p b u f f e r , l e n ) ; i f ( v a l i d a c i o n == 1 ) obtenerData ( p b u f f e r , l e n ) ; p r i n t f ( ”−−−−−−−− END Paquete Capturado No . %d −−−−−−−−− \n \n” , p a q u e t e s ) ; } // f i n d e l e l s e bzero ( p buffer , sizeof ( p b u f f e r ) ) ; } // f i n d e l w h i l e
PARTE 4. SNIFFER
36
return 0 ; }
int c r e a S o c k e t ( int p r o t o c o l ) { int r s o c k e t ; i f ( ( r s o c k e t = s o c k e t (PF PACKET, SOCK RAW, h t o n s ( p r o t o c o l ) ) )== −1){ p e r r o r ( ” E r r o r a l c r e a r e l s o c k e t crudo ” ) ; e x i t ( −1) ; } return r s o c k e t ; } void h e a d e r ( ) { p r i n t f ( ” S n i f f e r ! \n” ) ; p r i n t f ( ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n” ) ; }
int s o c k e t i f ( char ∗ i n t e r f a z , int r s o c k , int p r o t o c o l ) { /∗ Ahora en v e z de l i g a r e l s o c k e t con un p u e r t o ∗/ /∗ La l i g a r e m o s con una i n t e r f a z ∗/ struct s o c k a d d r l l s l l ; struct i f r e q i f r ; b z e r o (& s l l , s i z e o f ( s l l ) ) ; /∗ Limpiamos l a e s t r u c t u r a de d a t o s de l a i n t e r f a z ∗/ b z e r o (& i f r , s i z e o f ( i f r ) ) ; strcpy ( i f r . ifr name , i n t e r f a z ) ; /∗ Cargamos d a t o s de l a i n t e r f a z a l a e s t r u c t u r a i f r ∗/ i f ( ( i o c t l ( r s o c k , SIOCGIFINDEX , & i f r ) ) == −1){ p r i n t f ( ”No s e puede o b t e n e r l a i n t e r f a z ! \ n” ) ; e x i t ( −1) ; } /∗ I m p r e s i ´ o n de p r o p i e d a d e s de l a i n t e r f a z ∗/ /∗ Obtenemos l a s f l a g s de l a i n t e r f a z ∗/ i f ( ( i o c t l ( r s o c k , SIOCGIFFLAGS,& i f r ) ) < 0 ) { p e r r o r ( ” E r r o r : Al o b t e n e r b a n d e r a s de l a interfaz ”) ; } int f l a g s =0; flags = ifr . ifr flags ;
PARTE 4. SNIFFER /∗ Checamos s i l a i n t e r f a z e s t ´ a a c t i v a ∗/ i f ( ( f l a g s & IFF UP ) != 0 ) p r i n t f ( ” D i s p o s i t i v o a r r i b a [UP] \n” ) ; else { p r i n t f ( ” El d i s p o s i t i v o no e x i s t e no e s t ´a a r r i b a \n ” ) ; e x i t ( −1) ; } /∗ Checamos s i l a i n t e r f a z e s t ´ a en modo promisuo ∗/ i f ( ( f l a g s & IFF PROMISC) != 0 ) p r i n t f ( ” D i s p o s i t i v o en modo Promiscuo \n” ) ; p r i n t f ( ”La i n t e r f a z de c a p t u r a e s %s \n” , i n t e r f a z ) ; /∗ Obtenemos l a d i r e c c i o n MAC ∗/ i f ( ( i o c t l ( r s o c k ,SIOCGIFHWADDR,& i f r ) ) < 0 ) { p e r r o r ( ” E r r o r : Al o b t e n e r MAC a d d r e s s ” ) ; e x i t ( −1) ; } p r i n t f ( ”La MAC de l a i n t e r f a z e s : ” ) ; impresionHex ( i f r . i f r h w a d d r . s a d a t a , 6 ) ; /∗ Obtenemos l a d i r e c c i o n IP ∗/ i f ( ( i o c t l ( r s o c k , SIOCGIFADDR,& i f r ) ) < 0 ) { p e r r o r ( ” E r r o r : Al o b t e n e r d i r e c c i ´o n IP ” ) ; e x i t ( −1) ; } p r i n t f ( ”La D i r e c c i ´o n IP de l a i n t e r f a z e s : ” ) ; impresionFormatoIP (& i f r . i f r a d d r . s a d a t a [ 2 ] , 4 ) ; /∗ Obtenemos l a m´ a scara de r e d ∗/ i f ( ( i o c t l ( r s o c k , SIOCGIFNETMASK,& i f r ) ) < 0 ) { p e r r o r ( ” E r r o r : Al o b t e n e r l a m´a scara de r e d ” ) ; e x i t ( −1) ; } p r i n t f ( ”La M´ a scara de r e d de l a i n t e r f a z e s : ” ) ; impresionFormatoIP (& i f r . i f r n e t m a s k . s a d a t a [ 2 ] , 4 ) ; /∗ Obtenemos l a d i r e c c i ´ o n de b r o a d c a s t ∗/ i f ( ( i o c t l ( r s o c k ,SIOCGIFBRDADDR,& i f r ) ) < 0 ) { p e r r o r ( ” E r r o r : Al o b t e n e r l a d i r e c c i ´o n de broadcast ” ) ; e x i t ( −1) ; } p r i n t f ( ”La d i r e c c i ´o n de b r o a d c a s t de l a i n t e r f a z e s : ”
37
PARTE 4. SNIFFER ); impresionFormatoIP (& i f r . i f r b r o a d a d d r . s a d a t a [ 2 ] , 4 ) ; /∗ Obtenemos e l ´ı n d i c e de l a i n t e r f a z ∗/ i f ( ( i o c t l ( r s o c k , SIOCGIFINDEX , & i f r ) ) == −1){ p r i n t f ( ”No s e puede o b t e n e r l a i n t e r f a z ! \ n” ) ; e x i t ( −1) ; } /∗ Siempre AF PACKET ∗/ s l l . s l l f a m i l y = AF PACKET; /∗ Definimos e l ´ı n d i c e a l c u a l s e l i g a r ´ a e l s o c k e t ∗/ sll . sll ifindex = ifr . ifr ifindex ; /∗ Definimos e l p r o t o c o l o que s e manejar´ a ∗/ s l l . s l l p r o t o c o l = htons ( p r o t o c o l ) ; /∗ Ligamos e l s o c k e t a l a i n t e r f a z ∗/ i f ( ( bind ( r s o c k , ( struct s o c k a d d r ∗ )&s l l , s i z e o f ( s l l ) ) )== −1){ p e r r o r ( ” E r r o r a l u n i r e l s o c k e t con l a i n t e r f a z \n” ) ; e x i t ( −1) ; } p r i n t f ( ” \n−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−” ) ; return 1 ; }
void impresionHex ( unsigned char ∗p , int num) { while (num−−){ p r i n t f ( ” %.2X ” , ∗p ) ; p++; } p r i n t f ( ” \n” ) ; } void impresionASCII ( unsigned char ∗p , int num) { while (num−−){ p r i n t f ( ” %c ” , t o a s c i i ( ∗ p ) ) ; p++; } p r i n t f ( ” \n” ) ; } void impresionFormatoIP ( unsigned char ∗p , int num) { while (num−−){ p r i n t f ( ” %d” , ∗p ) ;
38
PARTE 4. SNIFFER
39
i f (num!=0) printf (” . ”) ; p++; } p r i n t f ( ” \n” ) ; } void o b t e n e r H E t h e r n e t ( unsigned char ∗ packet , int l e n ) { /∗ Creamos una e s t r u c t u r a de t i p o e t h h d r ∗/ /∗ para v a c i a r l o s d a t o s y c a s t e a r l o s ∗/ struct e t h h d r ∗ h e t h e r n e t ; /∗ Hacemos e l ordenamiento s i e m p r e y cuando tengamos s u f i c i e n t e s b y t e s ∗/ i f ( l e n > s i z e o f ( struct e t h h d r ) ) { h e t h e r n e t = ( struct e t h h d r ∗ ) p a c k e t ; /∗ Ahora obtenemos l o s d a t o s i m p o r t a n t e s que s e r´ıa n ∗/ /∗ MAC ORIGEN,MAC DESTINO y PROTOCOLO DE RED∗/ p r i n t f ( ” P r o t o c o l o de r e d : ” ) ; impresionHex ( ( void ∗ )&h e t h e r n e t −>h p r o t o , 2 ) ; p r i n t f ( ”MAC D e s t i n o : ” ) ; impresionHex ( h e t h e r n e t −>h d e s t , 6 ) ; p r i n t f ( ”MAC Origen : ” ) ; impresionHex ( h e t h e r n e t −>h s o u r c e , 6 ) ; } else p r i n t f ( ”HETHERNET : Paquete de tama˜ n o i n s u f i c i e n t e \n” ) ; }
void obtenerHIP ( unsigned char ∗ packet , int l e n ) { struct e t h h d r ∗ h e t h e r n e t ; struct i p h d r ∗ h i p ; h e t h e r n e t = ( struct e t h h d r ∗ ) p a c k e t ; /∗ Confirmamos que s e t r a t a da un p a q u e t e IP ∗/ /∗ r e v i s a n d o e l campo h p r o t o de l a e s t r u c t u r a ∗/ /∗ e t h h d r ∗/ i f ( n t o h s ( h e t h e r n e t −>h p r o t o ) == ETH P IP ) { /∗ Confirmamos l a e x i s t e n c i a de s u f i c i e n t e s b y t e s ∗/ i f ( l e n >= ( s i z e o f ( struct e t h h d r ) + s i z e o f ( struct i p h d r ) ) ) { h i p = ( struct i p h d r ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) ) ; p r i n t f ( ” IP D e s t i n o : %s \n” , ( char ∗ ) i n e t n t o a ( h i p −>daddr ) ) ;
PARTE 4. SNIFFER
40
p r i n t f ( ” IP Origen : %s \n” , ( char ∗ ) i n e t n t o a ( h i p −>s a d d r ) ) ; } else p r i n t f ( ”HIP : Paquete de tama˜ n o i n s u f i c i e n t e \n” ) ; } else p r i n t f ( ” Este no e s un paquete IP \n ” ) ; }
int obtenerHTCP ( unsigned char ∗ packet , int l e n ) { struct e t h h d r ∗ h e t h e r n e t ; struct i p h d r ∗ h i p ; struct t c p h d r ∗ h t c p ; /∗ V e r i f i c a m o s que haya s u f i c i e n t e s b y t e s para c a s t e a r l o s h e a d e r s ∗/ i f ( l e n >= ( s i z e o f ( struct e t h h d r ) + s i z e o f ( struct i p h d r ) + s i z e o f ( struct t c p h d r ) ) ) { h e t h e r n e t = ( struct e t h h d r ∗ ) p a c k e t ; /∗ V e r i f i c a m o s s e t r a t e de un p a q u e t e IP ∗/ i f ( n t o h s ( h e t h e r n e t −>h p r o t o ) == ETH P IP ) { h i p = ( struct i p h d r ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) ) ; /∗ V e r i f i c a m o s s e t r a t a d e l p r o t o c o l o TCP ∗/ i f ( h i p −>p r o t o c o l == IPPROTO TCP) { /∗ Apuntamos a l a c a b e c e r a t c p ∗/ h t c p = ( struct t c p h d r ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) + h i p −>i h l ∗4 ) ; p r i n t f ( ” S o u r c e Port : %d\n” , n t o h s ( h tc p −>s o u r c e ) ) ; p r i n t f ( ” Dest Port : %d\n” , n t o h s ( h tc p −>d e s t ) ) ; return 1 ; } else p r i n t f ( ”No e s un paquete TCP\n” ) ; } else p r i n t f ( ”No e s un paquete IP \n” ) ; } else p r i n t f ( ”HTCP : Paquete de tama˜ n o i n s u f i c i e n t e \n” ) ; return 0 ; }
int obtenerData ( unsigned char ∗ packet , int l e n ) { struct e t h h d r ∗ h e t h e r n e t ; struct i p h d r ∗ h i p ;
PARTE 4. SNIFFER
41
struct t c p h d r ∗ h t c p ; unsigned char ∗ data ; int d a t a l e n ; i f ( l e n > ( s i z e o f ( struct e t h h d r ) + s i z e o f ( struct i p h d r ) + s i z e o f ( struct t c p h d r ) ) ) { /∗ Apuntamos y casteamos a l h e a d e r i p ∗/ h i p = ( struct i p h d r ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) ) ; /∗ Apuntamos a l i n i c i o de l a p a r t e de l o s d a t o s ∗/ data = ( p a c k e t + s i z e o f ( struct e t h h d r ) + s i z e o f ( struct i p h d r ) + s i z e o f ( struct t c p h d r ) ) ; /∗La l o n g i t u d de d a t o s e s l a l o n g i t u d de t o d o e l p a q u e t e ip , menos e l tama˜ n o d e l h e a d e r i p y h e a d e r t c p ∗/ d a t a l e n = n t o h s ( h i p −>t o t l e n ) − h i p −>i h l ∗4 − s i z e o f ( struct t c p h d r ) ; i f ( data len ){ p r i n t f ( ” Longitud de d a t o s : %d\n” , d a t a l e n ) ; p r i n t f ( ” Datos : \n” ) ; impresionHex ( data , d a t a l e n ) ; p r i n t f ( ” \n” ) ; return 1 ; } else { p r i n t f ( ”No hay d a t o s en l o s p a q u e t e s \n” ) ; return 0 ; } } else { p r i n t f ( ”DATOS : Paquete de tama˜ n o i n s u f i c i e n t e \n” ) ; return 0 ; } }
Como vermos tenemos funciones llamada obtener que nos permiten sacar la informaci´on de las diferentes capas, aunque todo esto se pudo haber hecho en una sola funci´on creo que est´a m´as claro al separarlo en varias. Ahora bien, hemos identificado algunos protocolos, y desglosado algunos de sus campos, por lo que ahora, tendremos que aumentarle funcionalidad y modos de captura, que ser´a el tema de la siguiente parte.
Parte 5 Implantar Funcionalidades 5.1.
Modificaciones
Como mencion´e antes, ahora se le implementar´an algunas funcionalidades extras, para que quede m´as clara la forma de trabajo de un sniffer un poco m´as completo; en este caso, debemos recordar que la documentaci´on de cada protocolo se haya en un RFC, el cual tendr´emos que leer y entender si necesitamos un an´alisis de un cierto protocolo espec´ıficamente. En las siguientes subsecciones s´olo pongo la modificaci´on del c´odigo que se hizo, no pongo todo el sniffer, ya que como tal ocupa muchas hojas, pero cada modificaci´on la pueden hallar en un programa sniffer#.c, que incluyo a descarga en mi p´agina.
5.1.1.
A˜ nadimos UDP
Ahora ya tenemos sniffer2.c que nos permite recibir solo tr´afico TCP, por lo que haremos una modificaci´on para poder entender el protocolo UDP i f ( h i p −>p r o t o c o l == IPPROTO TCP) { p r i n t f ( ” P r o t o c o l o TCP \n” ) ; h t c p = ( struct t c p h d r ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) + h i p −>i h l ∗4 ) ; p r i n t f ( ” S o u r c e Port : %d\n” , n t o h s ( h tc p −>s o u r c e ) ) ; p r i n t f ( ” Dest Port : %d\n” , n t o h s ( h tc p −>d e s t ) ) ; return 1 ; /∗ Se i n c l u y e n e s t a s l´ı n e a s , para c a p t u r a y d e s g l o s e de UDP ∗/
42
PARTE 5. IMPLANTAR FUNCIONALIDADES
43
} e l s e i f ( h i p −>p r o t o c o l == IPPROTO UDP) { p r i n t f ( ” P r o t o c o l o UDP \n” ) ; h udp = ( struct udphdr ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) + h i p −>i h l ∗4 ) ; p r i n t f ( ” S o u r c e Port : %d\n” , n t o h s ( h udp−>s o u r c e ) ) ; p r i n t f ( ” Dest Port : %d\n” , n t o h s ( h udp−>d e s t ) ) ; return 1 ; }
5.1.2.
A˜ nadimos ICMP
Bien ya tenemos el tr´afico TCP-UDP, ahora en sniffer3.c haremos la modificaci´on para captar ICMP y distinguir algunos tipos de mensajes, en este punto conviene que veamos la siguiente imagen, para observar en qu´e parte de la trama se haya la informaci´on correspondiente al protocolo ICMP. i f ( h i p −>p r o t o c o l == IPPROTO TCP) { p r i n t f ( ” P r o t o c o l o TCP \n” ) ; h t c p = ( struct t c p h d r ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) + h i p −>i h l ∗4 ) ; p r i n t f ( ” S o u r c e Port : %d\n” , n t o h s ( h tc p −>s o u r c e ) ) ; p r i n t f ( ” Dest Port : %d\n” , n t o h s ( h tc p −>d e s t ) ) ; return 1 ; } e l s e i f ( h i p −>p r o t o c o l == IPPROTO UDP) { p r i n t f ( ” P r o t o c o l o UDP \n” ) ; h udp = ( struct udphdr ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) + h i p −>i h l ∗4 ) ; p r i n t f ( ” S o u r c e Port : %d\n” , n t o h s ( h udp−>s o u r c e ) ) ; p r i n t f ( ” Dest Port : %d\n” , n t o h s ( h udp−>d e s t ) ) ; return 1 ; } e l s e i f ( h i p −>p r o t o c o l == IPPROTO ICMP) { p r i n t f ( ” P r o t o c o l o ICMP \n” ) ; icmp = ( struct icmphdr ∗ ) ( p a c k e t + h i p −>i h l ∗ 4 ) ; i f ( icmp−>type == ICMP INFO REQUEST ) p r i n t f ( ” ICMP p e t i c i ´o n d e s d e %s \n” , ( char ∗ ) i n e t n t o a ( h i p −>s a d d r ) ) ; e l s e i f ( icmp−>type == ICMP ECHO ) p r i n t f ( ” ICMP echo d e s d e %s \n” , ( char ∗ ) i n e t n t o a ( h i p −> daddr ) ) ; e l s e i f ( icmp−>type == ICMP ECHOREPLY ) p r i n t f ( ” ICMP e c h o r e p l y d e s d e %s \n” , ( char ∗ ) i n e t n t o a ( h i p −>daddr ) ) ; e l s e i f ( icmp−>type == ICMP DEST UNREACH )
PARTE 5. IMPLANTAR FUNCIONALIDADES
44
Figura 5.1: Header ICMP p r i n t f ( ” ICMP d e s t i n o i n a l c a n z a b l e d e s d e %s \n” , ( char ∗ ) i n e t n t o a ( h i p −>s a d d r ) ) ; } else p r i n t f ( ”No e s un paquete TCP\n” ) ;
5.1.3.
A˜ nadimos DHCP
Sigamos, d´emosle la funcionalidad de captar mensajes DHCP, bas´andonos en la estructura que maneja bind9 (DHCP server), para la mensajer´ıa de DHCP. Por lo que la pongo antes de todo el c´odigo fuente, aunque s´e que ser´ıa mejor y convendr´ıa ponerla en un archivo .h, para liberar un poco el c´odigo fuente, no lo hago debido a que quiero tener todo en un mismo archivo. /∗ Encabezados , e s t r u c t u r a s y v a r i a b l e s para e l manejo de DHCP ∗/ /∗ O b t e n i d o s d e l programa b i n d 9 ∗/ #define DHCP UDP OVERHEAD \ #define DHCP SNAME LEN #define DHCP FILE LEN #define DHCP FIXED NON UDP #define DHCP FIXED LEN DHCP UDP OVERHEAD)
( 2 0 + /∗ IP h e a d e r ∗/ 8) /∗ UDP h e a d e r ∗/ 64 128 236 (DHCP FIXED NON UDP + /∗ E v e r y t h i n g but options . ∗/
#define BOOTP MIN LEN
300
#define DHCP MTU MAX
1500
PARTE 5. IMPLANTAR FUNCIONALIDADES #define DHCP MTU MIN
576
#define DHCP MAX OPTION LEN #define DHCP MIN OPTION LEN
(DHCP MTU MAX − DHCP FIXED LEN) (DHCP MTU MIN − DHCP FIXED LEN)
45
struct d h c p p a c k e t { u i n t 8 t op ; /∗ 0 : Message opcode / t y p e ∗/ u i n t 8 t htype ; /∗ 1 : Hardware addr t y p e ( n e t / i f t y p e s . h ) ∗/ u i n t 8 t hlen ; /∗ 2 : Hardware addr l e n g t h ∗/ u i n t 8 t hops ; /∗ 3 : Number o f r e l a y a g e n t hops from c l i e n t ∗/ u i n t 3 2 t xid ; /∗ 4 : T r a n s a c t i o n ID ∗/ u int16 t secs ; /∗ 8 : Seconds s i n c e c l i e n t s t a r t e d l o o k i n g ∗/ u int16 t flags ; /∗ 1 0 : F l a g b i t s ∗/ struct i n a d d r c i a d d r ; /∗ 1 2 : C l i e n t IP a d d r e s s ( i f a l r e a d y i n use ) ∗/ struct i n a d d r y i a d d r ; /∗ 1 6 : C l i e n t IP a d d r e s s ∗/ struct i n a d d r s i a d d r ; /∗ 1 8 : IP a d d r e s s o f n e x t s e r v e r t o t a l k t o ∗/ struct i n a d d r g i a d d r ; /∗ 2 0 : DHCP r e l a y a g e n t IP a d d r e s s ∗/ unsigned char chaddr [ 1 6 ] ; /∗ 2 4 : C l i e n t hardware a d d r e s s ∗/ char sname [DHCP SNAME LEN ] ; /∗ 4 0 : S e r v e r name ∗/ char f i l e [ DHCP FILE LEN ] ; /∗ 1 0 4 : Boot f i l e n a m e ∗/ unsigned char o p t i o n s [ DHCP MAX OPTION LEN ] ; /∗ 2 1 2 : O p t i o n a l p a r a m e t e r s ( a c t u a l l e n g t h d e p e n d e n t on MTU) . ∗/ }; u i n t 3 2 t sequencedhcp = 0 x0000 ; int dhcphase = 0 ;
/∗ C´ o digo f u e n t e de i m p l e m e n t a c i ´ o n de DHCP en n u e s t r o s n i f f e r ∗/
e l s e i f ( h i p −>p r o t o c o l == IPPROTO UDP) { p r i n t f ( ” P r o t o c o l o UDP \n” ) ; h udp = ( struct udphdr ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) + h i p −>i h l ∗4 ) ; p r i n t f ( ” S o u r c e Port : %d\n” , n t o h s ( h udp−>s o u r c e ) ) ; p r i n t f ( ” Dest Port : %d\n” , n t o h s ( h udp−>d e s t ) ) ;
PARTE 5. IMPLANTAR FUNCIONALIDADES
46
i f ( n t o h s ( h udp−>d e s t ) == 67 | | n t o h s ( h udp−>s o u r c e ) == 67 ) { p r i n t f ( ” Mensajes DHCP \n” ) ; dhcp = ( struct d h c p p a c k e t ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) + h i p −>i h l ∗4 + s i z e o f ( struct udphdr ) ) ; p r i n t f ( ”TRANSACTION ID %x \n” , dhcp−>x i d ) ; i f ( dhcp−>op == 1 && sequencedhcp == dhcp−>x i d ) p r i n t f ( ”DHCP REQUEST \n ” ) ; e l s e i f ( dhcp−>op == 1 ) { p r i n t f ( ”DHCP DISCOVER \n” ) ; sequencedhcp = dhcp−>x i d ; p r i n t f ( ” Este e s e l p r o c e s o %x \n” , dhcp−>x i d ) ; } e l s e i f ( dhcp−>op == 2 && dhcphase !=0) { p r i n t f ( ”DHCP ACK \n” ) ; sequencedhcp = 0 x00000000 ; dhcphase = 0 ; } e l s e i f ( dhcp−>op == 2 ) { p r i n t f ( ”DHCP OFFER \n” ) ; dhcphase ++ ; } } return 1 ;
Corriendo el programa sniffer3, y haciendo en otra terminal un dhclient, que como sabemos hace peticiones para encontrar un servidor DHCP, esto para que pueda enviarme par´ametros, para la configuraci´on de la red. Podemos ver la existencia de un transaction ID, que es como un identificador de proceso, que nos permite saber a qu´e ventana o proceso redirigir la salida de la petici´on DHCP, adem´as de permitir como tal tener la secuencia ligada a un proceso, secuencia que consta de (DHCP DISCOVER, DHCP OFFER, DHCP REQUEST, DHCP ACK). root@koitoerdp:~/Tutorial raw-sockets# ./sniffer3 eth0 1000 Sniffer ! ----------------------------------------------Dispositivo arriba [UP] La interfaz de captura es eth0 La MAC de la interfaz es : 00 40 F4 A5 8C 5A La Direcci´ on IP de la interfaz es : 192.168.1.70 La M´ ascara de red de la interfaz es : 255.255.255.0 La direcci´ on de broadcast de la interfaz es : 192.168.1.255 ---------------------------- Paquete Capturado No. 0 ------------
PARTE 5. IMPLANTAR FUNCIONALIDADES Protocolo de red : 08 00 MAC Destino : FF FF FF FF FF FF MAC Origen : 00 40 F4 A5 8C 5A IP Destino: 255.255.255.255 IP Origen : 0.0.0.0 Protocolo UDP Source Port: 68 Dest Port: 67 Mensajes DHCP TRANSACTION ID 395dc602 DHCP DISCOVER Este es el proceso 395dc602 Longitud de datos : 288 Datos : 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 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 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 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 00 00 63 82 53 63 35 01 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 00 00 00 00 00 00 00 00 00 37 00 00
00 00 00 00 00 00 00 00 00 00 07 00 00
00 00 00 00 00 00 00 00 00 00 01 00 00
47
00 00 00 00 00 00 00 00 00 00 1C 00 00
00 00 00 00 00 00 00 00 00 00 02 00 00
00 00 00 00 00 00 00 00 00 00 03 00 00
-------- END Paquete Capturado No. 999 ---------------- Paquete Capturado No. 1 -----------Protocolo de red : 08 00 MAC Destino : FF FF FF FF FF FF MAC Origen : 00 23 51 07 09 B9 IP Destino: 255.255.255.255 IP Origen : 192.168.1.254 Protocolo UDP
40 00 00 00 00 00 00 00 00 00 0F 00 00
F4 00 00 00 00 00 00 00 00 00 06 00 00
A5 00 00 00 00 00 00 00 00 00 0C 00 00
8C 00 00 00 00 00 00 00 00 00 FF 00 00
5A 00 00 00 00 00 00 00 00 00 00 00 00
PARTE 5. IMPLANTAR FUNCIONALIDADES Source Port: 67 Dest Port: 68 Mensajes DHCP TRANSACTION ID 395dc602 DHCP OFFER Longitud de datos : 288 Datos : 00 00 00 00 C0 A8 01 46 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 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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 63 82 53 63 80 3A 04 00 00 A8 C0 3B A8 01 FE 01 04 FF FF FF 00 00
C0 00 00 00 00 00 00 00 00 00 35 04 00
A8 00 00 00 00 00 00 00 00 00 01 00 FF
01 00 00 00 00 00 00 00 00 00 02 01 00
FE 00 00 00 00 00 00 00 00 00 36 27 00
00 00 00 00 00 00 00 00 00 00 04 50 00
00 00 00 00 00 00 00 00 00 00 C0 06 00
48
00 00 00 00 00 00 00 00 00 00 A8 04 00
00 00 00 00 00 00 00 00 00 00 01 C0 00
00 00 00 00 00 00 00 00 00 00 FE A8 00
-------- END Paquete Capturado No. 998 ---------------- Paquete Capturado No. 2 -----------Protocolo de red : 08 00 MAC Destino : FF FF FF FF FF FF MAC Origen : 00 40 F4 A5 8C 5A IP Destino: 255.255.255.255 IP Origen : 0.0.0.0 Protocolo UDP Source Port: 68 Dest Port: 67 Mensajes DHCP TRANSACTION ID 395dc602 DHCP REQUEST Longitud de datos : 288 Datos :
40 00 00 00 00 00 00 00 00 00 33 01 00
F4 00 00 00 00 00 00 00 00 00 04 FE 00
A5 00 00 00 00 00 00 00 00 00 00 03 00
8C 00 00 00 00 00 00 00 00 00 01 04 00
5A 00 00 00 00 00 00 00 00 00 51 C0 00
PARTE 5. IMPLANTAR FUNCIONALIDADES 00 00 00 00 00 00 00 00 00 00 00 46 00 00
00 00 00 00 00 00 00 00 00 00 00 37 00 00
00 00 00 00 00 00 00 00 00 00 00 07 00
00 00 00 00 00 00 00 00 00 00 00 01 00
00 00 00 00 00 00 00 00 00 00 63 1C 00
00 00 00 00 00 00 00 00 00 00 82 02 00
00 00 00 00 00 00 00 00 00 00 53 03 00
00 00 00 00 00 00 00 00 00 00 63 0F 00
00 00 00 00 00 00 00 00 00 00 35 06 00
00 00 00 00 00 00 00 00 00 00 01 0C 00
00 00 00 00 00 00 00 00 00 00 03 FF 00
00 00 00 00 00 00 00 00 00 00 36 00 00
00 00 00 00 00 00 00 00 00 00 04 00 00
00 00 00 00 00 00 00 00 00 00 C0 00 00
49 00 00 00 00 00 00 00 00 00 00 A8 00 00
00 00 00 00 00 00 00 00 00 00 01 00 00
00 00 00 00 00 00 00 00 00 00 FE 00 00
40 00 00 00 00 00 00 00 00 00 32 00 00
F4 00 00 00 00 00 00 00 00 00 04 00 00
A5 00 00 00 00 00 00 00 00 00 C0 00 00
8C 00 00 00 00 00 00 00 00 00 A8 00 00
5A 00 00 00 00 00 00 00 00 00 01 00 00
40 00 00 00 00 00 00
F4 00 00 00 00 00 00
A5 00 00 00 00 00 00
8C 00 00 00 00 00 00
5A 00 00 00 00 00 00
-------- END Paquete Capturado No. 997 ---------------- Paquete Capturado No. 3 Protocolo de red : 08 00 MAC Destino : 00 40 F4 A5 8C 5A MAC Origen : 00 23 51 07 09 B9 IP Destino: 192.168.1.70 IP Origen : 192.168.1.254 Protocolo UDP Source Port: 67 Dest Port: 68 Mensajes DHCP TRANSACTION ID 395dc602 DHCP ACK Longitud de datos : 293 Datos : 00 00 00 00 C0 A8 01 46 C0 A8 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 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 00 00 00 00 00 00 00 00 00 00 00 00 00
------------
FE 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 00 00 00 00 00 00
00 00 00 00 00 00 00
PARTE 5. IMPLANTAR FUNCIONALIDADES
50
Figura 5.2: Ejecucion del sniffer, Protocolo DHCP 00 00 00 00 80 A8 72
00 00 00 00 3A 01 65
00 00 00 00 04 FE 2E
00 00 00 00 00 01 6E
00 00 00 63 00 04 65
00 00 00 82 A8 FF 74
00 00 00 53 C0 FF FF
00 00 00 63 3B FF
00 00 00 35 04 00
00 00 00 01 00 0F
00 00 00 05 01 11
00 00 00 36 27 67
00 00 00 04 50 61
00 00 00 C0 06 74
00 00 00 A8 04 65
00 00 00 01 C0 77
00 00 00 FE A8 61
-------- END Paquete Capturado No. 996 ---------
00 00 00 33 01 79
00 00 00 04 FE 2E
00 00 00 00 03 32
00 00 00 01 04 77
00 00 00 51 C0 69
PARTE 5. IMPLANTAR FUNCIONALIDADES
5.1.4.
51
A˜ nadimos ARP
Por u ´ltimo, como hacer para poder implementar algo que no sea tan est´andar o una modificaci´on nuestra, hay estructuras muy complejas que realmente podemos o no ocuparlas del todo como fue el caso de DHCP, que s´olo manejamos algunos campos para este ejemplo, pero que pasa si no queremos respetar las estructuras est´andar, pues simple y sencillamente recordamos que s´olo tenemos que apuntar al lugar correcto y adem´as rescatar u obtener los datos, con un tipo de dato igual con el cual fueron insertados, para no tener problemas de .agarrar”m´as bytes o no .agarrar”todos los bytes. Por lo que se plantea ahora el caso de ARP, al que le hice una modificaci´on para entender el tr´afico ARP, bas´andonos en el principio que les comento de s´olo saber de que posici´on sacar la informaci´on y que cantidad de informaci´on sacar. /∗ D e f i n i c i o n e s de ARP ∗/ #define IPALEN 4 /∗ Length i n b y t e s o f an IP a d d r e s s ∗/ #define MAXHWALEN 5 /∗ Maximum l e n g t h o f a hardware a d d r e s s ∗/ enum arp hwtype { ARP NETROM=0x0000 , s e n t ) ∗/ ARP ETHER, /∗ ARP EETHER, /∗ ARP AX25 , /∗ ARP PRONET, /∗ ARP CHAOS, /∗ ARP IEEE802 , /∗ ARP ARCNET, ARP APPLETALK };
/∗ Fake f o r NET/ROM ( n e v e r a c t u a l l y Assigned Assigned Assigned Assigned Assigned Who u s e s
t o 10 m e g a b i t E t h e r n e t ∗/ t o e x p e r i m e n t a l E t h e r n e t ∗/ t o AX. 2 5 L e v e l 2 ∗/ t o PROnet t o k e n r i n g ∗/ t o Chaosnet ∗/ t h i s ? ∗/
enum a r p o p c o d e { ARP REQUEST=0x0001 , ARP REPLY, REVARP REQUEST, REVARP REPLY };
struct arp { enum arp hwtype hardware ; /∗ Hardware t y p e ∗/ u int16 t protocol ; /∗ P r o t o c o l t y p e ∗/
PARTE 5. IMPLANTAR FUNCIONALIDADES
52
u i n t 1 6 t hwalen ; /∗ Hardware a d d r e s s l e n g t h , b y t e s ∗/ enum a r p o p c o d e opcode ; /∗ ARP opcode ( r e q u e s t / r e p l y ) ∗/ u i n t 8 t shwaddr [MAXHWALEN] ; /∗ Sender hardware a d d r e s s f i e l d ∗/ };
/∗ Fin de d e f i n i c i o n e s de ARP ∗/ /∗ C´ o digo f u e n t e de i m p l e m e n t a c i ´ o n de ARP en n u e s t r o s n i f f e r ∗/ h e t h e r n e t = ( struct e t h h d r ∗ ) p a c k e t ; i f ( n t o h s ( h e t h e r n e t −>h p r o t o ) == ETH P IP ) { i f ( l e n >= ( s i z e o f ( struct e t h h d r ) + s i z e o f ( struct i p h d r ) ) ) { h i p = ( struct i p h d r ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) ) ; p r i n t f ( ” IP D e s t i n o : %s \n” , ( char ∗ ) i n e t n t o a ( h i p −>daddr ) ) ; p r i n t f ( ” IP Origen : %s \n” , ( char ∗ ) i n e t n t o a ( h i p −>s a d d r ) ) ; } else p r i n t f ( ”HIP : Paquete de tamano i n s u f i c i e n t e \n” ) ; } e l s e i f ( n t o h s ( h e t h e r n e t −>h p r o t o ) == ETH P ARP) { h a r p = ( struct arp ∗ ) ( p a c k e t + s i z e o f ( struct e t h h d r ) ) ; i f ( n t o h s ( h arp−>hardware ) == 0 x0001 ) p r i n t f ( ” \tARP ETHERNET \n” ) ; p r i n t f ( ” \ t S e n d e r MAC ADDRESS : ” ) ; impresionHex ( h arp−>shwaddr −4 ,6) ; p r i n t f ( ” \ t T a r g e t MAC ADDRESS : ” ) ; impresionHex ( h arp−>shwaddr +6 ,6) ; p r i n t f ( ” \ t S e n d e r IP ADDRESS : ” ) ; impresionFormatoIP ( h arp−>shwaddr +2 ,4) ; p r i n t f ( ” \ t T a r g e t IP ADDRESS : ” ) ; impresionFormatoIP ( h arp−>shwaddr +12 ,4) ; } else { p r i n t f ( ” Este no e s un paquete que s e t e n g a c o n o c i m i e n t o \n ” ); p r i n t f ( ” P r o t o c o l o %d ” , n t o h s ( h e t h e r n e t −>h p r o t o ) ) ; }
-------- Paquete Capturado No. 4 -----------Protocolo de red : 08 06 MAC Destino : FF FF FF FF FF FF MAC Origen : 00 23 51 07 09 B9
PARTE 5. IMPLANTAR FUNCIONALIDADES
Figura 5.3: Ejecuci´on del sniffer, Protocolo ARP ARP ETHERNET Sender MAC ADDRESS :00 23 51 07 09 B9 Target MAC ADDRESS :FF FF FF FF FF FF Sender IP ADDRESS :192.168.1.254 Target IP ADDRESS :192.168.1.64 No es un paquete IP -------- END Paquete Capturado No. 995 ---------
53
Parte 6 Conclusi´ on e ideas finales 6.1.
Problemas principales
En este caso es indispensable saber el buen uso de estructuras, arreglos y apuntadores, para entender perfectamente los programas, considero que en la compilaci´on y dem´as no existe ninguna problem´atica a mencionar.
6.2.
Tutoriales futuros
Pues no se, por ahora no tengo idea de cual ser´a el siguiente aunque tengo temas interesante para realizar alg´ un tutorial, podr´ıa ser de JNI para trabajar C con Java, Sockets Seguros en Java o Sockets de C comunicandose con Sockets de Java, o implementaciones de sistemas, o un peque˜ no tuto de ncurses para crear un chat con todo lo aprendido. Pero en fin ya ver´e qu´e se me ocurre, por el momento me retirar´e un poco hasta encontrar un buen tema y arreglar cosas pendientes.
6.3.
Ideas Finales
Se que hay varios sniffers y muy potentes, pero recordando, la idea principal de este tutorial era el c´omo poder programar y usar los sockets crudos. A alguien que desee realizar un sniffer mas complejo, le recomiendo las librer´ıas pcap y/o libnet que tienen muchas funciones que nos permiten brincarnos la
54
´ PARTE 6. CONCLUSION
55
parte tediosa que vimos en este manual, y pasamos r´apidamente a la implementaci´on de aplicaciones con sockets crudos. Espero tambi´en disculpen mis faltas de ortograf´ıa y mi redacci´on, si en alg´ un momento consideran que est´a mal. Cualquier aclaraci´on, duda o comentario me pueden contactar a este correo. (([email protected])) Los c´odigos del tutorial est´an en esta p´agina: http://www.koitoer.com/tutoriales/socketraw.tar.gz Este tutorial fue creado en LATEX.
6.4.
Agradecimientos
Pues ser´ıan para las personas que me hicieron llegar sus comentarios sobre el primer tutorial que hice y para mi marthita querida XD