Banner 1

TCP Timestamp y detección de Spoofing

Antes que nada en este caso entenderemos que se habla de spoofeo de origen (IP Spoofing en la capa IP o mac spoofing en la capa ethernet o ambas...)

Disección de un paquete capturado.

En este caso no nos complicaremos mucho de las demás capas (que no sean la TCP) y nos centraremos principalmente en el campo Options.

Puerto origen (2 bytes) | Puerto destino (2 bytes) | SeqNum (4 bytes) | Acknowledgement (4 bytes) | Tamaño total header (1 byte) | Flags (1 byte) | Window size (2 bytes) | Checksum (2 bytes) | Nulls (2 bytes) | Options (12 bytes) |

De esta forma se estructura un header tcp, pero en este caso únicamente nos centraremos en el campo Options.

Estructura del campo Options:

NOP (1 byte = 0x01) | NOP (1 byte = 0x01) | TimeStamp (8 bytes)|

Dentro del campo de Options de un paquete TCP se puede encontrar un sub-campo (TimeStamp) el cual esta constituido de la siguiente forma:

8 (1 byte)| 10 (1 byte) | TS Value (TSval) (4 bytes) |TS Echo Reply (TSecr) (4 bytes) |

Esto es, el primer valor siempre sera un 8 (8 en hex) y el siguiente 10 (A en hex), y de ahí tenemos dos campos mas: TS Value y TS Echo Reply, el primero se entiende como el valor actual del reloj TCP del servidor que envía dicho paquete, el siguiente (TS Echo Reply) seria el valor del reloj TCP del destino, para esto el paquete tiene que estar respondiendo a otro paquete (ACK) en el cual se especifico dicho valor como TS Value, en caso de que este valor sea invalido se debe enviar como 0.

Bien y ahora que tiene que ver este campo con detección de spoofing?

Pasa que el valor que es enviado cambia de forma constante, puede incluso calcularse en nanosegundos, pero la forma en que este valor cambia varia según el sistema operativo, pero teniendo 2 paquetes del mismo origen se puede medir el retraso y calcular el aumento de este valor (aproximadamente y en la mayoría de los casos), ahora suponiendo que sabemos el valor aproximado que tiene el reloj TCP de una maquina, aunque se cambien campos como son el origen (IP o MAC) si dicho valor no cambia es posible determinar por aproximación de que PC salio dicho paquete únicamente capturando los paquetes.


Ahora vamos a recurrir al sniffer en xs (C++ y perl) que había publicado, pero mejorado para este caso:



view plaincopy to clipboardprint?
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class MyClass {
int raw;
char * interfaz;
int proto;
int buffer;
char * packet_buffer;

public:
MyClass(char * i, int p, int b) {
interfaz = i;
proto = p;
buffer = b;
Makeraw();
BindRaw();
packet_buffer = new char[buffer];
}

~MyClass() {}
void closesocket() {
close(raw);
}

void Makeraw()
{
if((raw = socket(PF_PACKET, SOCK_RAW, htons(proto)))== -1)
{
perror("Imposible crear socket: ");
}
}

int BindRaw()
{

struct sockaddr_ll esqueleto;
struct ifreq ifr;
bzero(&esqueleto, sizeof(esqueleto));
bzero(&ifr, sizeof(ifr));
strncpy((char *)ifr.ifr_name, interfaz, IFNAMSIZ);
if((ioctl(raw, SIOCGIFINDEX, &ifr)) == -1)
{
printf("No se encontro esta interfaz!\n");
return 0;
}
esqueleto.sll_family = AF_PACKET;
esqueleto.sll_ifindex = ifr.ifr_ifindex;
esqueleto.sll_protocol = htons(proto);
if((bind(raw, (struct sockaddr *)&esqueleto, sizeof(esqueleto)))== -1)
{
perror("Imposible poner a la escucha esta interfaz!\n");
return 0;
}
return 1;

}

char * ascii2hex(char * packet,int len)
{
if(!packet)
return 0;
char * buffer = new char[(10 * len)];
if(!buffer)
{
return 0;
}
for (int i = 0; i < len; i++)
{
sprintf(buffer + 9 * i, ",%08x", packet[i]);
}
return buffer;
}

char *leer()
{
/* proto = ETH_P_ALL */
int len;
struct sockaddr_ll packet_info;
int packet_info_size = sizeof(packet_info_size);
if((len = recvfrom(raw, packet_buffer, buffer, 0, (struct sockaddr*)&packet_info, (socklen_t*)&packet_info_size)) == -1)
{
perror("No se pudo leer (-1)!");
return 0;
}
else
{
return ascii2hex(packet_buffer,len);
}
return 0;
}
};

MODULE = Xianur0 PACKAGE = Xianur0

MyClass *
MyClass::new(char * i, int p, int b)

char*
MyClass::leer()

void
MyClass::closesocket()

void
MyClass::DESTROY()




como verán sigue siendo un desastre pero de momento sirve... xD el único cambio que se le hizo es en la función ascii2hex, tenia el problema de que como solo retornaba 2 caracteres del hexadecimal y en caso de que se hiciera acarreo retornaba 0xFF en lugar del valor real del carácter.

en este caso como ya retorna el valor completo toca en perl "corregir" ese valor para hacerlo útil.

Ahora va el núcleo que se encarga de monitorizar los TimeStamps, en este caso lleva registros temporales de los paquetes, pero muchos de esos valores no se utilizan, igualmente lo deje por si lo quieren usar para alguna de sus aplicaciones:


view plaincopy to clipboardprint?
use Xianur0;
use Time::HiRes;
require Exporter;
require DynaLoader;
@ISA = qw(Exporter DynaLoader);
@EXPORT = qw(rpcb_gettime getnetconfigent);
bootstrap Xianur0;
my %promedio = ();
my $start_time = [Time::HiRes::gettimeofday()];
my @packets = ();
my $totalpacks = 0;
my $router = 'xxxxxxxxxxxx';
sub ascii2hex
{
my $str = $_[0];
print $str;
$str =~ s/(.)/sprintf("%02lx", ord $1)/egsm;
return $str;
}

sub iphex_ip {
my $iphex = $_[0];
$iphex =~ s/([a-fA-F0-9]{2})/hex($1)."."/eg;
$iphex =~ s/\.$//g;
return $iphex;
}

sub ethernet {
my $paquete = $_[0];
my $ethernet;
($ethernet,$paquete) = ($paquete =~ /^([\w\d]{28})(.+)/);
return (($ethernet =~ /^([\w\d]{12})([\w\d]{12})([\w\d]{4})/),$paquete);
}

sub ip {
my $paquete = $_[0];
my $ip;
($ip,$paquete) = ($paquete =~ /^([\w\d]{40})(.+)/);
return (($ip =~ /^([\w\d]{2})([\w\d]{2})([\w\d]{4})([\w\d]{4})([\w\d]{4})([\w\d]{2})([\w\d]{2})([\w\d]{4})([\w\d]{8})([\w\d]{8})/),$paquete);
}

sub tcp {
my $paquete = $_[0];
return (($paquete =~ /^([\w\d]{4})([\w\d]{4})([\w\d]{8})([\w\d]{8})([\w\d]{2})([\w\d]{2})([\w\d]{4})([\w\d]{4})([\w\d]{4})([\w\d]{24})(.*)/));
}
while(true) {
my $x = new Xianur0("wlan0",3,20480);
my $contador = 5;
while(($contador--) != 0) {
$paquete = $x->leer();
$paquete =~ s/,[0f]{6}//g;
$paquete =~ s/^,//;
my ($destinomac,$origenmac,$tipo,$paquete) = ethernet($paquete);
if($tipo ne "0800" || $origenmac =~ /$router/i) {$contador++; next;}
my ($versionip,$diffserv,$totallength,$identification,$fragment,$ttl,$protocol,$checksum,$iporg,$ipdst,$paquete) = ip($paquete);
if($protocol ne '06') {$contador++; next;}
my ($srcport,$dstport,$seqnum,$acknowledgement,$hlength,$flags,$window,$checksum,$nulls,$options,$paquete) = tcp($paquete);
my ($nop,$nop,$kind,$dies,$TSval,$TSecr) = ($options =~ /^([\w\d]{2})([\w\d]{2})([\w\d]{2})([\w\d]{2})([\w\d]{8})([\w\d]{8})/);
if($TSval eq "" || $TSecr eq "") {$contador++; next;}
$origenmac =~ s/([\w\d]{2})/$1:/g;
$origenmac =~ s/:$//g;
$destinomac =~ s/([\w\d]{2})/$1:/g;
$destinomac =~ s/:$//g;
my $iporigen = iphex_ip($iporg);
my $ipdestino = iphex_ip($ipdst);
my $time = Time::HiRes::tv_interval($start_time);
my $ts = hex($TSval);
my $difft = $time - $promedio{$iporigen}{'time'};
$packets[$totalpacks]{'time'} = $time;
$packets[$totalpacks]{'ts'} = $ts;
$packets[$totalpacks]{'ip'} = $iporigen;
$packets[$totalpacks]{'mac'} = $origenmac;
$totalpacks++;
if($promedio{$origenmac}{'time'} eq '') {
$promedio{$origenmac}{'time'} = $time;
$promedio{$origenmac}{'ts'} = $ts;
print "\n";
} else {
# print "Diff Time: ".$difft." (aprox.)\n";
my $diffts = $ts - $promedio{$origenmac}{'ts'};
# print "Diff TimeStamp: ".$diffts." (aprox.)\n";
my $clock = $diffts/$difft;
# print "Clock: ".$clock." (aprox.)\n\n";
$promedio{$origenmac}{'clock'} = $clock;
for($z=0; $totalpacks > $z; $z++) {
my $timetmp = $packets[$z]{'time'};
next if($timetmp > $ts || ($packets[$z]{'mac'} eq $origenmac && $packets[$z]{'ip'} eq $iporigen));
# $clock =~ s/\..+//g;
my $tmpts = $packets[$z]{'ts'} + (($time-$temptmp) * $clock);
my $diferencia = $tmpts - $ts;
$diferencia =~ s/^-//;
if(7000 > $diferencia) {
print "[!] Spoofing detectado!\n\tMAC Original: ".$packets[$z]{'mac'}."\n\tMAC Actual: ".$origenmac."\n\tIP Original: ".$packets[$z]{'ip'}."\n\tIP Actual: ".$iporigen."\n";
print "\tOrigen (mac): ".$origenmac."\n\tDestino (mac): ".$destinomac."\n";
print "\tOrigen (ip): ".$iporigen.":".hex($srcport)."\n\tDestino (ip): ".$ipdestino.":".hex($dstport)."\n\tTSval: ".$ts.
"(".$TSval.")\n\tTSecr: ".hex($TSecr)."(".$TSecr.")\n\tTime: ".$time."\n\tClock: ".$clock."\n\n";

}
}
}
}
}
print "Terminamos!\n";


Como podrán apreciar se puede utilizar para un sin fin de cosas...

Fuente: http://hackingtelevision.blogspot.com/2010/12/tcp-timestamp-y-deteccion-de-spoofing.html

No hay comentarios:

Powered by Bad Robot
Helped by Blackubay