This shows you the differences between two versions of the page.
so:curs:mem-sec [2020/04/04 15:28] razvan.deaconescu |
so:curs:mem-sec [2020/04/06 17:33] (current) alexandru.radovici |
||
---|---|---|---|
Line 16: | Line 16: | ||
* Filmări | * Filmări | ||
+ | * 3CA [[https://web.microsoftstream.com/video/631f6edd-2f5b-474e-9f87-ae4edecbd93d]] | ||
* 3CC, curs 11, partea 1: https://web.microsoftstream.com/video/ff52e02f-c2dc-49d6-b227-2dc9a1026625 | * 3CC, curs 11, partea 1: https://web.microsoftstream.com/video/ff52e02f-c2dc-49d6-b227-2dc9a1026625 | ||
* 3CC, curs 11, partea a 2-a: https://web.microsoftstream.com/video/7bae5cdb-0a54-4f2e-b5a5-df039790ac37 | * 3CC, curs 11, partea a 2-a: https://web.microsoftstream.com/video/7bae5cdb-0a54-4f2e-b5a5-df039790ac37 | ||
+ | | ||
+ | * Curs CA [[https://www.slideshare.net/alexandruradovici/sisteme-de-operare-securitatea-memoriei|slideshare]] | ||
===== Demo-uri ===== | ===== Demo-uri ===== | ||
Line 123: | Line 126: | ||
<code> | <code> | ||
- | $ python payloads.py | + | $ python3 payloads.py |
overwrite func_ptr (32 bits): \x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x5f\x85\x04\x08 | overwrite func_ptr (32 bits): \x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x5f\x85\x04\x08 | ||
overwrite return address (32 bits): \x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x46\x85\x04\x08\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x5f\x85\x04\x08 | overwrite return address (32 bits): \x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x46\x85\x04\x08\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x5f\x85\x04\x08 | ||
Line 254: | Line 257: | ||
<code> | <code> | ||
- | $ checksec buffer-overflow | + | $ wget https://raw.githubusercontent.com/slimm609/checksec.sh/master/checksec |
- | [*] '/home/razvan/school/so/git-repos/curs.git/curs-07-demo/buffer-overflow/buffer-overflow' | + | [...] |
- | Arch: amd64-64-little | + | |
- | RELRO: Partial RELRO | + | $ chmod a+x checksec |
- | Stack: No canary found | + | |
- | NX: NX enabled | + | $ ./checksec --file=buffer-overflow |
- | PIE: No PIE (0x400000) | + | RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE |
- | $ checksec buffer-overflow-pie | + | Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 75 Symbols No 0 3 buffer-overflow |
- | [*] '/home/razvan/school/so/git-repos/curs.git/curs-07-demo/buffer-overflow/buffer-overflow-pie' | + | |
- | Arch: amd64-64-little | + | $ ./checksec --file=buffer-overflow-pie |
- | RELRO: Full RELRO | + | RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE |
- | Stack: No canary found | + | Full RELRO No canary found NX enabled PIE enabled No RPATH No RUNPATH 77 Symbols No 0 3 buffer-overflow-pie |
- | NX: NX enabled | + | |
- | PIE: PIE enabled | + | $ ./checksec --file=buffer-overflow-ssp |
- | $ checksec buffer-overflow-ssp | + | RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE |
- | [*] '/home/razvan/school/so/git-repos/curs.git/curs-07-demo/buffer-overflow/buffer-overflow-ssp' | + | Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH 76 Symbols Yes 0 3 buffer-overflow-ssp |
- | Arch: amd64-64-little | + | |
- | RELRO: Partial RELRO | + | |
- | Stack: Canary found | + | |
- | NX: NX enabled | + | |
- | PIE: No PIE (0x400000) | + | |
</code> | </code> | ||
==== Injectarea codului. Shellcodes ==== | ==== Injectarea codului. Shellcodes ==== | ||
+ | |||
+ | <note important> | ||
+ | Pentru acest demo trebuie să aveți instalat pe sistem asamblorul NASM. Pe un sistem Debian/Ubuntu îl puteți instala folosind comanda: | ||
+ | <code> | ||
+ | sudo apt install nasm | ||
+ | </code> | ||
+ | </note> | ||
În exploit-urile prezentate mai sus am suprascris code pointeri și am modificat fluxul de execuție al programului apelând o funcție existentă (''inject_func''). Această metodă, de refolosire a codului existent în cadrul unui atac, poartă numele de //code reuse attacks//. Din păcate pentru atacator, în cazul unui atac de tipul //code reuse// spațiul posibil de acțiune este limitat la codul existent. Așa că este de preferat un atac de tipul //code injection// care adaugă (injectează) cod în spațiul virtual de adrese al procesului. În general acest cod rezidă într-o zonă de date (unde este citit) care primește permisiuni de execuție. | În exploit-urile prezentate mai sus am suprascris code pointeri și am modificat fluxul de execuție al programului apelând o funcție existentă (''inject_func''). Această metodă, de refolosire a codului existent în cadrul unui atac, poartă numele de //code reuse attacks//. Din păcate pentru atacator, în cazul unui atac de tipul //code reuse// spațiul posibil de acțiune este limitat la codul existent. Așa că este de preferat un atac de tipul //code injection// care adaugă (injectează) cod în spațiul virtual de adrese al procesului. În general acest cod rezidă într-o zonă de date (unde este citit) care primește permisiuni de execuție. | ||
Line 390: | Line 395: | ||
Programul este compilat cu suport de //Stack Smashing Protection// care plasează stack canary pe stivă în funcția ''process_client()''. Opțiunea de compilare ''-fstack-protector'' este adăugată în fișierul ''Makefile'': | Programul este compilat cu suport de //Stack Smashing Protection// care plasează stack canary pe stivă în funcția ''process_client()''. Opțiunea de compilare ''-fstack-protector'' este adăugată în fișierul ''Makefile'': | ||
<code> | <code> | ||
- | CFLAGS = -Wall -Wextra -g -fstack-protector -fno-PIC | + | CFLAGS = -Wall -Wextra -Wno-unused-function -g -fstack-protector -fno-PIC |
</code> | </code> | ||
Line 433: | Line 438: | ||
Știm că adresa de retur se găsește pe stivă la adresa ''rbp+0x8''. | Știm că adresa de retur se găsește pe stivă la adresa ''rbp+0x8''. | ||
- | În realizarea atacului, ținem cont că la ''fork()'' (modul de tratare a conexiunilor în implementarea ''socket_ssp.c'') se păstrează spațiul de adresă al procesului, se vor păstra și //stack canary//. Așa că le putem suprascrie din clientul TCP octet cu octet până nimerim valoarea acelui octet, conform algoritmului: | + | În realizarea atacului, ținem cont că la ''fork()'' (modul de tratare a conexiunilor în implementarea ''socket_ssp.c'') se păstrează spațiul de adresă al procesului, se vor păstra și //stack canary//. Așa că le putem suprascrie din clientul TCP octet cu octet până nimerim valoarea acelui octet, conform algoritmului: \\ |
- | 1. Creăm un mesaj care supascrie doar un octet din //canary value//: umplem spațiul de la buffer la //stack canary// și adăugăm un octet. | + | 1. Creăm un mesaj care supascrie doar un octet din //canary value//: umplem spațiul de la buffer la //stack canary// și adăugăm un octet. \\ |
- | 2. Trimitem mesajul pe rețea. | + | 2. Trimitem mesajul pe rețea. \\ |
- | 3. Dacă valoarea nu este cea corectă, procesul copil creat se va încheia cu segmentation fault și conexiune se va încheia. Dacă așa a fost, creștem valoarea cu 1 și încercăm din nou pasul 2. | + | 3. Dacă valoarea nu este cea corectă, procesul copil creat se va încheia cu segmentation fault și conexiune se va încheia. Dacă așa a fost, creștem valoarea cu 1 și încercăm din nou pasul 2. \\ |
- | 3'. Când nimerim o valoare, programul nu va genera eroare de tipul //stack smashing detection//. Se va încheia cu succes, va întoarce mesaj pe rețea și atunci știm că am nimerit octetul și trecem la următorul. | + | 3'. Când nimerim o valoare, programul nu va genera eroare de tipul //stack smashing detection//. Se va încheia cu succes, va întoarce mesaj pe rețea și atunci știm că am nimerit octetul și trecem la următorul.\\ |
- | 4. O dată descoperit un nou octet, mărim mesajul cu un nou octet și trecem la pasul 2. | + | 4. O dată descoperit un nou octet, mărim mesajul cu un nou octet și trecem la pasul 2. |
Atacul este descris în fișierul ''exploit.py''. Pentru a realiza atacul, avem nevoie de două console: una pe care pornim serverul și una pe care pornim exploit-ul care va crea clienți pentru server. Pornim serverul pe o consolă: | Atacul este descris în fișierul ''exploit.py''. Pentru a realiza atacul, avem nevoie de două console: una pe care pornim serverul și una pe care pornim exploit-ul care va crea clienți pentru server. Pornim serverul pe o consolă: | ||
Line 447: | Line 452: | ||
și atacul pe altă consolă. Atacul va dura să treacă prin toți octeții și să creeze un proces pentru fiecare socket. În final atacul va reuși și vom apela funcția ''inject_func()''. Un exemplu de atac este prezentat în fișierul ''result.txt'': | și atacul pe altă consolă. Atacul va dura să treacă prin toți octeții și să creeze un proces pentru fiecare socket. În final atacul va reuși și vom apela funcția ''inject_func()''. Un exemplu de atac este prezentat în fișierul ''result.txt'': | ||
<code> | <code> | ||
- | $ python exploit.py | + | $ python3 exploit.py |
Canary byte 0 is 0x00 | Canary byte 0 is 0x00 | ||
Canary byte 1 is 0x0c | Canary byte 1 is 0x0c |