GNU/Linux Exploiting
Introducción a la explotación de binarios
GNU/Linux Exploiting 2
• Manuel Blanco Parajón
• Jugador habitual de competiciones “CTF”
• w0pr
• ID-10-T
• Estudiante de Ingeniería Informática
• Autodidacta
# whoami
@manuelbp01
manuelbp01@gmail.com
GNU/Linux Exploiting 3
• ¿Qué vamos a ver en este taller?
Introducción a la explotación de vulnerabilidades en software
• Requisitos recomendados
• Nivel básico de programación en C
• Manejo sencillo de la shell GNU/Linux
• Conocimientos básicos de Ingeniería Inversa
• Fundamentos de Computadores
• Resultados
Ser capaz de desarrollar tu primer exploit
Introducción
GNU/Linux Exploiting 4
Motivación
GNU/Linux Exploiting 5
• Bug: Error de software o fallo de programación que causa un
comportamiento anómalo o desencadena un resultado inesperado en la
aplicación.
• Vulnerabilidad: Clase particular de bug que puede ser aprovechado por
un atacante para comprometer la seguridad, integridad, disponibilidad y
confidencialidad de un sistema.
• Exploit: Fragmento de software utilizado para aprovechar una
vulnerabilidad de un sistema, con el fin de conseguir un comportamiento
no deseado para el mismo.
• Payload: Efecto que se desea lograr al explotar una vulnerabilidad.
Términos
GNU/Linux Exploiting 6
• Ingeniería Inversa: Proceso llevado a cabo con el objetivo de obtener
información a partir de un producto final.
• Análisis estático
• Análisis dinámico
Ingeniería Inversa
GNU/Linux Exploiting 7
• Análisis estático: Tipo de análisis de software que se realiza sin ejecutar
el programa.
• Ejemplo: Podemos utilizar objdump como un desensamblador
(traduce código máquina a ensamblador)
Ingeniería Inversa
GNU/Linux Exploiting 8
• Análisis dinámico: Tipo de análisis de software que se realiza
ejecutando el programa.
• Ejemplo
• strace: Permite monitorear las llamadas al sistema y las señales.
• ltrace: Permite monitorear las llamadas a las librerías compartidas.
Ingeniería Inversa
GNU/Linux Exploiting 9
• IDA 7.0 Freeware Version
https://www.hex-rays.com/products/ida/support/download_freeware.shtml
Herramientas útiles
GNU/Linux Exploiting 10
• radare2
https://github.com/radare/radare2
Herramientas útiles
GNU/Linux Exploiting 11
• GDB (GNU Debugger)
Herramientas útiles
GNU/Linux Exploiting 12
• PEDA (Python Exploit Development Assistance for GDB)
https://github.com/longld/peda
Herramientas útiles
GNU/Linux Exploiting 13
• Los depuradores son muy útiles!!
Primer ejercicio
GNU/Linux Exploiting 14
• Estructuras de datos (tablas) que muestran la distribución de la
memoria
Mapa de memoria
GNU/Linux Exploiting 15
• Segmentación de memoria: División de la memoria primaria en segmentos
o secciones
• Los segmentos normalmente corresponden a las divisiones naturales de un
programa, como las rutinas o las tablas de datos.
• data: rw-
• code: r-x
• stack: rw-
• heap: rw-
Segmentación de memoria
GNU/Linux Exploiting 16
• ¿Qué sucede cuando ejecutas un archivo ELF?
• $ ./test
• Normalmente el programa estará en el disco, y el kernel será el encargado de
realizar una serie de procedimientos para el mapeo de la memoria del
programa.
Flujo de ejecución
GNU/Linux Exploiting 17
Flujo de ejecución
./test
fork()
execve(“./test”, *argv[], *envp[])
sys_execve()
do_execve() search_binary_handler()
load_elf_binary()
ld.so
_start
__libc_start_main _init
main
user mode
kernel mode
GNU/Linux Exploiting 18
Cómo se realiza el mapeo del programa a la memoria virtual
• En el encabezado del programa
• Se guardan qué segmentos se deben mapear y sus respectivas
ubicaciones
• También se guarda qué secciones pertenecen a qué segmentos
• Durante el mapeo la memoria se dividirá en distintos segmentos
dependiendo de sus respectivos permisos
• Un segmento puede contener 0 o varias secciones
Flujo de ejecución
GNU/Linux Exploiting 19
Cómo se realiza el mapeo del programa a la memoria virtual
Flujo de ejecución
GNU/Linux Exploiting 20
Cómo se realiza el mapeo del programa a la memoria virtual
Flujo de ejecución
otra sección
.data
.bss
.got.plt
.rodata
.text
.init
ELF encabezado
RW
R o RX
kernel space
DATA VMA
CODE VMA
stack
heap
En disco En memoria
GNU/Linux Exploiting 21
Registros
• Registros de propósito general
• EAX EBX ECX EDX – 32 bit
• AX BX CX DX – 16 bit
• AH BH CH DH – 8 bit (parte alta)
• AL BL CL DL – 8 bit (parte baja)
Ensamblador x86
AH AL
EAX
AX
GNU/Linux Exploiting 22
Registros
• Stack Pointer
• ESP – 32 bit
• Apunta a la cima de la pila
• Base Pointer
• EBP – 32 bit
• Apunta a la base de la pila
• La pila es una estructura de datos (cola LIFO) que permite almacenar y
recuperar datos
Ensamblador x86
GNU/Linux Exploiting 23
EBP: 0xffffcfd8
0x804871c
???
???
0x804871c
???
???
0xffffcfd8
Funcionamiento CPU
Prólogo de la función
Llamada a get_flag
RET addr
RET addr
Frame pointer
* La representación real de la pila sería al revés
GNU/Linux Exploiting 24
0x804871c
???
???
0xffffcfd8
???
???
Funcionamiento CPU
???
???
???
Stack Frame
Marco de pila: Estructura de datos que contienen la información de estado de la
subrutina, son utilizados para almacenar variables locales y cálculos.
GNU/Linux Exploiting 25
Funcionamiento CPU
Epílogo de la función
0x804871c
???
???
0xffffcfd8
0x804871c
???
???
0x804871c
???
0xffffcfd8
???
GNU/Linux Exploiting 26
Registros
• Registro contador del programa
• EIP
• Apunta a la siguiente instrucción a ejecutar
• Registro flag
• eflags
• Almacena los resultados de ejecución
• Registro de segmento
• cs ss ds es fs gs
Ensamblador x86
GNU/Linux Exploiting 27
Buffer: Espacio de memoria reservado para almacenar datos de
manera temporal.
Si se introducen más datos que los que el buffer puede almacenar,
entonces se produce un desbordamiento.
Buffer Overflow
GNU/Linux Exploiting 28
Stack Smash
gcc -fno-stack-protector stack-smash.c –o stack-smash
GNU/Linux Exploiting 29
Stack Smash
buffer (64 bytes)
variable
EBP
RET
argc
argv
envp
variable
EBP
RET
argc
argv
envp
A AA A
A A A A
A … … …
buffer (64 bytes)
AAA
A A A …
…
A A A A
Recordemos que la pila crece desde las
direcciones altas hacia las bajas, la
representación real sería al revés.
GNU/Linux Exploiting 30
Stack Smash
• r <<< $(python -c 'print "A" * 64 + "B" * 4')
GNU/Linux Exploiting 31
Stack Smash
• r <<< $(python -c 'print "A" * 64 + "xefxbexadxde"')
GNU/Linux Exploiting 32
Stack Smash
El buffer podía almacenar 64 bytes, lo hemos desbordado y a
continuación hemos sobrescrito la variable correctamente.
Recordemos que en el formato little-endian el orden es del byte
menos significativo hasta el byte más significativo.
GNU/Linux Exploiting 33
Return to Text
gcc -fno-stack-protector return-to-text.c -o return-to-text
GNU/Linux Exploiting 34
Return to Text
La representación de la pila sería:
Nuestro objetivo es sobrescribir la dirección de retorno con la dirección de la función win()
buffer (64 bytes)
EBP
RET
GNU/Linux Exploiting 35
Return to Text
Procedemos a calcular el desplazamiento necesario para llegar a
sobrescribir la dirección de retorno. Para este proceso podemos
utilizar un patrón cíclico (una secuencia única que nos permitirá
calcular dicho offset).
GNU/Linux Exploiting 36
Return to Text
Tras generar un patrón de 100 bytes, obtenemos el desplazamiento
GNU/Linux Exploiting 37
Return to Text
Procedemos pues a obtener la dirección de la función win()
objdump -M intel -D ./return-to-text
GNU/Linux Exploiting 38
Return to Text
Verificamos que podemos alterar el flujo correctamente:
GNU/Linux Exploiting 39
Return to Shellcode
gcc -fno-stack-protector -z execstack return-to-shellcode.c -o return-to-shellcode
GNU/Linux Exploiting 40
Return to Shellcode
GNU/Linux Exploiting 41
Return to Shellcode
A partir de 264 bytes, sobrescribimos el saved EBP (frame pointer) y
RET
GNU/Linux Exploiting 42
Return to Shellcode
Esta ocasión nuestro fin es lograr ejecutar código arbitrario en el
sistema, para dicha labor utilizaremos un shellcode.
GNU/Linux Exploiting 43
Return to Shellcode
Un shellcode es un conjunto de instrucciones normalmente programadas en
lenguaje ensamblador y representadas en forma de códigos de operación, su
propósito es ejecutar la operación que se haya programado.
Shellcode que ejecuta /bin/sh con execve()
GNU/Linux Exploiting 44
Return to Shellcode
El buffer podía almacenar 64 bytes, lo hemos desbordado y a
continuación hemos sobrescrito la variable correctamente.
Recordemos que en el formato little-endian el orden es del byte
menos significativo hasta el byte más significativo.
GNU/Linux Exploiting 45
Return to Shellcode
Procedemos a desactivar la ASLR:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
A continuación ponemos un punto de ruptura en la llamada a gets() y observamos
los parámetros que recibe:
GNU/Linux Exploiting 46
Return to Shellcode
Ahora que sabemos cual es la dirección de inicio de nuestro buffer, podemos
alojar nuestro shellcode en el mismo y saltar a el:
GNU/Linux Exploiting 47
Return to Shellcode
Vamos a probar a ejecutarlo fuera del depurador
Vemos que algo no va bien, habilitaremos la generación de core dumps (crasheos)
y procederemos con un análisis post mortem.
ulimit -c unlimited
GNU/Linux Exploiting 48
Return to Shellcode
Analizamos un poco el core dump y rápidamente localizamos el shellcode
gdb -q --core core
GNU/Linux Exploiting 49
Return to Shellcode
Modificamos el exploit con la nueva dirección y ejecutamos de
nuevo…
¿Dónde está mi shell?
GNU/Linux Exploiting 50
Return to Shellcode
Utilicemos strace para ver las llamadas al sistema
GNU/Linux Exploiting 51
Return to Shellcode
Parece ser que estamos perdiendo el contexto de la entrada estándar, debemos mantener stdin
abierto.
(python exploit.py; cat) | ./return-to-shellcode
cat exploit - | ./return-to-shellcode
GNU/Linux Exploiting 52
Protecciones
ASLR (Address Space Layout Randomization)
La aleatoriedad en la disposición del espacio de direcciones es una técnica que intenta mitigar o
dificultar la explotación de vulnerabilidades basadas en la corrupción de memoria (originalmente
se implementó en PaX).
En 32 bits la entropía no es muy alta pues 12 bits quedan estáticos, es posible realizar un ataque
de fuerza bruta. Luego se verán maneras de sortear esta mitigación.
En este caso tendríamos una probabilidad de
1
165 para adivinar la dirección del buffer.
GNU/Linux Exploiting 53
Protecciones
NX (No eXecute)
Normalmente las páginas de memoria suelen estar marcadas como no ejecutables gracias a la
protección NX (non-execute).
Esto significa que aunque logremos inyectar un shellcode en la memoria y logremos alterar el flujo
del programa para que salte a nuestra zona controlada, no podremos ejecutarlo.
GNU/Linux Exploiting 54
Protecciones
PIE/PIC (Position Independent Execution)
Este mecanismo de protección permite realizar una aleatorización en los segmentos de texto y
datos.
Es decir, se realiza un direccionamiento relativo, en cada ejecución se generará de manera pseudo
aleatoria una dirección base y se irán calculando el resto de direcciones mediante sumas de
desplazamientos.
Por defecto gcc no compila con PIE, para utilizar esta protección se deben utilizar las flags -fPIC -
pie
GNU/Linux Exploiting 55
Protecciones
StackGuard
Este mecanismo de protección consiste en generar un valor aleatorio (canario) en el prólogo de
una función, salvaguardarlo justo antes del frame pointer y dirección de retorno en la pila.
En el epílogo de la función realizará la operación lógica de disyunción exclusiva con el valor actual
y el generado anteriormente, de manera que detectará si ha sido modificado o no.
buffer
EBP
canario
RET
GNU/Linux Exploiting 56
PLT/GOT
La PLT (Procedure Linkage Table) es usada para llamar a
procedimientos/funciones cuya dirección no se conoce durante el
enlazado, es el enlazador dinámico el encargado de resolverla durante
la ejecución.
La GOT (Global Offsets Table) es otra tabla que contiene direcciones
absolutas los procedimientos/funciones que serán utilizados, se utiliza
de manera similar a la PLT.
GNU/Linux Exploiting 57
Enlace perezoso (Lazy Binding)
En el enlace perezoso (procesos llevado a cabo por el cargador de ELF) cuando un
binario está cargado en memoria y una función es llamada por primera vez, la PLT
realiza un salto a la GOT donde resolverá la entrada que aún no ha sido resuelta.
En ese momento el enlazador dinámico es invocado, este resolverá y almacenará
en la GOT la dirección del símbolo correspondiente a la función invocada.
Las siguientes llamadas a la función no volverán a pasar por dicho proceso, pues
su dirección ya estará resuelta en la GOT.
GNU/Linux Exploiting 58
Protecciones
RELRO (Relocation Read-Only)
RELRO Parcial: Reordena las secciones ELF de manera que las
secciones internas de datos (.got, .dtors, etc.) precedan las secciones
de datos del programa (.data y .bss), la problemática es que la GOT es
escribible.
RELRO Completo: Remapea toda la GOT como solo lectura. Es la única
manera de mitigar cualquier tipo de técnica que trate de modificar la
GOT, pues protege las secciones de datos internos en el ELF para que
no se sobrescriban (a medida que se reordenan las secciones ELF).
Flags para compilar con Full RELRO: gcc -Wl,-z,relro,-z,now
GNU/Linux Exploiting 59
GOT
Cómo encontrar la GOT
objdump -R elf
GNU/Linux Exploiting 60
GOT Hijacking
Para poder implementar el enlazado perezoso la GOT debe ser escribible.
El objetivo sería sobrescribir alguna entrada de la GOT, de manera que afecte al
flujo del programa.
…
…
call foo@plt
…
…
printf
system
…
.text
.got.plt
jmp *(foo@GOT)
push index
jmp PLT0
foo@plt
push *(GOT + 4)
jmp *(GOT + 8)
PLT0
Cuando se produce un call foo, se realizará un jmp a la
función system.
GNU/Linux Exploiting 61
Return to Library
El objetivo de esta técnica es sortear la protección NX.
Para lograr dicho fin, debemos sobrescribir la dirección de retorno con
una llamada de librería del sistema.
Uno de los problemas sería la ASLR, para poder realizar esta
metodología en dicho escenario sería necesaria alguna fuga de
información que nos permitiese calcular la dirección base de la
librería del sistema.
GNU/Linux Exploiting 62
Return to Library
gcc -fno-stack-protector return-to-library.c -o return-to-library
GNU/Linux Exploiting 63
Return to Library
Procederemos a ejecutar system("/bin/sh"), debemos situar los
argumentos en la pila de manera que cuando se ejecute system estos
sean interpretados como tal.
AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA
system
fake RET
& /bin/sh
GNU/Linux Exploiting 64
Return to Library
Procederemos a buscar las direcciones de los argumentos requeridos.
GNU/Linux Exploiting 65
Return to Library
Ponemos un punto de ruptura en la instrucción ret y verificamos que
todo se encuentra en el lugar correcto
GNU/Linux Exploiting 66
Return to Library
Podemos utilizar exit como dirección de retorno, para evitar generar
un core dump al finalizar e intentar ejecutar "0x41414141".
GNU/Linux Exploiting 67
Condición de carrera (Race Condition)
Son un tipo de error lógico donde dos flujos de código se ejecutan de
forma concurrente y el resultado final depende del orden de
ejecución, como consecuencia las acciones de uno sobre los datos
puede influir en los resultados del otro.
GNU/Linux Exploiting 68
Condición de carrera (Race Condition)
GNU/Linux Exploiting 69
Condición de carrera (Race Condition)
Nuestro objetivo será aprovecharnos del sleep, para poder leer el
fichero temporal.
GNU/Linux Exploiting 70
Condición de carrera (Race Condition)
Hemos logrado el objetivo!
GNU/Linux Exploiting 71
Format String
Este tipo de bug ocurre cuando una entrada de datos se evalúa por
una función de manera incorrecta (normalmente la función
pertenecerá a la familia *printf()).
Explotando dicha vulnerabilidad se puede lograr desde una fuga de
memoria hasta una escritura.
GNU/Linux Exploiting 72
Format String
GNU/Linux Exploiting 73
Format String
Este tipo de bug ocurre cuando una entrada de datos se evalúa por
una función de manera incorrecta (normalmente la función
pertenecerá a la familia *printf()).
Explotando dicha vulnerabilidad obtenemos una primitiva de lectura y
escritura.
GNU/Linux Exploiting 74
Format String
Procedemos pues a introducir algún testigo de formato e intentamos
volcar valores de la pila.
GNU/Linux Exploiting 75
Format String
Utilicemos un depurador, para visualizar mejor lo que sucede.
Vemos como los valores examinados coinciden con el volcado.
GNU/Linux Exploiting 76
Format String
Vamos a escribir los dos bytes inferiores (LOB) del objetivo:
• r <<< $(python -c 'print "x34xa0x04x08" + "%16701d%7$hn"')
Ahora vamos a escribir los dos bytes superiores (HOB):
• r <<< $(python -c 'print "x36xa0x04x08" + "%16701d%7$hn"')
GNU/Linux Exploiting 77
Format String
• Reglas de escritura:
• Si HOB > LOB
• [dirección+2] [dirección] [LOB - 8] [offset+1] [HOB-LOB] [offset]
• Si HOB < LOB
• [dirección+2] [dirección] [HOB - 8] [offset] [LOB-HOB] [offset+1]
GNU/Linux Exploiting 78
Format String
Vamos a aprovechar esta fuga de información (infoleak), para
bypassear el StackGuard
GNU/Linux Exploiting 79
Format String
Vamos a ver el canario que genera, poner un punto de ruptura en la
llamada al sistema y buscar dicho valor en la pila
GNU/Linux Exploiting 80
Format String
Vemos que la posición del canario es $esp + 540, como las
direcciones son de 4 bytes:
540
4
= 135. Podemos utilizar el testigo de
acceso directo: %135$p
GNU/Linux Exploiting 81
ROP (Return-oriented programming)
Esta técnica comúnmente nos permitirá evadir la protección NX.
El objetivo consiste en lograr ejecutar una secuencia de instrucciones
máquina llamadas gadgets (presentes en la memoria de la máquina)
con el fin de lograr ejecutar operaciones arbitrarias en la máquina.
Cada gadget generalmente termina en una instrucción de retorno y se
suelen encontrar en subrutinas del programa y/o bibliotecas
compartidas.
Utilizaremos una herramienta para localizar los gadgets fácilmente:
• https://github.com/sashs/Ropper
GNU/Linux Exploiting 82
ROP
gcc -static -fno-stack-protector rop.c -o rop
GNU/Linux Exploiting 83
ROP
http://syscalls.kernelgrok.com/
GNU/Linux Exploiting 84
ROP
Nuestro objetivo será hacer ejecutable el stack, para esta labor
utilizaremos la syscall mprotect:
GNU/Linux Exploiting 85
ROP
Ahora que sabemos los argumentos que recibe, buscaremos los
gadgets necesarios para controlar los registros y efectuar la llamada al
sistema.
La instrucción int 0x80 provoca una interrupción software (llamada al
sistema), es una instrucción especial que causa que el procesador
transfiera el control a un código privilegiado (núcleo).
GNU/Linux Exploiting 86
ROP
Desactivemos la ASLR y veamos cual es la dirección del stack:
Ahora tracearemos nuestro rop-chain y verifiquemos que la pila
queda con permisos de ejecución.
GNU/Linux Exploiting 87
ROP
Automatizaremos un poquito el proceso
GNU/Linux Exploiting 88
ROP
Vemos que controlamos perfectamente la pila
GNU/Linux Exploiting 89
ROP
Y finalmente hemos logrado nuestro fin
Ahora que tenemos control de la pila, podemos alojar nuestro
shellcode al inicio del buffer y hacer un exploit en condiciones
GNU/Linux Exploiting 90
ROP
GNU/Linux Exploiting 91
ROP
Verifiquemos que la shellcode se ejecuta correctamente
r < <(python exploit.py)
GNU/Linux Exploiting 92
ROP
Habilitamos los core dumps y ajustamos el exploit con la dirección del
buffer fuera del depurador.
Y finalmente hemos logrado nuestro objetivo!
GNU/Linux Exploiting 93
Feel like a pirate

Manuel Blanco - GNU/Linux Binary Exploitation I&II [rooted2018]

  • 1.
    GNU/Linux Exploiting Introducción ala explotación de binarios
  • 2.
    GNU/Linux Exploiting 2 •Manuel Blanco Parajón • Jugador habitual de competiciones “CTF” • w0pr • ID-10-T • Estudiante de Ingeniería Informática • Autodidacta # whoami @manuelbp01 manuelbp01@gmail.com
  • 3.
    GNU/Linux Exploiting 3 •¿Qué vamos a ver en este taller? Introducción a la explotación de vulnerabilidades en software • Requisitos recomendados • Nivel básico de programación en C • Manejo sencillo de la shell GNU/Linux • Conocimientos básicos de Ingeniería Inversa • Fundamentos de Computadores • Resultados Ser capaz de desarrollar tu primer exploit Introducción
  • 4.
  • 5.
    GNU/Linux Exploiting 5 •Bug: Error de software o fallo de programación que causa un comportamiento anómalo o desencadena un resultado inesperado en la aplicación. • Vulnerabilidad: Clase particular de bug que puede ser aprovechado por un atacante para comprometer la seguridad, integridad, disponibilidad y confidencialidad de un sistema. • Exploit: Fragmento de software utilizado para aprovechar una vulnerabilidad de un sistema, con el fin de conseguir un comportamiento no deseado para el mismo. • Payload: Efecto que se desea lograr al explotar una vulnerabilidad. Términos
  • 6.
    GNU/Linux Exploiting 6 •Ingeniería Inversa: Proceso llevado a cabo con el objetivo de obtener información a partir de un producto final. • Análisis estático • Análisis dinámico Ingeniería Inversa
  • 7.
    GNU/Linux Exploiting 7 •Análisis estático: Tipo de análisis de software que se realiza sin ejecutar el programa. • Ejemplo: Podemos utilizar objdump como un desensamblador (traduce código máquina a ensamblador) Ingeniería Inversa
  • 8.
    GNU/Linux Exploiting 8 •Análisis dinámico: Tipo de análisis de software que se realiza ejecutando el programa. • Ejemplo • strace: Permite monitorear las llamadas al sistema y las señales. • ltrace: Permite monitorear las llamadas a las librerías compartidas. Ingeniería Inversa
  • 9.
    GNU/Linux Exploiting 9 •IDA 7.0 Freeware Version https://www.hex-rays.com/products/ida/support/download_freeware.shtml Herramientas útiles
  • 10.
    GNU/Linux Exploiting 10 •radare2 https://github.com/radare/radare2 Herramientas útiles
  • 11.
    GNU/Linux Exploiting 11 •GDB (GNU Debugger) Herramientas útiles
  • 12.
    GNU/Linux Exploiting 12 •PEDA (Python Exploit Development Assistance for GDB) https://github.com/longld/peda Herramientas útiles
  • 13.
    GNU/Linux Exploiting 13 •Los depuradores son muy útiles!! Primer ejercicio
  • 14.
    GNU/Linux Exploiting 14 •Estructuras de datos (tablas) que muestran la distribución de la memoria Mapa de memoria
  • 15.
    GNU/Linux Exploiting 15 •Segmentación de memoria: División de la memoria primaria en segmentos o secciones • Los segmentos normalmente corresponden a las divisiones naturales de un programa, como las rutinas o las tablas de datos. • data: rw- • code: r-x • stack: rw- • heap: rw- Segmentación de memoria
  • 16.
    GNU/Linux Exploiting 16 •¿Qué sucede cuando ejecutas un archivo ELF? • $ ./test • Normalmente el programa estará en el disco, y el kernel será el encargado de realizar una serie de procedimientos para el mapeo de la memoria del programa. Flujo de ejecución
  • 17.
    GNU/Linux Exploiting 17 Flujode ejecución ./test fork() execve(“./test”, *argv[], *envp[]) sys_execve() do_execve() search_binary_handler() load_elf_binary() ld.so _start __libc_start_main _init main user mode kernel mode
  • 18.
    GNU/Linux Exploiting 18 Cómose realiza el mapeo del programa a la memoria virtual • En el encabezado del programa • Se guardan qué segmentos se deben mapear y sus respectivas ubicaciones • También se guarda qué secciones pertenecen a qué segmentos • Durante el mapeo la memoria se dividirá en distintos segmentos dependiendo de sus respectivos permisos • Un segmento puede contener 0 o varias secciones Flujo de ejecución
  • 19.
    GNU/Linux Exploiting 19 Cómose realiza el mapeo del programa a la memoria virtual Flujo de ejecución
  • 20.
    GNU/Linux Exploiting 20 Cómose realiza el mapeo del programa a la memoria virtual Flujo de ejecución otra sección .data .bss .got.plt .rodata .text .init ELF encabezado RW R o RX kernel space DATA VMA CODE VMA stack heap En disco En memoria
  • 21.
    GNU/Linux Exploiting 21 Registros •Registros de propósito general • EAX EBX ECX EDX – 32 bit • AX BX CX DX – 16 bit • AH BH CH DH – 8 bit (parte alta) • AL BL CL DL – 8 bit (parte baja) Ensamblador x86 AH AL EAX AX
  • 22.
    GNU/Linux Exploiting 22 Registros •Stack Pointer • ESP – 32 bit • Apunta a la cima de la pila • Base Pointer • EBP – 32 bit • Apunta a la base de la pila • La pila es una estructura de datos (cola LIFO) que permite almacenar y recuperar datos Ensamblador x86
  • 23.
    GNU/Linux Exploiting 23 EBP:0xffffcfd8 0x804871c ??? ??? 0x804871c ??? ??? 0xffffcfd8 Funcionamiento CPU Prólogo de la función Llamada a get_flag RET addr RET addr Frame pointer * La representación real de la pila sería al revés
  • 24.
    GNU/Linux Exploiting 24 0x804871c ??? ??? 0xffffcfd8 ??? ??? FuncionamientoCPU ??? ??? ??? Stack Frame Marco de pila: Estructura de datos que contienen la información de estado de la subrutina, son utilizados para almacenar variables locales y cálculos.
  • 25.
    GNU/Linux Exploiting 25 FuncionamientoCPU Epílogo de la función 0x804871c ??? ??? 0xffffcfd8 0x804871c ??? ??? 0x804871c ??? 0xffffcfd8 ???
  • 26.
    GNU/Linux Exploiting 26 Registros •Registro contador del programa • EIP • Apunta a la siguiente instrucción a ejecutar • Registro flag • eflags • Almacena los resultados de ejecución • Registro de segmento • cs ss ds es fs gs Ensamblador x86
  • 27.
    GNU/Linux Exploiting 27 Buffer:Espacio de memoria reservado para almacenar datos de manera temporal. Si se introducen más datos que los que el buffer puede almacenar, entonces se produce un desbordamiento. Buffer Overflow
  • 28.
    GNU/Linux Exploiting 28 StackSmash gcc -fno-stack-protector stack-smash.c –o stack-smash
  • 29.
    GNU/Linux Exploiting 29 StackSmash buffer (64 bytes) variable EBP RET argc argv envp variable EBP RET argc argv envp A AA A A A A A A … … … buffer (64 bytes) AAA A A A … … A A A A Recordemos que la pila crece desde las direcciones altas hacia las bajas, la representación real sería al revés.
  • 30.
    GNU/Linux Exploiting 30 StackSmash • r <<< $(python -c 'print "A" * 64 + "B" * 4')
  • 31.
    GNU/Linux Exploiting 31 StackSmash • r <<< $(python -c 'print "A" * 64 + "xefxbexadxde"')
  • 32.
    GNU/Linux Exploiting 32 StackSmash El buffer podía almacenar 64 bytes, lo hemos desbordado y a continuación hemos sobrescrito la variable correctamente. Recordemos que en el formato little-endian el orden es del byte menos significativo hasta el byte más significativo.
  • 33.
    GNU/Linux Exploiting 33 Returnto Text gcc -fno-stack-protector return-to-text.c -o return-to-text
  • 34.
    GNU/Linux Exploiting 34 Returnto Text La representación de la pila sería: Nuestro objetivo es sobrescribir la dirección de retorno con la dirección de la función win() buffer (64 bytes) EBP RET
  • 35.
    GNU/Linux Exploiting 35 Returnto Text Procedemos a calcular el desplazamiento necesario para llegar a sobrescribir la dirección de retorno. Para este proceso podemos utilizar un patrón cíclico (una secuencia única que nos permitirá calcular dicho offset).
  • 36.
    GNU/Linux Exploiting 36 Returnto Text Tras generar un patrón de 100 bytes, obtenemos el desplazamiento
  • 37.
    GNU/Linux Exploiting 37 Returnto Text Procedemos pues a obtener la dirección de la función win() objdump -M intel -D ./return-to-text
  • 38.
    GNU/Linux Exploiting 38 Returnto Text Verificamos que podemos alterar el flujo correctamente:
  • 39.
    GNU/Linux Exploiting 39 Returnto Shellcode gcc -fno-stack-protector -z execstack return-to-shellcode.c -o return-to-shellcode
  • 40.
  • 41.
    GNU/Linux Exploiting 41 Returnto Shellcode A partir de 264 bytes, sobrescribimos el saved EBP (frame pointer) y RET
  • 42.
    GNU/Linux Exploiting 42 Returnto Shellcode Esta ocasión nuestro fin es lograr ejecutar código arbitrario en el sistema, para dicha labor utilizaremos un shellcode.
  • 43.
    GNU/Linux Exploiting 43 Returnto Shellcode Un shellcode es un conjunto de instrucciones normalmente programadas en lenguaje ensamblador y representadas en forma de códigos de operación, su propósito es ejecutar la operación que se haya programado. Shellcode que ejecuta /bin/sh con execve()
  • 44.
    GNU/Linux Exploiting 44 Returnto Shellcode El buffer podía almacenar 64 bytes, lo hemos desbordado y a continuación hemos sobrescrito la variable correctamente. Recordemos que en el formato little-endian el orden es del byte menos significativo hasta el byte más significativo.
  • 45.
    GNU/Linux Exploiting 45 Returnto Shellcode Procedemos a desactivar la ASLR: echo 0 | sudo tee /proc/sys/kernel/randomize_va_space A continuación ponemos un punto de ruptura en la llamada a gets() y observamos los parámetros que recibe:
  • 46.
    GNU/Linux Exploiting 46 Returnto Shellcode Ahora que sabemos cual es la dirección de inicio de nuestro buffer, podemos alojar nuestro shellcode en el mismo y saltar a el:
  • 47.
    GNU/Linux Exploiting 47 Returnto Shellcode Vamos a probar a ejecutarlo fuera del depurador Vemos que algo no va bien, habilitaremos la generación de core dumps (crasheos) y procederemos con un análisis post mortem. ulimit -c unlimited
  • 48.
    GNU/Linux Exploiting 48 Returnto Shellcode Analizamos un poco el core dump y rápidamente localizamos el shellcode gdb -q --core core
  • 49.
    GNU/Linux Exploiting 49 Returnto Shellcode Modificamos el exploit con la nueva dirección y ejecutamos de nuevo… ¿Dónde está mi shell?
  • 50.
    GNU/Linux Exploiting 50 Returnto Shellcode Utilicemos strace para ver las llamadas al sistema
  • 51.
    GNU/Linux Exploiting 51 Returnto Shellcode Parece ser que estamos perdiendo el contexto de la entrada estándar, debemos mantener stdin abierto. (python exploit.py; cat) | ./return-to-shellcode cat exploit - | ./return-to-shellcode
  • 52.
    GNU/Linux Exploiting 52 Protecciones ASLR(Address Space Layout Randomization) La aleatoriedad en la disposición del espacio de direcciones es una técnica que intenta mitigar o dificultar la explotación de vulnerabilidades basadas en la corrupción de memoria (originalmente se implementó en PaX). En 32 bits la entropía no es muy alta pues 12 bits quedan estáticos, es posible realizar un ataque de fuerza bruta. Luego se verán maneras de sortear esta mitigación. En este caso tendríamos una probabilidad de 1 165 para adivinar la dirección del buffer.
  • 53.
    GNU/Linux Exploiting 53 Protecciones NX(No eXecute) Normalmente las páginas de memoria suelen estar marcadas como no ejecutables gracias a la protección NX (non-execute). Esto significa que aunque logremos inyectar un shellcode en la memoria y logremos alterar el flujo del programa para que salte a nuestra zona controlada, no podremos ejecutarlo.
  • 54.
    GNU/Linux Exploiting 54 Protecciones PIE/PIC(Position Independent Execution) Este mecanismo de protección permite realizar una aleatorización en los segmentos de texto y datos. Es decir, se realiza un direccionamiento relativo, en cada ejecución se generará de manera pseudo aleatoria una dirección base y se irán calculando el resto de direcciones mediante sumas de desplazamientos. Por defecto gcc no compila con PIE, para utilizar esta protección se deben utilizar las flags -fPIC - pie
  • 55.
    GNU/Linux Exploiting 55 Protecciones StackGuard Estemecanismo de protección consiste en generar un valor aleatorio (canario) en el prólogo de una función, salvaguardarlo justo antes del frame pointer y dirección de retorno en la pila. En el epílogo de la función realizará la operación lógica de disyunción exclusiva con el valor actual y el generado anteriormente, de manera que detectará si ha sido modificado o no. buffer EBP canario RET
  • 56.
    GNU/Linux Exploiting 56 PLT/GOT LaPLT (Procedure Linkage Table) es usada para llamar a procedimientos/funciones cuya dirección no se conoce durante el enlazado, es el enlazador dinámico el encargado de resolverla durante la ejecución. La GOT (Global Offsets Table) es otra tabla que contiene direcciones absolutas los procedimientos/funciones que serán utilizados, se utiliza de manera similar a la PLT.
  • 57.
    GNU/Linux Exploiting 57 Enlaceperezoso (Lazy Binding) En el enlace perezoso (procesos llevado a cabo por el cargador de ELF) cuando un binario está cargado en memoria y una función es llamada por primera vez, la PLT realiza un salto a la GOT donde resolverá la entrada que aún no ha sido resuelta. En ese momento el enlazador dinámico es invocado, este resolverá y almacenará en la GOT la dirección del símbolo correspondiente a la función invocada. Las siguientes llamadas a la función no volverán a pasar por dicho proceso, pues su dirección ya estará resuelta en la GOT.
  • 58.
    GNU/Linux Exploiting 58 Protecciones RELRO(Relocation Read-Only) RELRO Parcial: Reordena las secciones ELF de manera que las secciones internas de datos (.got, .dtors, etc.) precedan las secciones de datos del programa (.data y .bss), la problemática es que la GOT es escribible. RELRO Completo: Remapea toda la GOT como solo lectura. Es la única manera de mitigar cualquier tipo de técnica que trate de modificar la GOT, pues protege las secciones de datos internos en el ELF para que no se sobrescriban (a medida que se reordenan las secciones ELF). Flags para compilar con Full RELRO: gcc -Wl,-z,relro,-z,now
  • 59.
    GNU/Linux Exploiting 59 GOT Cómoencontrar la GOT objdump -R elf
  • 60.
    GNU/Linux Exploiting 60 GOTHijacking Para poder implementar el enlazado perezoso la GOT debe ser escribible. El objetivo sería sobrescribir alguna entrada de la GOT, de manera que afecte al flujo del programa. … … call foo@plt … … printf system … .text .got.plt jmp *(foo@GOT) push index jmp PLT0 foo@plt push *(GOT + 4) jmp *(GOT + 8) PLT0 Cuando se produce un call foo, se realizará un jmp a la función system.
  • 61.
    GNU/Linux Exploiting 61 Returnto Library El objetivo de esta técnica es sortear la protección NX. Para lograr dicho fin, debemos sobrescribir la dirección de retorno con una llamada de librería del sistema. Uno de los problemas sería la ASLR, para poder realizar esta metodología en dicho escenario sería necesaria alguna fuga de información que nos permitiese calcular la dirección base de la librería del sistema.
  • 62.
    GNU/Linux Exploiting 62 Returnto Library gcc -fno-stack-protector return-to-library.c -o return-to-library
  • 63.
    GNU/Linux Exploiting 63 Returnto Library Procederemos a ejecutar system("/bin/sh"), debemos situar los argumentos en la pila de manera que cuando se ejecute system estos sean interpretados como tal. AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA system fake RET & /bin/sh
  • 64.
    GNU/Linux Exploiting 64 Returnto Library Procederemos a buscar las direcciones de los argumentos requeridos.
  • 65.
    GNU/Linux Exploiting 65 Returnto Library Ponemos un punto de ruptura en la instrucción ret y verificamos que todo se encuentra en el lugar correcto
  • 66.
    GNU/Linux Exploiting 66 Returnto Library Podemos utilizar exit como dirección de retorno, para evitar generar un core dump al finalizar e intentar ejecutar "0x41414141".
  • 67.
    GNU/Linux Exploiting 67 Condiciónde carrera (Race Condition) Son un tipo de error lógico donde dos flujos de código se ejecutan de forma concurrente y el resultado final depende del orden de ejecución, como consecuencia las acciones de uno sobre los datos puede influir en los resultados del otro.
  • 68.
    GNU/Linux Exploiting 68 Condiciónde carrera (Race Condition)
  • 69.
    GNU/Linux Exploiting 69 Condiciónde carrera (Race Condition) Nuestro objetivo será aprovecharnos del sleep, para poder leer el fichero temporal.
  • 70.
    GNU/Linux Exploiting 70 Condiciónde carrera (Race Condition) Hemos logrado el objetivo!
  • 71.
    GNU/Linux Exploiting 71 FormatString Este tipo de bug ocurre cuando una entrada de datos se evalúa por una función de manera incorrecta (normalmente la función pertenecerá a la familia *printf()). Explotando dicha vulnerabilidad se puede lograr desde una fuga de memoria hasta una escritura.
  • 72.
  • 73.
    GNU/Linux Exploiting 73 FormatString Este tipo de bug ocurre cuando una entrada de datos se evalúa por una función de manera incorrecta (normalmente la función pertenecerá a la familia *printf()). Explotando dicha vulnerabilidad obtenemos una primitiva de lectura y escritura.
  • 74.
    GNU/Linux Exploiting 74 FormatString Procedemos pues a introducir algún testigo de formato e intentamos volcar valores de la pila.
  • 75.
    GNU/Linux Exploiting 75 FormatString Utilicemos un depurador, para visualizar mejor lo que sucede. Vemos como los valores examinados coinciden con el volcado.
  • 76.
    GNU/Linux Exploiting 76 FormatString Vamos a escribir los dos bytes inferiores (LOB) del objetivo: • r <<< $(python -c 'print "x34xa0x04x08" + "%16701d%7$hn"') Ahora vamos a escribir los dos bytes superiores (HOB): • r <<< $(python -c 'print "x36xa0x04x08" + "%16701d%7$hn"')
  • 77.
    GNU/Linux Exploiting 77 FormatString • Reglas de escritura: • Si HOB > LOB • [dirección+2] [dirección] [LOB - 8] [offset+1] [HOB-LOB] [offset] • Si HOB < LOB • [dirección+2] [dirección] [HOB - 8] [offset] [LOB-HOB] [offset+1]
  • 78.
    GNU/Linux Exploiting 78 FormatString Vamos a aprovechar esta fuga de información (infoleak), para bypassear el StackGuard
  • 79.
    GNU/Linux Exploiting 79 FormatString Vamos a ver el canario que genera, poner un punto de ruptura en la llamada al sistema y buscar dicho valor en la pila
  • 80.
    GNU/Linux Exploiting 80 FormatString Vemos que la posición del canario es $esp + 540, como las direcciones son de 4 bytes: 540 4 = 135. Podemos utilizar el testigo de acceso directo: %135$p
  • 81.
    GNU/Linux Exploiting 81 ROP(Return-oriented programming) Esta técnica comúnmente nos permitirá evadir la protección NX. El objetivo consiste en lograr ejecutar una secuencia de instrucciones máquina llamadas gadgets (presentes en la memoria de la máquina) con el fin de lograr ejecutar operaciones arbitrarias en la máquina. Cada gadget generalmente termina en una instrucción de retorno y se suelen encontrar en subrutinas del programa y/o bibliotecas compartidas. Utilizaremos una herramienta para localizar los gadgets fácilmente: • https://github.com/sashs/Ropper
  • 82.
    GNU/Linux Exploiting 82 ROP gcc-static -fno-stack-protector rop.c -o rop
  • 83.
  • 84.
    GNU/Linux Exploiting 84 ROP Nuestroobjetivo será hacer ejecutable el stack, para esta labor utilizaremos la syscall mprotect:
  • 85.
    GNU/Linux Exploiting 85 ROP Ahoraque sabemos los argumentos que recibe, buscaremos los gadgets necesarios para controlar los registros y efectuar la llamada al sistema. La instrucción int 0x80 provoca una interrupción software (llamada al sistema), es una instrucción especial que causa que el procesador transfiera el control a un código privilegiado (núcleo).
  • 86.
    GNU/Linux Exploiting 86 ROP Desactivemosla ASLR y veamos cual es la dirección del stack: Ahora tracearemos nuestro rop-chain y verifiquemos que la pila queda con permisos de ejecución.
  • 87.
  • 88.
    GNU/Linux Exploiting 88 ROP Vemosque controlamos perfectamente la pila
  • 89.
    GNU/Linux Exploiting 89 ROP Yfinalmente hemos logrado nuestro fin Ahora que tenemos control de la pila, podemos alojar nuestro shellcode al inicio del buffer y hacer un exploit en condiciones
  • 90.
  • 91.
    GNU/Linux Exploiting 91 ROP Verifiquemosque la shellcode se ejecuta correctamente r < <(python exploit.py)
  • 92.
    GNU/Linux Exploiting 92 ROP Habilitamoslos core dumps y ajustamos el exploit con la dirección del buffer fuera del depurador. Y finalmente hemos logrado nuestro objetivo!
  • 93.