Los Caballeros

"Sobre seguridad, programación, modding, frikismo, etc... "

Debugging BoF con Valgrind

Twitter icon Twitter icon
Valgrind es un conjunto de herramientas libres que ayuda en la depuración de problemas de memoria y rendimiento de programas.

Asi lo define wikipedia.

Ahora pues esta tool actúa como una especie de monitor de recursos, es decir por ejemplo cuando detectamos un desborde o un error similar esta tool nos puede ayudar a determinar la naturaleza del mismo (determinar detalles de bug que encontramos por pura suerte xD), así que comencemos:

para comenzar entre las opciones que utilizaremos del valgrind están:

--log-file=<file> log messages to <file> (tal cual, crea un log de la ejecución a un archivo)
--log-socket=ipaddr:port log messages to socket ipaddr:port (lo mandamos por un socket tcp)

Del mismo modo se pueden crear logs xml's para poder leerlos mas fácilmente con algún parser (o programar nuestro propia tool para analizar dichos "eventos").

--leak-check=full (establecemos el nivel de "leaks" que se van a comprobar, en este caso nos interesan todos :P...)

Bien ahora comencemos:

xianur0@Zer0-Null:~$ valgrind --log-file=log.txt --leak-check=full -v gtmess

de este modo vamos a generar un reporte del gtmess, se inicia la aplicación y ahora nos toca causar el BoF manualmente, en este caso vamos a intentar conectarnos con un usuario de 512 de largo sin @, para ver que pasa...

y al obtener el desborde, vamos a ver un poco del que paso, en este caso no nos vamos a guiar del stacktrace que nos devolverá la aplicación, vamos a analizar los logs (ya que nos facilitan un tanto la vida...)


==11520== Memcheck, a memory error detector
==11520== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==11520== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==11520== Command: gtmess
==11520== Parent PID: 11373
==11520==
--11520--
--11520-- Valgrind options:
--11520-- --suppressions=/usr/lib/valgrind/debian-libc6-dbg.supp
--11520-- --log-file=log.txt
--11520-- --leak-check=full
--11520-- -v
--11520-- Contents of /proc/version:
--11520-- Linux version 2.6.32-26-generic (buildd@rothera) (gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) ) #48-Ubuntu SMP Wed Nov 24 09:00:03 UTC 2010
--11520-- Arch and hwcaps: X86, x86-sse1-sse2
--11520-- Page sizes: currently 4096, max supported 4096
--11520-- Valgrind library directory: /usr/lib/valgrind
--11520-- Reading syms from /lib/ld-2.11.1.so (0x4000000)
--11520-- Reading debug info from /lib/ld-2.11.1.so ..
--11520-- .. CRC mismatch (computed d005eb74 wanted 53dc8daf)
--11520-- Reading debug info from /usr/lib/debug/lib/ld-2.11.1.so ..
--11520-- Reading syms from /usr/local/bin/gtmess (0x8048000)
--11520-- Reading syms from /usr/lib/valgrind/memcheck-x86-linux (0x38000000)
--11520-- object doesn't have a dynamic symbol table
--11520-- Reading suppressions file: /usr/lib/valgrind/debian-libc6-dbg.supp
--11520-- Reading suppressions file: /usr/lib/valgrind/default.supp
--11520-- REDIR: 0x40160b0 (index) redirected to 0x3803e9b3 (vgPlain_x86_linux_REDIR_FOR_index)
--11520-- Reading syms from /usr/lib/valgrind/vgpreload_core-x86-linux.so (0x401f000)
--11520-- Reading syms from /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so (0x4022000)
==11520== WARNING: new redirection conflicts with existing -- ignoring it
--11520-- new: 0x040160b0 (index ) R-> 0x04025c30 index
--11520-- REDIR: 0x4016290 (strlen) redirected to 0x4026070 (strlen)
--11520-- Reading syms from /lib/i686/cmov/libssl.so.0.9.8 (0x4043000)
--11520-- Reading debug info from /lib/i686/cmov/libssl.so.0.9.8 ..
--11520-- .. CRC mismatch (computed 7b8b88b0 wanted b921d0c8)
--11520-- object doesn't have a symbol table
--11520-- Reading syms from /lib/i686/cmov/libcrypto.so.0.9.8 (0x408c000)
--11520-- Reading debug info from /lib/i686/cmov/libcrypto.so.0.9.8 ..
--11520-- .. CRC mismatch (computed 85170666 wanted 720fbd0f)
--11520-- object doesn't have a symbol table
--11520-- Reading syms from /lib/libncurses.so.5.7 (0x41de000)
--11520-- Reading debug info from /lib/libncurses.so.5.7 ..
--11520-- .. CRC mismatch (computed 99b3a921 wanted 788a2112)
--11520-- object doesn't have a symbol table
--11520-- Reading syms from /lib/tls/i686/cmov/libpthread-2.11.1.so (0x4216000)
--11520-- Reading debug info from /lib/tls/i686/cmov/libpthread-2.11.1.so ..
--11520-- .. CRC mismatch (computed 38da17dd wanted d3835c81)
--11520-- Reading debug info from /usr/lib/debug/lib/tls/i686/cmov/libpthread-2.11.1.so ..
--11520-- Reading syms from /lib/tls/i686/cmov/libc-2.11.1.so (0x422f000)
--11520-- Reading debug info from /lib/tls/i686/cmov/libc-2.11.1.so ..
--11520-- .. CRC mismatch (computed 0893b039 wanted f05c11b3)
--11520-- Reading debug info from /usr/lib/debug/lib/tls/i686/cmov/libc-2.11.1.so ..
--11520-- Reading syms from /lib/tls/i686/cmov/libdl-2.11.1.so (0x4389000)
--11520-- Reading debug info from /lib/tls/i686/cmov/libdl-2.11.1.so ..
--11520-- .. CRC mismatch (computed 6be1e729 wanted de5b14b0)
--11520-- Reading debug info from /usr/lib/debug/lib/tls/i686/cmov/libdl-2.11.1.so ..
--11520-- Reading syms from /lib/libz.so.1.2.3.3 (0x438e000)
--11520-- Reading debug info from /lib/libz.so.1.2.3.3 ..
--11520-- .. CRC mismatch (computed 53909dc3 wanted dc0e37c9)
--11520-- object doesn't have a symbol table
--11520-- REDIR: 0x42a2140 (strcmp) redirected to 0x401f44c (_vgnU_ifunc_wrapper)
--11520-- REDIR: 0x42a1fd0 (index) redirected to 0x4025ba0 (index)
--11520-- REDIR: 0x42a33a0 (memchr) redirected to 0x40267b0 (memchr)
--11520-- REDIR: 0x42a2b10 (rindex) redirected to 0x4025ae0 (rindex)
--11520-- REDIR: 0x42a27f0 (__GI_strlen) redirected to 0x4026050 (__GI_strlen)
--11520-- REDIR: 0x42a52b0 (strchrnul) redirected to 0x4027510 (strchrnul)
--11520-- REDIR: 0x42a8e00 (__GI_strncmp) redirected to 0x40265c0 (__GI_strncmp)
--11520-- REDIR: 0x42a2a30 (strncpy) redirected to 0x4026270 (strncpy)
--11520-- REDIR: 0x429ef40 (malloc) redirected to 0x4024e9b (malloc)
--11520-- REDIR: 0x42a3f20 (memcpy) redirected to 0x401f44c (_vgnU_ifunc_wrapper)
--11520-- REDIR: 0x433f000 (__memcpy_ssse3) redirected to 0x40267f0 (memcpy)
--11520-- REDIR: 0x429ee60 (free) redirected to 0x4024ab5 (free)
--11520-- REDIR: 0x42a2190 (__GI_strcmp) redirected to 0x4026690 (__GI_strcmp)
--11520-- REDIR: 0x429fec0 (realloc) redirected to 0x4024f4a (realloc)
--11520-- REDIR: 0x42a28b0 (strnlen) redirected to 0x4025fb0 (strnlen)
--11520-- REDIR: 0x42a3c20 (stpcpy) redirected to 0x40270a0 (stpcpy)
--11520-- REDIR: 0x42a2200 (strcpy) redirected to 0x40260b0 (strcpy)
--11520-- REDIR: 0x42a51e0 (rawmemchr) redirected to 0x4027540 (rawmemchr)
--11520-- REDIR: 0x42a2730 (strlen) redirected to 0x401f44c (_vgnU_ifunc_wrapper)
--11520-- REDIR: 0x42a2770 (__strlen_sse2) redirected to 0x4026030 (strlen)
--11520-- REDIR: 0x429e660 (calloc) redirected to 0x402417f (calloc)
--11520-- REDIR: 0x4347240 (__strcmp_ssse3) redirected to 0x4026630 (strcmp)
--11520-- REDIR: 0x42a29e0 (strncmp) redirected to 0x401f44c (_vgnU_ifunc_wrapper)
--11520-- REDIR: 0x43486b0 (__strncmp_ssse3) redirected to 0x4026550 (strncmp)
--11520-- REDIR: 0x42a3930 (memset) redirected to 0x401f44c (_vgnU_ifunc_wrapper)
--11520-- REDIR: 0x433def0 (__memset_sse2) redirected to 0x4027420 (memset)
--11520-- Reading syms from /lib/libgcc_s.so.1 (0x57fe000)
--11520-- Reading debug info from /lib/libgcc_s.so.1 ..
--11520-- .. CRC mismatch (computed 75b2cc22 wanted fffc9534)
--11520-- object doesn't have a symbol table
==11520==
==11520== Process terminating with default action of signal 6 (SIGABRT)
==11520== at 0x4259651: raise (raise.c:64)
==11520== by 0x425CA81: abort (abort.c:92)
==11520== by 0x429049C: __libc_message (libc_fatal.c:189)
==11520== by 0x431138F: __fortify_fail (fortify_fail.c:32)
==11520== by 0x43102C9: __chk_fail (chk_fail.c:29)
==11520== by 0x430F5F9: __strcat_chk (strcat_chk.c:51)
==11520== by 0x804EDEB: log_in (string3.h:146)
==11520== by 0x8051D7C: main (gtmess.c:2589)
--11520-- Discarding syms at 0x5800370-0x5818738 in /lib/libgcc_s.so.1 due to munmap()
==11520==
==11520== HEAP SUMMARY:
==11520== in use at exit: 497,443 bytes in 8,777 blocks
==11520== total heap usage: 11,671 allocs, 2,894 frees, 889,703 bytes allocated
==11520==
==11520== Searching for pointers to 8,777 not-freed blocks
==11520== Checked 17,412,980 bytes
==11520==
==11520== 136 bytes in 1 blocks are possibly lost in loss record 190 of 306
==11520== at 0x402425F: calloc (vg_replace_malloc.c:467)
==11520== by 0x4010CDB: _dl_allocate_tls (dl-tls.c:300)
==11520== by 0x421C2E2: pthread_create@@GLIBC_2.1 (allocatestack.c:561)
==11520== by 0x8050C2D: interval_init (gtmess.c:423)
==11520== by 0x8051736: main (gtmess.c:2492)
==11520==
==11520== 136 bytes in 1 blocks are possibly lost in loss record 191 of 306
==11520== at 0x402425F: calloc (vg_replace_malloc.c:467)
==11520== by 0x4010CDB: _dl_allocate_tls (dl-tls.c:300)
==11520== by 0x421C2E2: pthread_create@@GLIBC_2.1 (allocatestack.c:561)
==11520== by 0x8063707: msnftp_init (xfer.c:740)
==11520== by 0x805173B: main (gtmess.c:2493)
==11520==
==11520== LEAK SUMMARY:
==11520== definitely lost: 0 bytes in 0 blocks
==11520== indirectly lost: 0 bytes in 0 blocks
==11520== possibly lost: 272 bytes in 2 blocks
==11520== still reachable: 497,171 bytes in 8,775 blocks
==11520== suppressed: 0 bytes in 0 blocks
==11520== Reachable blocks (those to which a pointer was found) are not shown.
==11520== To see them, rerun with: --leak-check=full --show-reachable=yes
==11520==
==11520== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 27 from 10)
--11520--
--11520-- used_suppression: 27 dl-hack3-cond-1
==11520==
==11520== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 27 from 10)


podremos ver que se hacen algunas cosas con memoria y demás, pero en este momento la parte que nos interesa es la siguiente:

==11520==
==11520== Process terminating with default action of signal 6 (SIGABRT)
==11520== at 0x4259651: raise (raise.c:64)
==11520== by 0x425CA81: abort (abort.c:92)
==11520== by 0x429049C: __libc_message (libc_fatal.c:189)
==11520== by 0x431138F: __fortify_fail (fortify_fail.c:32)
==11520== by 0x43102C9: __chk_fail (chk_fail.c:29)
==11520== by 0x430F5F9: __strcat_chk (strcat_chk.c:51)
==11520== by 0x804EDEB: log_in (string3.h:146)
==11520== by 0x8051D7C: main (gtmess.c:2589)

vamos a ir analizando de abajo hacia arriba, aunque primero que nada hay que denotar que la aplicación termino con "signal 6" (SIGABRT), esto es la aplicación que ejecutamos con valgrind (gtmess) lo cual a simple vista nos esta diciendo que hubo un desborde y que se necesito abortar la aplicación, pero despues miramos lo siguiente:

==11520== by 0x8051D7C: main (gtmess.c:2589)

se cargo el main de gtmess.c y se llamo a algo en la linea 2589

==11520== by 0x804EDEB: log_in (string3.h:146)

ese algo que se llamo es log_in():

                            log_in(0);

vayamos a log_in() que se encuentra en la linea 2071, de esto podemos notar que se hizo algo con un string (puesto que nos esta marcado que llamo a string3.h linea 146).

Para entender un poco mas de que se hizo vamos a ese archivo y a esa linea, tenemos lo siguiente:

__extern_always_inline char *
__NTH (strcat (char *__restrict __dest, __const char *__restrict __src))
{
return __builtin___strcat_chk (__dest, __src, __bos (__dest));
}

que tal cual es lo que nos dijo valgrind arriba:

==11520== by 0x430F5F9: __strcat_chk (strcat_chk.c:51)

es decir se llamo a la función strcat(), y en esta parte hubo un error por que se llamo a:

==11520== by 0x43102C9: __chk_fail (chk_fail.c:29)

tenemos que ahí estuvo el desborde, ahora regresemos a gtmess.c linea 2071:

int log_in(int startup)
{
int r, retry;
if (msn.nfd != -1) {
msg(C_ERR, "You are already logged in\n");
return 0;
}
if (startup) {
if (!msn.login[0]) return 0;
} else {
if (!(r = get_string(C_EBX, 0, "Login as: ", msn.login, SML))) return 0;
if (r == 1) {
if (strchr(msn.login, '@') == NULL) strcat(msn.login, "@hotmail.com");
Strcpy(msn.nick, msn.login, SML);
msn.pass[0] = 0;
draw_status(1);
}
}
if (startup) {
if (!msn.pass[0]) return 0;
} else if (!get_string(C_EBX, 1, "Password: ", msn.pass, SML)) return 0;
msg2(C_MNU, "Logging in ...");

retry = Config.max_retries;
while (retry >= 0) {
while ((r = do_login()) == 1);
if (r == 0) return 0;
msn.nfd = -1;

msg(C_ERR, "Failed to connect to server\n");
if (r == -400) break; /* do not retry when passport authentication fails */
if (retry) msg(C_ERR, "Retrying %d more time%s ...\n", retry, (retry > 1)? "s": ZS);
--retry;
}
return -1;
}


ya que ubicamos aproximadamente que es lo que causo el desborde nos toca detectar exactamente en que linea se causo el desborde con strcat(), localicemos todos los strcat(), en este caso no deseo complicar mucho las cosas de modo que solo veremos lo simple, así que queda ir haciendo un "mapeo de ejecución" para ver que se ejecuto y donde se detuvo, para esto realmente nos bastaría con llenar de printf() e ir imprimiendo según se vayan ejecutando las cosas, en mi caso quedo algo como esto:

Code:
int log_in(int startup)
{
int r, retry;
if (msn.nfd != -1) {
msg(C_ERR, "You are already logged in\n");
return 0;
}
if (startup) {
if (!msn.login[0]) return 0;
} else {
if (!(r = get_string(C_EBX, 0, "Login as: ", msn.login, SML))) return 0;
if (r == 1) {
printf("en la linea 2083\n");
if (strchr(msn.login, '@') == NULL) strcat(msn.login, "@hotmail.com");
printf("en la linea 2085\n");
Strcpy(msn.nick, msn.login, SML);
printf("en la linea 2087\n");
msn.pass[0] = 0;
draw_status(1);
}
}
if (startup) {
if (!msn.pass[0]) return 0;
} else if (!get_string(C_EBX, 1, "Password: ", msn.pass, SML)) return 0;
msg2(C_MNU, "Logging in ...");

retry = Config.max_retries;
while (retry >= 0) {
while ((r = do_login()) == 1);
if (r == 0) return 0;
msn.nfd = -1;

msg(C_ERR, "Failed to connect to server\n");
if (r == -400) break; /* do not retry when passport authentication fails */
if (retry) msg(C_ERR, "Retrying %d more time%s ...\n", retry, (retry > 1)? "s": ZS);
--retry;
}
return -1;
}

compilamos y volvemos a ejecutar, ya no necesitamos a valgrind, únicamente veremos que es lo que nos retorna en la terminal:

en la linea 2083
Terminado (killed)
xianur0@Zer0-Null:~$

así que lo ultimo fue la linea 2083, vayamos a esa linea:

y nos encontramos con:

            if (strchr(msn.login, '@') == NULL) strcat(msn.login, "@hotmail.com");

ya encontramos exactamente donde fue el BoF, es decir únicamente tenemos que buscar de cuanto es msn.login (la cual es una msn_t):


src/client/nserver.h:29:


Code:
typedef struct {
/* must be set by user */
char login[SML], pass[SML];
char notaddr[SML];

/* personal state */
char nick[SML];
char psm[SML];
msn_stat_t status;
int inbox, folders;
/* privacy mode */
char BLP; /* all other users: (A)llow; (B)lock */
char GTC; /* prompt when other users add you: (A)lways; (N)ever */
/* lists */
msn_glist_t GL; /* group list */
msn_clist_t CL; /* contact list (forward, reverse, allow, block) */

char hlogin[SML]; /* highlighted contact in CL */
char hgid[SNL]; /* highlighted group in CL */
int dhid; /* delta pos. of highlighted contact */

/*msn_clist_t IL; /* initial status list */
/* unsigned int SYN; /* syn list version */
int list_count; /* number of LST responses */

int flskip; /* FL list line skip (for display) */
pthread_mutex_t lock;

FILE *fp_log; /* log file pointer */
char fn_log[SML]; /* log file name */


/* session */
unsigned int tid;
int nfd;
int in_syn; /* SYN in progress */
pthread_t thrid;
} msn_t;

tenemos que el campo login tiene de tamaño SML:

src/client/msn.h:30:

#define SML 512

es decir 512, y listo, ya tenemos ubicado y "analizado" el bug.

Saludos!

BOF gtmess <= 0.96

Twitter icon Twitter icon
src/client/msn.h:30:


#define SML 512


src/client/nserver.h:29:


typedef struct {
/* must be set by user */
char login[SML], pass[SML];
char notaddr[SML];

/* personal state */
char nick[SML];
char psm[SML];
msn_stat_t status;
int inbox, folders;
/* privacy mode */
char BLP; /* all other users: (A)llow; (B)lock */
char GTC; /* prompt when other users add you: (A)lways; (N)ever */
/* lists */
msn_glist_t GL; /* group list */
msn_clist_t CL; /* contact list (forward, reverse, allow, block) */

char hlogin[SML]; /* highlighted contact in CL */
char hgid[SNL]; /* highlighted group in CL */
int dhid; /* delta pos. of highlighted contact */

/*msn_clist_t IL; /* initial status list */
/* unsigned int SYN; /* syn list version */
int list_count; /* number of LST responses */

int flskip; /* FL list line skip (for display) */
pthread_mutex_t lock;

FILE *fp_log; /* log file pointer */
char fn_log[SML]; /* log file name */


/* session */
unsigned int tid;
int nfd;
int in_syn; /* SYN in progress */
pthread_t thrid;
} msn_t;


Largo máximo del usuario reservado: 512


src/client/gtmess.c:2081:

        if (!(r = get_string(C_EBX, 0, "Login as: ", msn.login, SML))) return 0;
if (r == 1) {
if (strchr(msn.login, '@') == NULL) strcat(msn.login, "@hotmail.com");
Strcpy(msn.nick, msn.login, SML);
msn.pass[0] = 0;
draw_status(1);
}



que básicamente seria, colocar 512 caracteres (sin @), el sistema los leerá, pero al llegar a esta ultima parte se concatenaría "@hotmail.com" (12 bytes) y eso causaría el desborde.

Nota: bug inicialmente observado por "HacKeRsr", analizado y explotado por Xianur0.

TCP Timestamp y detección de Spoofing

Twitter icon Twitter icon
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:



#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <features.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/ip.h>
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:


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 podran apresiar se puede utilizar para un sin fin de cosas...

[FHTTP] Proxy Evasor (ofuscador)

Twitter icon Twitter icon
FHTTP es un kit de pentesting completamente enfocado al protocolo HTTP, es decir, únicamente trabaja utilizando el protocolo HTTP, entre las cosas que implementa esta un proxy (obviamente HTTP) el cual esta enfocado al análisis de los IDS (en este caso: análisis = evasión), pero también nos da una gran cantidad de facilidades para atacar básicamente cualquier cosa que soporte HTTP, esto actuando como un proxy y modificando el trafico que recibe, les daré un ejemplo de las posibilidades que nos da esta herramienta:

Eliminación del SSL (HTTPS), a diferencia de las herramientas publicadas para "romper" el SSL, esta herramienta actúa como proxy editando los links (cambiando el https por http) y agregando un parámetro al final, esto con la finalidad de reconocer en futuras consultas una que tiene que ir por HTTPS de una HTTP, es decir repite la consulta HTTP pasándola por HTTPS (de modo que del navegador a nosotros el trafico va sin cifrado), no es una técnica del todo eficiente pero funciona...

Evasión de portales cautivos, esto es los métodos que utiliza para despistar a los IDS también son validos en gran cantidad de casos contra portales cautivos.

Reglas de evasión y modificación, igual que los IDS tienen reglas para detectar ataques, esta herramienta tiene reglas para diseñar evasiones (o ataques en concreto).

Bueno estas son algunas de las cosas que nos permite hacer esta herramienta, ahora pasemos a lo interesante, el uso...

Esta herramienta se libero con 2 interfaces, de terminal y GTK+, pero realmente la interfaz es tan simple que dudo que necesite muchas explicaciones....

Vamos a ver un poco eso de las reglas de evasión, con el paquete ya se incluyen algunas reglas (inclusive 4 que son de otro modulo, pero se las dejo para que se hagan una idea :P....)

[donde]: [que] => [por que] [<!-- comentario] es decir, donde seria en que parte del paquete HTTP se va a editar, de momento únicamente tenemos los siguientes "dondes":
  • url
  • todo
  • cabeceras
  • postdata



El "que" seria una cadena (compatible con regex) que indicaría el patrón a remplazar, igual que en las regex de perl tenemos lo siguiente:

todo: ^GET(\s|\t)+ => POST $1 <!-- GET a POST


En este caso remplazaríamos en todo el paquete (esto por que la linea inicial se toma como en la sección de "todo") las lineas que comienzen con GET, tengan espacios o tabulaciones por GET utilizando los mismos separadores que se encontraron ($1), en este caso siempre que vayamos a usar esta clase de valores se tiene que colocar un espacio antes. Y bueno para dejar claro lo que hace esta regla es pasar por POST todas las GET (obviamente no mueve los parámetros GET a POST, únicamente cambia el método).

Nivel 0, solo actúa de proxy (y si le activaste desactivar SSL entonces lo desactiva).

Nivel 1, Se codifican los parámetros en url encode (parámetros de POST).

Nivel 2, Se remplazan los separadores por algun caracter establecido en la variable $ch y se codifican todos los parámetros (GET y POST) y nombres de directorios y archivos con url encode.

Nivel 3, Adicional se utiliza HTTP Request Smuggling.

En resumen es eso...

Ahora finalmente después de esta "pequeña" introducción al funcionamiento de esta herramienta, se las regalo:

https://sourceforge.net/projects/fhttp/files/Evasor.tar.gz/download

dentro van las 2 versiones, la gráfica y la de terminal.


Saludos, cualquier contribución al proyecto es bien recibido.

Técnicas de evasión de "portales cautivos" Cap. 1.

Twitter icon Twitter icon
lcAquí xianur0 de nueva cuenta, el día de hoy vamos a ver un poco sobre como pasar esos portales cautivos que nos separan casi siempre de internet gratis y un limite a ciertos dominios, pasa lo siguiente jugando con el celular se puede notar que cuando no tenemos saldo salta el portal cautivo, la idea es que el portal cautivo esta redireccionado por un proxy, el cual solo va a filtrar ciertos dominios, y al ser un proxy HTTP únicamente va a filtrar paginas HTTP (No HTTPS ni ningún otro protocolo), por lo cual si abrimos una pagina HTTPS esta nos abrirá sin ningún problema, a todo eso se puede utilizar una VPN (por ejemplo HotSpot Shield) y tendremos libre el acceso a internet.

Esto en un ejemplo con un celular, pero también otras empresas utilizan estos portales cautivos y estos proxys HTTP, se supone como mencionamos que solo van a filtrar ciertos dominios, pero obviamente no el del portal cautivo, por lo cual esta el metodo 1:


1. Bypass por el header host:
Creamos un header Host apuntando al host que esta permitido por el proxy del proveedor, pondré un ejemplo:

Host: permitido

y seguido de este el header Host real de la web que queremos visitar, en este caso el proxy nos deja pasar como si nada pues no tiene por que filtrar este Host, de modo que programamos un proxy HTTP que agregue dicho header y mágicamente tenemos internet libre.


Al ser un proxy HTTP tiene las clásicas deficiencias del protocolo HTTP, por ejemplo en la mayoría de los casos se tiene el desconocimiento total de que existe la versión 0.9 y de que los servidores web no solo soportan espacios como separadores, por lo cual el metodo 2:

2. HTTP/0.9 y separadores diferentes del espacio:

Solo filtra los paquetes HTTP con formato:

[metodo] [ruta] HTTP/[version]

de modo que los paquetes que se envían con diferente separador y los de la version 0.9 se dejan pasar.

3. No filtra las paginas encriptadas, solo HTTP.

Como ya se menciono no se filtran webs HTTPS ni similares, por lo cual cualquiera de estas se pueden navegar fácilmente.

4. El puerto DNS no esta filtrado, de modo que se pueden crear tunel con otro servidor remoto (que actuaria de proxy).


Nuevamente recurrimos a las deficiencias de los proxys y de su pobre implementación del protocolo HTTP, ahora juguemos con las conexiones persistentes:

5. En conexiones persistentes, se puede enviar un paquete inicial de tipo:

GET / HTTP/1.1
Host: hostpermitido
Connection: keep-alive

el proxy dejara de vigilar esta conexión y ya se puede enviar paquetes limpiamente (cambiando el Host obviamente).

6. Otro dato curioso es que si se puede forzar al navegador a hacer un HTTP Request Smuggling, se puede enviar 2 paquetes con diferentes encabezados Host y obtener las respuestas de los diferentes servidores en la misma conexión, por lo cual se puede hacer fácilmente un robo de cookies del dominio cualquiera.

No he podido probar con otros proveedores pero de momento tenemos esos, un dato curioso es que el 0day que se había colocado como recompensa del primer reto de este blog ya tenia los métodos de evasión mencionados.

Pero creo que como motivo de esta publicación vale la pena regalarles el proxy, así que en la siguiente publicación hablare de esta herramienta y se las regalare ;)...