Skip to content

Ingenuity-Fainting-Goats/Binary-Exploiting-101

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

File ELF

Organizzazione della Memoria di un Processo x86

La memoria dei processi in esecuzione è suddivisa in

  • sezioni
  • segmenti

Diversi segmenti contengono diversi tipi di dato che vengono initializzati in fase di load in memoria

  • init = Contiene il codice di inizializzazione del programma che viene eseguito all'avvio, prima del `main()``
  • PLT = Procedure Linkage Table, serve per gestire le chiamate a funzione di di libreria
  • text = Contiene codice eseguibile del programma
  • fini = Come init, codice eseguito al termine del programma
  • rodata = Read Only Data, contiene le variabili globali o statiche dichiarate come const
  • eh_frame = Contiene i puntatori ad Exception handler ( solo linguaggi supportati )
  • data = contiene le variabili globali e/o statiche inizializzate
  • ctors = Contiene puntatori alle funzioni con attributo constructor
  • dtors = Contiene puntatori alle funzioni con attributo distructor
  • GOT = Global Offset Table, assieme alla sezione PLT è utilizzata per gestire le chiamate alle funzioni di libreria.
  • BSS = Contiene le variabili globali e/o statiche non inizializzate. All'inizio tutta l'area d memoria è impostata a zero
  • Heap = è una sezione dinamica, contiene memoria allocata tramite malloc() &c. Cresce verso indirizzi di memoria alti
  • Stack = è una sezione di memoria dinamica, organizzata secondo LIFO. Cresce da indirizzi alti verso indirizzi bassi.

< inserire qui immagine >

Informazioni memoria di un eseguibile

tramite comando objdump è possibile ottenere informazioni dettagliate dei file eseguili ad esempio i flag ( i flag sono il motivo per il quale la memoria è divisa in sezioni e segmenti in modo da associare flag differenti +r,+w,+rw etc).

objdump -h helloworld

helloworld:     formato del file elf64-x86-64

Sezioni:
Ind Nome          Dimens    VMA               LMA               Pos file  Allin
0 .interp       0000001c  0000000000400238  0000000000400238  00000238  2**0
                CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020  0000000000400254  0000000000400254  00000254  2**2

                CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.gnu.build-id 00000024  0000000000400274  0000000000400274  00000274  2**2
                CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .gnu.hash     0000001c  0000000000400298  0000000000400298  00000298  2**3
                CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .dynsym       00000048  00000000004002b8  00000000004002b8  000002b8  2**3
                CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynstr       00000038  0000000000400300  0000000000400300  00000300  2**0
                CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .gnu.version  00000006  0000000000400338  0000000000400338  00000338  2**1
                CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version_r 00000020  0000000000400340  0000000000400340  00000340  2**3
              CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .rela.dyn     00000018  0000000000400360  0000000000400360  00000360  2**3
              CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rela.plt     00000018  0000000000400378  0000000000400378  00000378  2**3
              CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .init         0000001a  0000000000400390  0000000000400390  00000390  2**2
              CONTENTS, ALLOC, LOAD, READONLY, CODE
11 .plt          00000020  00000000004003b0  00000000004003b0  000003b0  2**4
              CONTENTS, ALLOC, LOAD, READONLY, CODE

12 .plt.got      00000008  00000000004003d0  00000000004003d0  000003d0  2**3
              CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .text         00000182  00000000004003e0  00000000004003e0  000003e0  2**4
              CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .fini         00000009  0000000000400564  0000000000400564  00000564  2**2
              CONTENTS, ALLOC, LOAD, READONLY, CODE
15 .rodata       00000004  0000000000400570  0000000000400570  00000570  2**2
                CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .eh_frame_hdr 00000034  0000000000400574  0000000000400574  00000574  2**2
                CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .eh_frame     000000f4  00000000004005a8   00005a8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
18 .init_array   00000008  0000000000600e10  0000000000600e10  00000e10  2**3
                CONTENTS, ALLOC, LOAD, DATA
19 .fini_array   00000008  0000000000600e18  0000000000600e18  00000e18  2**3
              CONTENTS, ALLOC, LOAD, DATA
20 .jcr          00000008  0000000000600e20  0000000000600e20  00000e20  2**3
              CONTENTS, ALLOC, LOAD, DATA
21 .dynamic      000001d0  0000000000600e28  0000000000600e28  00000e28  2**3
            CONTENTS, ALLOC, LOAD, DATA
22 .got          00000008  0000000000600ff8  0000000000600ff8  00000ff8  2**3
            CONTENTS, ALLOC, LOAD, DATA
23 .got.plt      00000020  0000000000601000  0000000000601000  00001000  2**3
            CONTENTS, ALLOC, LOAD, DATA
24 .data         00000010  0000000000601020  0000000000601020  00001020  2**3
            CONTENTS, ALLOC, LOAD, DATA
25 .bss          00000008  0000000000601030  0000000000601030  00001030  2**0
            ALLOC
26 .comment      00000034  0000000000000000  0000000000000000  00001030  2**0
          CONTENTS, READONLY

Sezioni PLT e GOT

Sezioni utilizzate per gestire librerie condivise ( libc per funzioni come printf ) le librerie vengono caricate in memoria quando il primo programma ne richiedere l'utilizzo e il codice viene posto in condivisione con tutti i programmi che in un momento successivo le richiedono. Servono meccanismi per detectare se:

  • individuare se libreria è già caricata
  • trovare indirizzo da utilizzare

PLT = contiene codice eseguibile e ha atributo di sola lettura GOT = contiene solamente dati

Tramite comando objdump -d helloworld

Disassemblamento della sezione .plt.got:
0000000000400420 <.plt.got>:
  400420:	ff 25 d2 0b 20 00    	jmpq   *0x200bd2(%rip)        # 600ff8 <_DYNAMIC+0x1d0>
  400426:	66 90                	xchg   %ax,%ax


Disassemblamento della sezione .plt:

00000000004003f0 <printf@plt-0x10>:
  4003f0:	ff 35 12 0c 20 00    	pushq  0x200c12(%rip)        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
  4003f6:	ff 25 14 0c 20 00    	jmpq   *0x200c14(%rip)        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
  4003fc:	0f 1f 40 00          	nopl   0x0(%rax)

0000000000400400 <printf@plt>:
  400400:	ff 25 12 0c 20 00    	jmpq   *0x200c12(%rip)        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
  400406:	68 00 00 00 00       	pushq  $0x0
  40040b:	e9 e0 ff ff ff       	jmpq   4003f0 <_init+0x28>

0000000000400410 <__libc_start_main@plt>:
  400410:	ff 25 0a 0c 20 00    	jmpq   *0x200c0a(%rip)        # 601020 <_GLOBAL_OFFSET_TABLE_+0x20>
  400416:	68 01 00 00 00       	pushq  $0x1
  40041b:	e9 d0 ff ff ff       	jmpq   4003f0 <_init+0x28>

Disassemblamento della sezione .plt.got:

0000000000400420 <.plt.got>:
  400420:	ff 25 d2 0b 20 00    	jmpq   *0x200bd2(%rip)        # 600ff8 <_DYNAMIC+0x1d0>
  400426:	66 90                	xchg   %ax,%ax
...
0000000000400526 <main>:
  400526:	55                   	push   %rbp
  400527:	48 89 e5             	mov    %rsp,%rbp
  40052a:	bf c4 05 40 00       	mov    $0x4005c4,%edi
  40052f:	b8 00 00 00 00       	mov    $0x0,%eax
  400534:	e8 c7 fe ff ff       	callq  400400 <printf@plt>
  400539:	b8 00 00 00 00       	mov    $0x0,%eax
  40053e:	5d                   	pop    %rbp
  40053f:	c3                   	retq   

Si nota nella sezione main offset 400534 sia effettuata callq alla funzione printf@plt nella sezione PLT all'indirizzo 400400 che successivamente viene avviato il controllo all'indirizzo contenuto in *0x200c12(%rip) che rappresenta un indirizzo in <_GLOBAL_OFFSET_TABLE_+0x18> caricato dalla libc, questo perchè la libreria era già caricata e quindi non ha avuto necessità di recuperare nuovi indirizzi.

https://www.codeproject.com/Articles/70302/Redirecting-functions-in-shared-ELF-libraries

Sezione Data

Sono contenute le variabili globali e statiche inizializzate. File: static1.c Per visualizzare tale sezione si utilizza il seguente comando objdump -s -j .data static1

static1:     formato del file elf64-x86-64

Contenuto della sezione .data:
 601020 00000000 00000000 00000000 00000000  ................
 601030 41                                   A      

41 rappresenta il valore hex del carattere A

Sezione CTORS DTORS

File: ctors_dtors1.c Le funzioni constructor sono eseguite prima della funzione main(), mentre deconstructor dopo. Queste sezioni contengono i puntatori alle funzione dichiarate, per visualizzare tali puntatori comando objdump -s -j .ctors -j .dtors ctors_dtors1 che però non mostra nulla perchè può dipendere dal compilatore come rinomina tali sezioni, ad esempio tramite il comando readelf -S ctors_dtors1 possiamo visualizzare i campi:

  • init_array
  • fini_array
[19] .init_array       INIT_ARRAY       0000000000600e00  00000e00
     0000000000000010  0000000000000000  WA       0     0     8
[20] .fini_array       FINI_ARRAY       0000000000600e10  00000e10
     0000000000000010  0000000000000000  WA       0     0     8

per approfondire le sezioni si visualizza objdump -s ctors_dtors1

0000000000400520 <__do_global_dtors_aux>:
  400520:	80 3d 19 0b 20 00 00 	cmpb   $0x0,0x200b19(%rip)        # 601040 <__TMC_END__>
  400527:	75 11                	jne    40053a <__do_global_dtors_aux+0x1a>
  400529:	55                   	push   %rbp
  40052a:	48 89 e5             	mov    %rsp,%rbp
  40052d:	e8 6e ff ff ff       	callq  4004a0 <deregister_tm_clones>
  400532:	5d                   	pop    %rbp
  400533:	c6 05 06 0b 20 00 01 	movb   $0x1,0x200b06(%rip)        # 601040 <__TMC_END__>
  40053a:	f3 c3                	repz retq
  40053c:	0f 1f 40 00          	nopl   0x0(%rax)

oppure tramite objdump -x ctors_dtors1

0000000000400520 l     F .text	0000000000000000              __do_global_dtors_aux

Queste sezioni sono utili per implementare tecniche anti debugging e packer per spacchettare codice a runtime criptato e pacchettizato, ftp://hackbbs.org/milworm/9

Sezione BBS

Contiene variabili globali e statiche non inizializzate, non esiste un'immagine della sezione BSS nel file eseguibile, viene creata al momento dell'esecuzione del programma e le variabili presenti al suo interno sono inizializzate con byte NULL. File: bss1.c Tramite il comando objdump -x bss1 è possibile verificare la dimensione 0x40 ( 64 byte ) della sezione bbs indirizzo e offset

25 .bss          00000040  0000000000601030  0000000000601030  00001030  2**4
                 ALLOC

Mentre tramite il comando objdump -t bss1 | grep bss si ottiene output con le dimensioni delle singole variabili presenti nella sezione BBS, rispettivamente:

  • a = 0x10 = 16 byte (array char) -> indirizzo 0x0000000000601060
  • b = 0x10 = 16 byte (array char ) -> indirizzo 0x0000000000601050
  • c = 0x4 = 4 byte ( intero ) -> indirizzo 0x0000000000601040
objdump -t bss1 | grep bss
bss1:     formato del file elf64-x86-64
0000000000601030 l    d  .bss	0000000000000000              .bss
0000000000601030 l     O .bss	0000000000000001              completed.7585
0000000000000000 l    df *ABS*	0000000000000000              bss1.c
0000000000601040 l     O .bss	0000000000000004              c.1834
0000000000601050 l     O .bss	0000000000000010              b.1833
0000000000601070 g       .bss	0000000000000000              _end
0000000000601060 g     O .bss	0000000000000010              a
0000000000601030 g       .bss	0000000000000000              __bss_start

Tramite debugger gdb possiamo verificare che i dati siano effettivamente inizializzati a NULL 0x00 tramite i seguenti comandi

  • gdb bss <- avvio gdb sul binario
  • b main <- setto breakpoint esecuzione funzione main()
  • x/60b 0x0000000000601030 <- visualizza il contenuto della memoria all'indirizzo richiesto x per 64 elementi mostrati come formato byte

http://visualgdb.com/gdbreference/commands/x

gdb bss1
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from bss1...(no debugging symbols found)...done.
(gdb) b main
Breakpoint 1 at 0x4004da
(gdb) r
Starting program: /home/rhpco/PROJECT/exploiting/lab1/ale/bss1

Breakpoint 1, 0x00000000004004da in main ()
(gdb) x/64x 0x0000000000601030
0x601030 <completed.7585>:	0x00000000	0x00000000	0x00000000	0x00000000
0x601040 <c.1834>:	0x00000000	0x00000000	0x00000000	0x00000000
0x601050 <b.1833>:	0x00000000	0x00000000	0x00000000	0x00000000
0x601060 <a>:	0x00000000	0x00000000	0x00000000	0x00000000
0x601070:	0x00000000	0x00000000	0x00000000	0x00000000
0x601080:	0x00000000	0x00000000	0x00000000	0x00000000
0x601090:	0x00000000	0x00000000	0x00000000	0x00000000
0x6010a0:	0x00000000	0x00000000	0x00000000	0x00000000
0x6010b0:	0x00000000	0x00000000	0x00000000	0x00000000
0x6010c0:	0x00000000	0x00000000	0x00000000	0x00000000
0x6010d0:	0x00000000	0x00000000	0x00000000	0x00000000
0x6010e0:	0x00000000	0x00000000	0x00000000	0x00000000
0x6010f0:	0x00000000	0x00000000	0x00000000	0x00000000
0x601100:	0x00000000	0x00000000	0x00000000	0x00000000
0x601110:	0x00000000	0x00000000	0x00000000	0x00000000
0x601120:	0x00000000	0x00000000	0x00000000	0x00000000
(gdb) x/64b 0x0000000000601030
0x601030 <completed.7585>:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x601038:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x601040 <c.1834>:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x601048:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x601050 <b.1833>:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x601058 <b.1833+8>:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x601060 <a>:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x601068 <a+8>:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
(gdb)

Lo Stack

Porzione memoria dinamica gestita LIFO, operazioni base:

  • push
  • pop

L'ultimo elemento inserito è memorizzato ad un indirizzo pià basso rispetto agli elementi inseriti precedentemente. Lo stack cresce da indirizzi alti verso indirizzi basi di memoria. Nello stack vengono memorizzate le seguenti informazioni:

  • i parametri passati alle funzioni
  • le variabili locali delle funzioni
  • i dati necessari per gestire le chiamate a funzione ( registri EIP, ESP, EBP )

La gestione delle funzioni è quindi strettamente legata allo Stack, ogni volta che una funzione è eseguita viene riservata una porizione di stack associata a tale funzione che servirà a contenere i dati precedenemnte elecanti. Questa porizione di Stack viene chiamata frame ed il frame associato alla singola funzione in esecuzione frame corrente, nei processori x86 i frame sono gestiti tramite due registri:

  • ESP = Extended Stack Pointer registro a 32 bit contenente l'indirizzo della cima del frame corrente, ultimo elemento occupato ( full descending g)

  • EBP = Extended Base Pointer registro a 32 bit che contiene l'indirizzo della base del frame corrente. per non far confunzione tra "base" e "cima" si ricordi che lo stack cresce verso il basso e che quindi ESP contiene sempre un indirizzo <= a EBP.

  • EIP = Extendend Instruction Pointer registro a 32bit che contiene l'indirizzo della prossima instruzione da eseguire.

Ogni volta che si esegue una funzione viene ceato un nuovo frame. Prima di crearlo però vengono salvati i riferimenti del frame precednente in modo da poterlo ripristinare ( il frame in corso ) una volta che la funzione avrà terminato la sua esecuzione.

Di fatto il registro EBP viene utilizzato come frame pointer della funzione corrente, ovvero punta al primo elemento del frame, è possibile indirizzare le variabili locali ( locali del frame quindi della funzione in esecuzione in corso ) sommando a EBP un indirizzo di Offset.

Il processore ha istruzioni dedicate alla gestione dello Stack:

  • PUSH = inserisce un elemnto sulla cima dello stack e decrementa ( perchè cresce verso il basso ) il registro ESP del numero di byte inseriti.
  • POP = preleva un elemento dalla cima dello Stack, salvandolo in un registro e incrementa il registro ESP
  • CALL = esegue una funzione, per farlo salva il valore del registro EIP sullo stack e passa il controllo alla prima istruzione della nuova funzione chiamata. L'elemento salvato sullo Stack è chiamato indirizzo di ritorno o Activation Record
  • LEAVE = copia il EBP in ESP poi ripristina l'ultimo EBP salvato sullo stack
mov %ebp, %esp <- copia ebp in esp
pop %ebp       <- recupera ultimo valore come ebp incrementa lo esp
  • RET = è usato per il ritorno da una funzione, preleva dallo stack l'indirizzo di ritorno che era stato salvato in precedenza dall'istruzione call e lo mette in EIP equivale idealmente alla seguente operazione
pop %eip

Releases

No releases published

Packages

No packages published

Languages