User Tools

Site Tools


rev2_angr

Differences

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

Link to this comparison view

Next revision
Previous revision
rev2_angr [2025/10/30 15:53] – created mbunicrev2_angr [2025/12/01 11:40] (current) – external edit 127.0.0.1
Line 1: Line 1:
-==== Angr rješenje ====+==== Zadatak s Hacknite platforme - rev2 - rješenje pomoću alata Angr==== 
 + 
 + 
 +Prije nego što pročitate ovaj članak, preporučuje se pregled writeupa rješenja istog zadatka pomoću alata Ghidra. 
 + 
 +[[rev2_ghidra|CTF writeup - rev2-Ghidra]] 
 + 
 + 
  
 Angr je napredan i moćan alat koji se koristi za analizu binarnih izvršnih datoteka, gdje se može koristiti za reverzno inženjerstvo, automatizirano generiranje exploita, otkrivanje ranjivosti i druge namjene. Može izvršavati i statičku i dinamičku analizu, gdje je statička analiza slična kao ona koju pružaju Ghidra, Binary Ninja i slični alati, dok je dinamička analiza Angr alata njegova najjača strana. Angr je napredan i moćan alat koji se koristi za analizu binarnih izvršnih datoteka, gdje se može koristiti za reverzno inženjerstvo, automatizirano generiranje exploita, otkrivanje ranjivosti i druge namjene. Može izvršavati i statičku i dinamičku analizu, gdje je statička analiza slična kao ona koju pružaju Ghidra, Binary Ninja i slični alati, dok je dinamička analiza Angr alata njegova najjača strana.
  
-Angr pruža mogućnost tehnike simboličnog izvršavanja (symbolic execution), koja spada pod dinamičku analizu. Simbolično izvršavanje može tretirati neki korisnički unos kao neodređenu simboličnu varijablu, umjesto definirane vrijednosti, te potom tijekom rješavanja, na svakom grananju (npr. if statement), zabilježi uvjete nad simboličkom varijablom definirane za ulaz u svaku granu, i tako gradi moguće putanje izvršavanja programa. Kada nađželjenu putanju u programu, unazad riješi sve uvjete nad simboličkom varijablom, koji su potrebni da bi se program izvršio tom putanjom.+Angr pruža mogućnost tehnike simboličnog izvršavanja (symbolic execution), koja spada pod dinamičku analizu. Simbolično izvršavanje može tretirati neki korisnički unos kao neodređenu simboličnu varijablu, umjesto definirane vrijednosti. Tijekom rješavanja, na svakom grananju (npr. if statement), zabilježe se uvjeti nad simboličkom varijablom definirani za ulaz u svaku granu. Tako se grade moguće putanje izvršavanja programa. Kada je nađena željena putanja u programu, unazad se riješe svi uvjeti nad simboličkom varijablom, koji su potrebni da bi se program izvršio tom putanjom.
  
-Npr. simbolička varijabla "password" za korisnički unos u zadatku rev2, kada se dođe do prvog uvjeta koji provjerava duljinu varijable, je li jednaka 21, angr zabilježi+Npr. simbolička varijabla "password" za korisnički unos u zadatku rev2, kada se dođe do prvog uvjeta koji provjerava duljinu varijable, je li jednaka 21, Angr zabilježi
  
 <file> <file>
Line 23: Line 31:
 Efektivno, Angr alatu je samo potrebno objasniti kojoj varijabli mora naći specifičnu vrijednost i koja je željena putanja izvršavanja programa, a Angr alat sam rješava ostalo. Efektivno, Angr alatu je samo potrebno objasniti kojoj varijabli mora naći specifičnu vrijednost i koja je željena putanja izvršavanja programa, a Angr alat sam rješava ostalo.
  
-U nastavku je prikazana najjednostavnije Angr skripta koja rješava ovaj zadatak.+U nastavku je prikazana jednostavna Angr skripta koja rješava ovaj zadatak.
  
-{{ :slika27.png?nolink&500 | Slika 27 - Angr skripta - rješenje zadatka }}+<file> 
 +import angr 
 +import claripy
  
-Preporučuje se korištenje python virtual environmenta (venv) za instalaciju Angr paketa i pokretanje ove skripte.+# Otvori projekt 
 +p = angr.Project("./rev2", auto_load_libs=False) 
 + 
 +# Inicijalno stanje 
 +state = p.factory.full_init_state() 
 + 
 +# Main, instruction address prve instrukcije u mainu 
 +state.regs.rip = 0x004017e0 
 + 
 +# postavi base pointer 
 +state.regs.rbp = state.regs.rsp 
 + 
 +# Simbolicna varijabla - user input, duljina 21 bajt 
 +password = claripy.BVS("password",8*21) 
 + 
 + 
 +# preskoci fgets, manualno postavi 
 +# simbolicnu varijablu password kao unos za fgets 
 +@p.hook(0x0040186f, length = 5) 
 +def skip_fgets(state): 
 +    state.memory.store(state.regs.rsp + 0x40,password) 
 +    state.regs.rax = state.regs.rsp + 0x40 
 + 
 +# Preskoci poziv strcspn funkciju, kako ne bi 
 +# nesto krivo iz memorije procitala,  
 +# rucno postavi njezin return kao 0x15, odnosno 21 
 +# (potrebna duljina korisnickog unosa) 
 +@p.hook(0x00401887, length = 5) 
 +def skip_strcspn(state): 
 +    state.regs.rax = 0x15 
 + 
 +# Stvori simulation manager nad objektom p (rev2)  
 +# "namjesti" ga s definiranim inicijalnim stanjem 
 +sm = p.factory.simgr(state) 
 + 
 +# Pronađi putanju u kojoj će se izvršiti poziv funkcije koja ispisuje ("Correct!"
 +# 0x00401914 - instruction address poziva funkcije koja ispisuje "Correct!" 
 +sm.explore(find = 0x00401914) 
 + 
 +if sm.found: 
 +    # Ispiši pronađeno rješenje 
 +    print("Rješenje:", sm.found[0].solver.eval(password,cast_to = bytes)) 
 + 
 +else: 
 +    print("Nema rješenja!"
 + 
 +</file> 
 + 
 + 
 +Preporučuje se korištenje Python virtual environmenta (venv) za instalaciju Angr paketa i pokretanje ove skripte.
  
 Napravite novi direktorij, u njega stavite rev2 izvršnu datoteku i Python Angr skriptu, potom izvršite naredbe za postavljanje virtualnog okruženja: Napravite novi direktorij, u njega stavite rev2 izvršnu datoteku i Python Angr skriptu, potom izvršite naredbe za postavljanje virtualnog okruženja:
Line 42: Line 101:
 Pokretanjem ove skripte, Angr nalazi rješenje zadatka. Pokretanjem ove skripte, Angr nalazi rješenje zadatka.
  
-{{ :slika28.png?nolink&500 | Slika 28 - Rješenje zadatka s pomoću Angr-a }}+{{ rev2_angr:slika1.png?nolink&500 | Slika - Rješenje zadatka s pomoću Angr-a }} 
  
-Skripta prikazana na slici 27 ima komentare u kojima su objašnjenja koda, no još će dodatno biti objašnjeno kako se pronađe početna adresa i željena adresa za pronalazak, kao i dvije hook funkcije.+Skripta ima komentare u kojima su objašnjenja koda, no još će dodatno biti objašnjeno kako se pronađe početna adresa i željena adresa za pronalazak, kao i dvije hook funkcije.
  
 Na liniji koda 11, Na liniji koda 11,
Line 52: Line 112:
 </file> </file>
  
-Ova adresa je adresa prve instrukcije koja se izvršava u main funkciji, i prikazano je kako se može pronaći pomoću Ghidre na slici ispod+Ova adresa je adresa prve instrukcije koja se izvršava u main funkciji. Na slici je prikazano kako ju je moguće pronaći pomoću Ghidre
 + 
 +{{ rev2_angr:slika2.png?nolink&500 | Slika 2 - adresa prve instrukcije unutar main funkcije }}
  
-{{ :slika29.png?nolink&500 | Slika 29 - adresa prve instrukcije unutar main funkcije }} 
  
 Na liniji koda 41, Na liniji koda 41,
Line 62: Line 123:
 </file> </file>
  
-Postavlja se adresa instrukcije do koje se želi da Angr nađe put, ova adresa je adresa puts funkcije koja ispisuje "Correct!", što je ispis u slučaju kada je korisnički unos ispravan.+Postavlja se adresa ciljne instrukcije do koje se želi da Angr nađe put. Ova adresa je adresa puts funkcije koja ispisuje "Correct!", što je ispis u slučaju kada je korisnički unos ispravan.
  
 Na slici ispod je prikazano kako se može pronaći s pomoću Ghidre. Na slici ispod je prikazano kako se može pronaći s pomoću Ghidre.
  
-{{ :slika30.png?nolink&500 | Slika 30 - adresa instrukcije kojom se poziva ispis "Correct!" stringa }}+{{ rev2_angr:slika3.png?nolink&500 | Slika - adresa instrukcije kojom se poziva ispis "Correct!" stringa }} 
  
 Druga hook funkcija koja preskače strcspn funkciju definirana na liniji 31 Druga hook funkcija koja preskače strcspn funkciju definirana na liniji 31
Line 78: Line 140:
 Se postavlja, jer  strcspn funkcija čita iz memorije, no kada se koristi simbolično izvršavanje, ono što bi se pročitalo iz memorije može biti neispravno definirano, zato se "ručno" postavlja koji je željeni return te funkcije i sam poziv funkcije se preskače. Se postavlja, jer  strcspn funkcija čita iz memorije, no kada se koristi simbolično izvršavanje, ono što bi se pročitalo iz memorije može biti neispravno definirano, zato se "ručno" postavlja koji je željeni return te funkcije i sam poziv funkcije se preskače.
  
-Funkcije vračaju return vrijednost preko RAX registra, mi unaprijed znamo da ova funkcija vraća duljinu unesenog korisničkog unosa i da je željena duljina korisničkog unosa 21, odnosno 0x15 hex, zato se ovo ovom linijom postavlja željena return vrijednost+Funkcije vraćaju return vrijednost preko RAX registra, mi unaprijed znamo da ova funkcija vraća duljinu unesenog korisničkog unosa i da je željena duljina korisničkog unosa 21, odnosno 0x15 hex, zato se ovo ovom linijom postavlja željena return vrijednost
  
 <file> <file>
Line 92: Line 154:
 je adresa instrukcije koja poziva izvršavanje te funkcije, na slici ispod je prikazano kako je pronađena. je adresa instrukcije koja poziva izvršavanje te funkcije, na slici ispod je prikazano kako je pronađena.
  
-{{ :slika31.png?nolink&500 | Slika 31 - adresa instrukcije koja poziva strcspn funkciju }}+{{ rev2_angr:slika4.png?nolink&500 | Slika - adresa instrukcije koja poziva strcspn funkciju }} 
  
 Drugi argument hook funkcije, Drugi argument hook funkcije,
Line 100: Line 163:
 </file> </file>
  
-je duljina koja se se preskače, odnosno na kolikom offsetu nakon što se izvrši hook na definiranoj adresi se nastavlja izvršavanje.+je duljina bajtova koja se preskače, odnosno na kolikom offsetu nakon što se izvrši hook na definiranoj adresi se nastavlja izvršavanje.
  
-Adresa instrukcije odmah nakon adrese instrukcije poziva strscpn funkcije, je+Adresa instrukcije odmah nakon adrese instrukcije poziva strcspn funkcije, je
  
 <file> <file>
Line 108: Line 171:
 </file> </file>
  
-kao što se vidi na slici 31 (MOV instrukcija, odmah nakon CALL instrukcije koja se preskače)+kao što se vidi na slici iznad (MOV instrukcija, odmah nakon CALL instrukcije koja se preskače)
  
 <file> <file>
Line 127: Line 190:
 Argumenti hook funkcije su isti kao i u prethodnom objašnjenju, u slici ispod je prikazano gdje je definirana adresa instrukcije koja poziva izvršavanje fgets funkcije. Argumenti hook funkcije su isti kao i u prethodnom objašnjenju, u slici ispod je prikazano gdje je definirana adresa instrukcije koja poziva izvršavanje fgets funkcije.
  
-{{ :slika31.png?nolink&500 | Slika 31 - adresa instrukcije koja poziva fgets funkciju }}+{{ rev2_angr:slika5.png?nolink&500 | Slika - adresa instrukcije koja poziva fgets funkciju }} 
  
 No dio koda koji još nije jasan je sadržaj funkcije No dio koda koji još nije jasan je sadržaj funkcije
Line 146: Line 210:
 Jasno je da se simbolična varijabla password želi spremiti umjesto korisničkog unosa, pa je ona drugi argument ovog poziva, no kako pronaći adresu buffera u koji fgets funkcija sprema unos? Jasno je da se simbolična varijabla password želi spremiti umjesto korisničkog unosa, pa je ona drugi argument ovog poziva, no kako pronaći adresu buffera u koji fgets funkcija sprema unos?
  
-Prvi argument je user_input, podcrtan plavom bojom na slici 31.+Prvi argument je user_input, podcrtan plavom bojom na prethodnoj slici.
  
 Pregledom koda u prikazu dekompajlirane main funkcije vidi se linija: Pregledom koda u prikazu dekompajlirane main funkcije vidi se linija:
Line 160: Line 224:
 Na slici ispod, prikazana su oba načina. Na slici ispod, prikazana su oba načina.
  
-{{ :slika32.png?nolink&500 | Slika 32 - input_buffer adresa }}+{{ rev2_angr:slika6.png?nolink&500 | Slika - input_buffer adresa }} 
  
 Vidi se da se odmah prije poziva fgets funkcije u RDI registar kojim se prosljeđuje prvi argument, odnosno input_buffer postavlja vrijednost RBX registra, koji je ranije definiran, gdje se vidi relativna adresa RSP+0x40. Vidi se da se odmah prije poziva fgets funkcije u RDI registar kojim se prosljeđuje prvi argument, odnosno input_buffer postavlja vrijednost RBX registra, koji je ranije definiran, gdje se vidi relativna adresa RSP+0x40.
Line 174: Line 239:
 efektivno postavlja simbolična varijabla password u input_buffer. efektivno postavlja simbolična varijabla password u input_buffer.
  
-Nakon što se fgets funkcija uspješno izvrši, ona vraća pointer na buffer u koji je upisan unos, odnosno pointer na input_buffer u ovom slučaju. Pošto funkcija vraća return rezultat preko RAX registra, samo se postavlja vrijednost RAX registra na relativnu adresu input_buffera.+Nakon što se fgets funkcija uspješno izvrši, ona vraća pointer na buffer u koji je upisan unos, odnosno pointer na input_buffer u ovom slučaju. Pošto funkcija vraća return rezultat preko RAX registra, samo se postavlja vrijednost RAX registra na relativnu adresu input buffera.
  
 <file> <file>
Line 180: Line 245:
 </file> </file>
  
-Ako vas Angr alat zanima i želite i više naučiti, na slici ispod je prikaz Angr skripte koja također rješava ovaj zadatak, ali na još brži i efikasniji način.+Ako vas Angr alat zanima i želite naučiti višeu nastavku je prikaz Angr skripte koja također rješava ovaj zadatak, ali na još brži i efikasniji način. 
 + 
 + 
 +<file> 
 +import angr 
 +import claripy 
 +import logging 
 + 
 +logging.getLogger('angr.sim_manager').setLevel(logging.DEBUG) 
 + 
 +p = angr.Project("./rev2", auto_load_libs=False) 
 + 
 +state = p.factory.entry_state(addr = 0x004017e0, 
 +                            add_options = { 
 +                                angr.options.LAZY_SOLVES, 
 +                                angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY 
 +                                }) 
 + 
 + 
 +state.regs.rbp = state.regs.rsp 
 + 
 +password = claripy.BVS("password",8*21) 
 + 
 +@p.hook(0x0040185b, length = 5) 
 +def skip_print(state): 
 +    return 
 + 
 +@p.hook(0x0040186f, length = 5) 
 +def skip_fgets(state): 
 +    state.memory.store(state.regs.rsp + 0x40,password) 
 +    state.regs.rax = state.regs.rsp + 0x40 
 + 
 +@p.hook(0x00401887, length = 5) 
 +def skip_strcspn(state): 
 +    state.regs.rax = 0x15 
 + 
 +sm = p.factory.simgr(state) 
 + 
 +sm.explore(find = 0x0040190d ,avoid = 0x004018d0)  
 + 
 +if sm.found: 
 +    print("Rješenje:", sm.found[0].solver.eval(password,cast_to = bytes)) 
 + 
 +else: 
 +    print("Nema rješenja!"
 +</file> 
 + 
  
-{{ :slika33.png?nolink&500 | Slika 33 - Brža i efikasnija Angr skripta }} 
  
 Ova skripta ne radi full_init_state, nego odmah počinje iz main funkcije, koristi "LAZY_SOLVES" opciju koja dodatno optimizira simbolično izvršavanja u ovom slučaju (nije uvijek primjenjiva), također eksplicitno definira koju putanju izbjegavati (definirana "avoid" argumentom postavljenim na adresu funkcije koja ispisuje "Wrong password!), osim željene putanje i također preskače izvršavanje print funkcije. Ova skripta ne radi full_init_state, nego odmah počinje iz main funkcije, koristi "LAZY_SOLVES" opciju koja dodatno optimizira simbolično izvršavanja u ovom slučaju (nije uvijek primjenjiva), također eksplicitno definira koju putanju izbjegavati (definirana "avoid" argumentom postavljenim na adresu funkcije koja ispisuje "Wrong password!), osim željene putanje i također preskače izvršavanje print funkcije.
  
rev2_angr.1761839631.txt.gz · Last modified: 2025/12/01 11:40 (external edit)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki