Reversing pe HackTheBox: Impossible Password

  • 3 minute de citit
  • 1 exemplu de cod
  • 4 imagini

Disponibil și în English

Salut, acesta este un write-up despre provocarea de reversing de pe HackTheBox: Impossible Password.

Te rog nu te uita la soluție dacă nu ai încercat încă provocarea, îți strică toată distracția. Încearcă mai întâi să o rezolvi singur, petrece câteva ore pe ea, nu este chiar atât de grea.

Sunt și eu începător în RE. Iată câteva indicii care te pot ajuta să începi:

Bine, deci, să rezolvăm asta.

Voi folosi dezasamblorul Binary Ninja pentru a rezolva provocarea, nu am bani pentru IDA. q.q (sigur că aș putea folosi IDA free)

Screen Shot 2018-07-14 at 23.12.51.png

După cum se vede în captura de ecran, există un call printf la adresa 0x004008ce, dar înainte de asta există o instrucțiune mov cu destinația EDI. Dacă faci dublu clic pe adresa sursă: 0x400a7f, vei vedea că indică spre caracterul *. Acesta este afișat când rulezi binarul pentru prima dată:Screen Shot 2018-07-14 at 23.15.24.png

Mie mi-e clar că EDI este parametrul transmis lui printf, dar nu sunt sigur de ce este transmis prin registrul EDI. După ce am căutat puțin pe Google, am aflat convenția de apel folosită de acest binar:

Convenția de apel a System V AMD64ABI este urmată pe Solaris, Linux, FreeBSD, macOS, [18] și este standardul de facto în sistemele Unix și asemănătoare Unix. Primele șase argumente întregi sau pointer sunt transmise în registrele RDI, RSI, RDX, RCX […]

Acum că știm convenția de apel, este mai ușor să înțelegem cum sunt apelate funcțiile. După printf, se face un apel către scanf.

Scanf are următorul prototip de funcție:

int scanf(const char *format, ...);

Uitându-ne la dezasamblare, vedem că EDI conține șirul de format, iar RSI (care este versiunea de 64 de biți a registrului ESI) conține adresa bufferului (l-am numit scanf_input). Următorul lucru pe care îl face programul este să afișeze pe ecran conținutul bufferului scanf_input.

  • Reține că șirul de format „%20s” înseamnă citirea a cel mult 20 de caractere.

Screen Shot 2018-07-14 at 23.23.23.png

Urmează un apel către strcmp.

Se pare că intrarea din scanf este comparată cu cheia: „SuperSeKretKey”. Acesta este primul șir pe care trebuie să-l introducem ca să trecem de partea 1.

Acum, să ne uităm la a doua parte și să vedem ce putem deduce de aici:

Screen Shot 2018-07-14 at 23.25.47.png

  1. Programul afișează asteriscul.
  2. Citește încă 20 de caractere în input_buffer.
  3. Returnează un input_buffer modificat, în funcția generate_second.
  4. Valoarea returnată este comparată cu input_buffer.
  5. Funcția finish_it este apelată la final.

Nu am vrut să fac reversing la funcția generate_second și la funcția finish_it, în cazul acesta nici nu este nevoie.

Poți, totuși, obține flag-ul făcând reversing la funcția finish_it și transmițându-i următorul parametru: „A]Kr=9k0=0o0;kl1?k81t”, care se găsește la începutul funcției main.

O cale mai ușoară, și cea pe care am folosit-o eu, este să modifici binarul la linia 0x0040095e astfel încât să muți RSI în RDI; în acest fel, strcmp va fi apelat cu: strcmp( RSI, RSI ) (cred că ai putea și să modifici saltul).

După ce facem asta, fluxul de execuție se schimbă și se execută finish_it, care afișează flag-ul.

Ca să ajung la această concluzie, a trebuit să mă uit la program cu edb-debugger și să parcurg funcția finish_it. La început nu am fost destul de atent și am crezut că finish_it primește un pointer către bufferul de intrare, dar, de fapt, primește un pointer către un șir pe care îl avem deja. Pe curând!

PS: Poate actualizez articolul ca să includ codul reversat al funcției finish_it, doar ca distracție.

PSS: Îmi dau seama că nu ar fi trebuit să public acest write-up, pentru că provocarea este încă activă, îmi pare rău.