Exploitation 101
Buffer Overflow
Par Israël Hallé
Adapté par Olivier Arteau
Réadapté par Israël Hallé
Plan de la présentation
- Concept de base
- Vulnérabilité Buffer overflow
- Return Oriented Programming
- Outils et trucs pouvant aider au reversing ou à l'exploitation d'un programme
Concept Important
- Registre du CPU
- Appel de fonction
- Structure de la pile
Registre du CPU
- Instruction Pointer (RIP)
- Stack Pointer (RSP)
- Base Pointeur (RBP)
- General Purpose Register (RDI, RSI, RAX, et cie)
- 64 bits: RDI, RSI, RAX, RBX, RCX, RDX
- 32 bits: EDI, ESI, EAX, EBX, ECX, EDX
- 16 bits: DI, SI, AX, BX, CX, DX
- 8 bits: AL, AH, BL, BH, CL, CH, DL, DH
call, ret
- call fn
- push $rip
- jmp fn
- ret
- pop $rip
Appel de fonction (C)
int hello(int a, int* b, int c) { int hello_var = 0xdeadbeef; return 0xf00; } int main() { int main_var = 0x0; int result = hello(main_var, &main_var, 0x123456); return 0; }
Appel de fonction (x86)
main
hello
Appel de fonction (Pile)
int hello(int a, int* b, int c);
hello(main_var, &main_var, 0x123456);
0x7fffffff
+ +----------+
Main return address | |0x00804e00|
| +----------+
Saved base stack | |0x7fff3ed0| <--+
| +----------+ |
Main local vars | |... | |
| +----------+ |
c | |0 | |
| +----------+ |
b | |0x7fff3ebc| |
| +----------+ |
a | |0x12345678| |
| +----------+ |
hello return address | |0x00804f56| |
| +----------+ |
Saved base stack | |0x7fff3ea0| ---+
| +----------+
Hello local vars | |... |
v +----------+
0x00000000
x86-64
-
Registre 64 bits:
RIP, RBP, RSP, RDI, RSI, RAX, RBX, RCX, RDX, R10, R8-15
-
Appel de fonction (Linux)
-
Arguments passé via registre:
RDI, RSI, RDX, RCX, R8, R9, stack
-
Pointeur 8 bytes
Buffer Overflow
int main() { int some_var = 0; char buffer[12]; fgets(buffer, 9001, stdin); return 0; }
Stack avant fgets
0x7fffffff + +---------+ | |Saved RIP| ^ | +---------+ | | |Saved RBP| | | +---------+ | | |some_var | | | +---------+ | | | | | | | | | | |buffer | + fgets(buffer, ...) v +---------+ 0x00000000
Stack après fgets
0x7fffffff + +---------+ | |AAAA | ^ | +---------+ | | |AAAA | | | +---------+ | | |AAAA | | | +---------+ | | |AAAA | | | |AAAA | | | |AAAA | | fgets(buffer, ...) v +---------+ 0x00000000
Cause Courante
- Classique CTF:
- char dst[100];
read(0, dst, 200);
- char dst[100];
- Fonction sans limites:
-
strcpy(src, dst); gets(dst); scanf("%s", dst)
-
- Débordement d'entier:
-
x > z
-
z + y < z ??
-
0xffffffff > 0x1000 (32 bits)
-
0xffffffff + 1 < 0x1000 (32bits)
-
- Signé / non-signé
-
if ( x < 0x1000) memcpy(src, dst, x); // x = -1, woops
-
Return Oriented Programming
- ROP
- La Stack les addresses de retour et paramètres des fonctions
- Buffer Overflow permet de réécrire la Stack
- Il est donc possible de retourner dans des fonctions tout en contrôlant les paramètres
ROP Gadgets
- Fragment d'instructions finissant par un saut ou une instruction de retour dont la destination est contrôlé par l'attaquant.
- Exécution en chaîne de plusieurs fragments pour créer un "programme"
Examples:
pop rdi;
pop esi; pop rdx; ret;
Pop; pop; ret
- Gadgets courant et pratiques
- Séries d'instructions qui permet de « dérouler » la Stack
- Permet de chaîner plusieurs appels de fonction avec des arguments valide
Chaîne de fonction
void a(int a1, int a2, int a3) {}
void b() {}
void c(int c1, int c2) {}
8048455: 83 c4 0c add esp,0xc 8048458: 5b pop ebx
8048459: 5e pop esi
804845a: 5f pop edi
804845b: 5d pop ebp
804845c: c3 ret
Objectif: Exécuter les fonctions dans l'ordre suivant:
- a(1,2,3);
- b();
- c(4,5);
Trouver les Gadgets
- https://github.com/JonathanSalwan/ROPgadget
- Logiciel de recherche de Gadget ROP
- ./ROPGadget --binary your_bin
- Permet même de générer un ROP pour
execve('/bin/sh', 0, 0); - ./ROPGadget --binary your_bin --ropchain
Limitation
- Executable ASLR (fPIE)
- Leak une adresse ou .PLT table
- Peu de gadget disponible
- Linked library! Libc is big...
pwntools
Suite d'outils en python très complète fais spécialement pour les CTFs et l'exploit
https://github.com/Gallopsled/pwntools
pwntools
Code de base
from pwn import *
context(arch = 'amd64', os = 'linux')
r = remote('192.168.4.178', 1239)
data = r.readline() # Réception
r.send(data) # Envoie
r.interactive() # Le terminal devient l'entrée et la sortie
Question?
Action!
Baby step: Dump ./flag.txt
Bonus: Pop a shell
Exploitation 101 - 2016
By Israel Hallé
Exploitation 101 - 2016
- 2,233