Root-Me: ExploitMe – Depășire de buffer de bază
- 2 minute de citit
- 6 exemple de cod
- 2 imagini
Disponibil și în English
Salut,
În acest articol îți prezint soluția la o provocare de cracking scurtă și plăcută de la Root-Me. După ce am deschis-o în Ghidra, am văzut că provocarea este ușor de rezolvat, tot ce trebuie să faci este să găsești parola, care este în text clar. În esență doar copiezi și lipești și obții flag-ul, dar stai, există o întorsătură!
Ar fi trebuit să învăț din lecția celeilalte provocări de la Root-Me, care avea și ea o întorsătură.
Mi-e rușine că nu am observat asta, la fel ca parola, totul era la vedere 🙁
Vezi ce vreau să spun?
function_ptr.2175 este un pointer către o funcție, iar în main-ul programului este făcut să indice spre adresa lui auth, după care este apelat.
0804869e b8 f4 86 MOV dest,auth 04 08 080486a3 a3 f4 a0 MOV [function_ptr.2175],dest = 00000000 04 08Și, dacă inspectăm funcția auth, vedem că apelează funcția _asm_ dacă parola furnizată se potrivește.
cmp_ret = strcmp(buff,dest);<br></br> if (cmp_ret == 0) {<br></br> _asm_();<br></br> }Putem introduce parola corectă și obținem flag-ul, asta am făcut eu la început, sau putem face un exploit simplu de tip buffer overflow ca să forțăm programul să apeleze direct funcția _asm_.
Pointerul la funcție și buffer-ul se află în secțiunea .bss a binarului. Secțiunea .bss conține obiecte neinițializate, în cazul nostru variabilele globale și statice.
Compilatorul a decis, nu știu cum, să plaseze pointerul la funcție imediat după buffer, buffer-ul pe care se execută următoarea linie de cod:
strcpy(buffer.2176,argv[1]);Buffer-ul are doar 146 de octeți, iar de la poziția 146+2 începe pointerul la funcție, ceea ce înseamnă că putem controla ce se scrie în pointerul la funcție dacă reușim să depășim buffer-ul.
Putem face asta, pentru că strcpy continuă să copieze valori în buffer până când întâlnește caracterul de terminare NULL.
Acum trebuie să aflăm adresa funcției _asm_. Aceasta se poate găsi ușor. Fie te uiți la vizualizarea din dezasamblor, fie folosești unealta nm.
➜ /vagrant nm Exploit_Me(if_you_can)<br></br> 08048731 T <em>asm</em>Dacă construim un payload care scrie „x” de 148 de ori ca să depășească buffer-ul și apoi adăugăm la el adresa lui _asm_, exploatăm cu succes binarul:
➜ /vagrant ./Exploit_Me(if_you_can) $(python -c "print('x'*148+'\x31\x87\x04\x08')")<br></br> [+] Felicitation password de validation de l'épreuve:: <redacted>- $() – pornește un shell nou
- python -c “..” parsează programul ca șir de caractere
Binarul ./Exploit_Me(if_you_can) primește rezultatul ca primul argument și gata! Buffer-ul se depășește, pointerul la funcție este suprascris, iar programul execută _asm_ în loc de auth.
function_ptr.2175 = auth; # Dacă ar fi fost după strcpy, lucrurile ar fi stat altfel.<br></br>strcpy(buffer.2176,argv[1]);<br></br>*(undefined *)((int)dest + 8) = '_';<br></br>*(undefined *)((int)dest + 9) = '.';<br></br>iVar1 = (*(code *)function_ptr.2175)(buffer.2176,dest);Dacă te întrebi de ce adresa asm este scrisă ca ‘\x31\x87\x04\x08’, este pentru că o vrem în format little-endian. În big endian, adresa este 0x08048731.
Funcția _asm_ este destul de complicată, decriptează flag-ul, iar magia aici este că nu depinde de starea programului sau de vreun argument, deci dacă reușim s-o executăm, obținem flag-ul direct.
Această provocare se poate rezolva și în alte moduri, verifică soluțiile de pe Root-Me pentru moduri mai creative de a rezolva acest crackme.
Mulțumesc că ai citit!