Scrieți un atac pentru programul dat. Întrucât pe calculatoarele din laborator, sistemele prezintă stivă neexecutabilă, protecție a stivei cu canar, și dispunere preventivă a variabilelor locale sub vârful stivei, cu pointerii înaintea tablourilor care ar putea avea depășiri, vom folosi un atac care modifică tabela de indirectare pentru funcții de bibliotecă (Global Offset Table), înlocuind un apel la printf cu un apel la system. Un astfel de atac e descris aici.
Pe scurt, apelurile la funcțiile standard de bibliotecă se fac cu indirectare, pentru a permite legarea dinamică (în momentul compilării programului nu se știu adresele la care vor fi localizate în memorie funcțiile de bibliotecă).
încărcăm codul programului vulnerabil în memorie cu depanatorul:
gdb nume_executabil
și îl examinăm:
disas main
Observăm apeluri de forma:
call 0x8048440 <printf@plt>
Continuăm și examinăm codul de la adresa respectivă (PLT = procedure linkage table):
disas 0x804844
vom remarca o instrucțiune de tipul
jmp *0x8049918 (modul de adresare diferă de la 32 la 64 de biți)
iar examinând locația respectivă:
x/a 0x8049914 0x8049914 <_GLOBAL_OFFSET_TABLE_+44> 0x8048446 <printf@plt+6>Deci, avem întâi un apel obișnuit (printf@plt), iar apoi un salt la conținutul unei intrări într-un tabel de adrese. Dacă modificăm conținutul acestei intrări, se va executa alt cod !
Ca explicație în paranteză, înainte de primul apel la funcție, intrarea din GOT indică spre codul care rezolvă (la rulare) referința la funcție, identificând locul unde e încărcată în memorie, și apoi suprascrie intrarea cu adresa găsită, care va fi folosită pentru următoarele apeluri.
Pentru a ataca programul, trebuie să:
-- identificăm intrarea GOT corespunzătoare funcției printf
-- o suprascriem cu conținutul pentru funcția system (inițial,
system@plt+6, după cum remarcăm prin examinare).
Aceste două valori numerice le obținem cu depanatorul și le folosim
în programul de atac.
Pentru aceasta, trebuie să identificăm în programul vulnerabil:
-- un fragment de cod prin care putem suprascrie un pointer (pe care îl facem să indice intrarea GOT pentru printf)
-- un alt fragment prin care să putem scrie valoarea dorită la acel
pointer, în acest caz, system+6 (sau chiar system).