Differences

This shows you the differences between two versions of the page.

Link to this comparison view

so:cursuri:curs-07 [2017/05/08 13:17]
theodor.stoican [Stiva unui proces]
so:cursuri:curs-07 [2019/04/07 10:15] (current)
razvan.deaconescu [Stack buffer overflow cu shellcode pe stivă]
Line 2: Line 2:
  
   * [[http://​elf.cs.pub.ro/​so/​res/​cursuri/​SO_Curs-07.pdf | Curs 07 - Securitatea memoriei (PDF)]]   * [[http://​elf.cs.pub.ro/​so/​res/​cursuri/​SO_Curs-07.pdf | Curs 07 - Securitatea memoriei (PDF)]]
 +
 +  * [[https://​drive.google.com/​open?​id=1I6o71Sbffo1Ucb-4i7_55UBKo0MFKyHVqDEOPr_Q5Kc|Notițe de curs]]
 +
   * Suport curs   * Suport curs
     * Modern Operating Systems, 3rd Edition     * Modern Operating Systems, 3rd Edition
Line 9: Line 12:
       * Section 0x270. Memory Segmentation       * Section 0x270. Memory Segmentation
       * Chapter 0x300. Exploitation       * Chapter 0x300. Exploitation
-    * [[http://io.smashthestack.org:84/|IO smashthestack ​wargame]] +    * [[https://io.netgarage.org|IO ​Netgarage ​wargame]] 
-    * [[http://www.phrack.org/​issues.html?​issue=49&id=14&​mode=txt| Aleph One - Smashing the Stack for Fun and Profit]] +    * [[http://​phrack.org/​issues/49/14.html|Aleph One - Smashing the Stack for Fun and Profit]] 
-    * [[http://www.cs.umd.edu/​class/​sum2003/​cmsc311/​Notes/​Mips/​stack.html|Understanding the Stack]] +    * [[http://​shell-storm.org/​shellcode/​|Shellcodes ​Database]]
-    * [[http://​repo.shell-storm.org/​shellcode/​|Shellcodes ​database]]+
     * [[http://​stackoverflow.com/​questions/​79923/​what-and-where-are-the-stack-and-heap|What and where are the stack and heap?]]     * [[http://​stackoverflow.com/​questions/​79923/​what-and-where-are-the-stack-and-heap|What and where are the stack and heap?]]
  
Line 627: Line 629:
  
 Atacurile reale trebuie să țină cont de aceste mecanisme de protecție care sunt comune pe sistemele de operare moderne. Din acest motiv atacurile sunt dificil de realizat (dar nu imposibil), lucru care face selectă populația celor care sunt capabili să genereze atacuri de exploatare a vulnerabilităților memoriei. Atacurile reale trebuie să țină cont de aceste mecanisme de protecție care sunt comune pe sistemele de operare moderne. Din acest motiv atacurile sunt dificil de realizat (dar nu imposibil), lucru care face selectă populația celor care sunt capabili să genereze atacuri de exploatare a vulnerabilităților memoriei.
 +
 +==== Atacarea Stack Smashing Protection (SSP) ====
 +
 +Dorim să atacăm mecanismul defensiv //Stack Smashing Protection//​ (SSP) care presupune plasarea unei valori predefinite pe stivă (numită //stack canary// sau //stack guard//) care detectează atacurile asupra vulnerabilităților de tip buffer overflow ce ar suprasscrie addresa de retur. Pentru aceasta accesăm subdirectorul ''​socket-ssp/''​ care creează un fork-based server, adică un server ce creează un proces pentru fiecare conexiune; această particularitate ne permite atacarea SSP permițându-ne suprascrierea adresei de retur.
 +
 +Urmărim conținutul fișierului ''​socket_ssp.c''​. În acest fișier în funcția ''​main()''​ se creează un server socket și se acceptă conexiuni de tratarea cărora se ocupă un proces copil. În funcția ''​process_client()''​ se apelează funcția ''​actual_func()''​. Obiectivul nostru este să exploatăm vulnerabilitatea de tip buffer-overflow din funcția ''​process_client()''​ pentru a suprascrie adresa de retur și a apela funcția ''​inject_func()''​.
 +
 +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>​
 +CFLAGS = -Wall -Wextra -g -fstack-protector -fno-PIC
 +</​code>​
 +
 +Compilăm programul (ignorăm warning-ul că funcția ''​inject_func()''​ nu este apelată, e utilă pentru atacul nostru):
 +<​code>​
 +$ make
 +cc -Wall -Wextra -g -fstack-protector -fno-PIC -I../​utils ​ -c -o socket_ssp.o socket_ssp.c
 +socket_ssp.c:​27:​13:​ warning: ‘inject_func’ defined but not used [-Wunused-function]
 + ​static void inject_func(void)
 +             ​^~~~~~~~~~~
 +cc -no-pie ​ socket_ssp.o ​  -o socket_ssp
 +</​code>​
 +și observăm prezența stack canary pe stivă la adresa ''​rbp-0x8''​ (în cazul nostru), poate fi altundeva în cazul vostru:
 +<​code>​
 +$ objdump -d -M intel socket_ssp | grep -A 6 '<​process_client>:'​
 +00000000004009c3 <​process_client>:​
 +  4009c3: ​      ​55 ​                     push   rbp
 +  4009c4: ​      48 89 e5                mov    rbp,rsp
 +  4009c7: ​      48 83 ec 20             ​sub ​   rsp,0x20
 +  4009cb: ​      64 48 8b 04 25 28 00    mov    rax,QWORD PTR fs:0x28
 +  4009d2: ​      00 00
 +  4009d4: ​      48 89 45 f8             ​mov ​   QWORD PTR [rbp-0x8],​rax
 +</​code>​
 +
 +Î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. Când nimerim 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.
 +
 +Atacul este descris în fișierul ''​exploit.py''​. Pentru a reuși trebuie să știm offset-ul dintre buffer și stack canary și adresa funcției ''​inject_func()''​. Ambele pot fi obținute prin dezasamblarea codului, identificarea construcției ce referă buffer-ul, valoarea stack canary și adresa funcției ''​inject_func()''​.
 +
 +De exemplu, pentru a identifica adresa buffer-ului și a stack canary urmărim dezasamblarea funcției ''​process_client()'':​
 +<​code>​
 +$ objdump -d -M intel socket_ssp | grep -A 21 '<​process_client>:'​
 +00000000004009c3 <​process_client>:​
 +  4009c3: ​      ​55 ​                     push   rbp
 +  4009c4: ​      48 89 e5                mov    rbp,rsp
 +  4009c7: ​      48 83 ec 20             ​sub ​   rsp,0x20
 +  4009cb: ​      64 48 8b 04 25 28 00    mov    rax,QWORD PTR fs:0x28
 +  4009d2: ​      00 00
 +  4009d4: ​      48 89 45 f8             ​mov ​   QWORD PTR [rbp-0x8],​rax
 +  4009d8: ​      31 c0                   ​xor ​   eax,eax
 +  4009da: ​      8b 05 ec 16 20 00       ​mov ​   eax,DWORD PTR [rip+0x2016ec] ​       # 6020cc <​connectfd>​
 +  4009e0: ​      48 8d 4d e0             ​lea ​   rcx,​[rbp-0x20]
 +  4009e4: ​      ba 64 00 00 00          mov    edx,0x64
 +  4009e9: ​      48 89 ce                mov    rsi,rcx
 +  4009ec: ​      89 c7                   ​mov ​   edi,eax
 +  4009ee: ​      e8 0d fe ff ff          call   ​400800 <​read@plt>​
 +  4009f3: ​      ​90 ​                     nop
 +  4009f4: ​      48 8b 45 f8             ​mov ​   rax,QWORD PTR [rbp-0x8]
 +  4009f8: ​      64 48 33 04 25 28 00    xor    rax,QWORD PTR fs:0x28
 +  4009ff: ​      00 00
 +  400a01: ​      74 05                   ​je ​    ​400a08 <​process_client+0x45>​
 +  400a03: ​      e8 a8 fd ff ff          call   ​4007b0 <​__stack_chk_fail@plt>​
 +  400a08: ​      ​c9 ​                     leave
 +  400a09: ​      ​c3 ​                     ret
 +</​code>​
 +Adresa buffer-ului este ''​rbp-0x20'',​ adresa stack canary este ''​rbp-0x8'',​ deci ofsset-ul este ''​0x20-0x8 = 0x18 = 24''​. Este trecută această valoare în ''​exploit.py''​
 +
 +Pentru a nu avea un executabil cu suport PIE (//Position Indenpendent Executable//​) și pentru a avea adrese fixe pentru funcțiile din cadrul executabilului,​ am folosit opțiunile corespunzătoare la compilare și linking în ''​Makefile'':​
 +<​code>​
 +CFLAGS = -Wall -Wextra -g -fstack-protector -fno-PIC
 +LDFLAGS = -no-pie
 +</​code>​
 +Adresa funcției ''​inject_func()''​ este fixă și o aflăm folosind ''​objdump'':​
 +<​code>​
 +$ objdump -d -M intel socket_ssp | grep '<​inject_func>:'​
 +00000000004009a5 <​inject_func>:​
 +</​code>​
 +La fel, adresa este trecută în ''​exploit.py''​.
 +
 +Acum putem realiza atacul. Pornim serverul pe o consolă:
 +<​code>​
 +$ ./​socket_ssp
 +
 +</​code>​
 +ș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>​
 +$ python exploit.py
 +Canary byte 0 is 0x00
 +Canary byte 1 is 0x0c
 +Canary byte 2 is 0xda
 +Canary byte 3 is 0x55
 +Canary byte 4 is 0x89
 +Canary byte 5 is 0x3c
 +Canary byte 6 is 0x40
 +Canary byte 7 is 0x71
 +Exploit result: Called injected function.
 +</​code>​
 +
so/cursuri/curs-07.1494238632.txt.gz · Last modified: 2017/05/08 13:17 by theodor.stoican
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0