Henry Isakoff 🥕 Sovellusten Hakkerointi

| Sovellusten Hakkerointi | 5 min

Lohikäärme ghidra, C ja koko tarina

Tässä raportissa tutustumme ghidraan työkaluna, käänteismallinnamme ohjelmia ja selvitämme käännettyjen binäärien toimintatapaa.

Kalilla ghidran asennus kävi helposti

sudo apt-get install ghidra

Sisältö

Ensimmäisenä kuitenkin Lyhyesti Ghidra - John Hammondin youtubesta.

Ensin tutkii file, strings, strace, objdump ja ltrace komennoilla löytämättä mitään. Ghidralla hän löytää hexaluvun 0x86187 joka kääntyy ’549255’

packd ja passtr

Viime viikolla tutustuimme ja obfuskoimme packd/passwd ohjelmia. Koitetaan nyt kääntää näitä ghidralla.

Sisältö Sisältö

Importtasin ja käänsin packd ohjelman sellaisenaan ja hämmennyin, koska en nähnyt selkeästi main ohjelmaa, tai mitään sen tapaista. Vaikka tiedänkin jo binäärin viime viikosta, en saanut sitä mitenkään luettavaan muotoon.

Sitten muistin tunnilta, toinen oppilas oli käyttänyt upxää ensin binäärin purkuun. Eli

upx -d packd

Tässä käytetään -d / decrompress muotoa joka purkaa ohjelman luettavaan muotoon. Paljon kätevämpi tapa kuin viime viikon RAM etsintä. Tallenna _purettu nimellä.

Sisältö

Sitten vaan ghidralla import->lohikäärme.

Main löytyi heti ja ajettava ohjelma.

Korjattu logiikka

Käyn koodin toimintalogiikan mistralini kanssa läpi. Teenpä siis muutoksia muuttujiin seuraavasti. Tämän jälkeen selitetty toimintalogiikka.

local_28 → sanasala: salasana muuttuja käyttäjälle iVar1 → tarkistus: pöydän tulos

Yritin myös etsiä ...201d muotoilua koodista, mutta tähän hätään en löytänyt sitä. Ymmärrän, että tämänkin pitäisi(?) löytyä tuolta merkkijonona. Olisi varmaan ihan kätevä debuggaukseen tietää esim. monta muotoa pitkä tuo olisi.

Korjattu logiikka kuitenkin seuraavasti.

Korjattu logiikka

Ohjelman toiminta vaiheittain:

Syötteen pyyntö: Ohjelma tulostaa käyttäjälle kehotteen, jossa pyydetään salasanaa.

Syötteen lukeminen: Käyttäjän syöte luetaan __isoc99_scanf-funktiolla. Funktio käyttää muistiosoitteessa DAT_0010201d sijaitsevaa muotoilumäärettä ja tallentaa syötetyn merkkijonon password-muuttujaan.

Salasanan vertailu: strcmp-funktio vertaa password-muuttujan arvoa ohjelmaan kovakoodattuun merkkijonoon piilos-AnAnAs. Vertailun tulos tallennetaan checker-muuttujaan. Ehdollinen tulostus: Ohjelma tarkistaa if-else-rakenteella checker-muuttujan arvon.

Jos arvo on 0 (salasanat täsmäävät), käyttäjälle tulostetaan onnitteluviesti ja lippu.

Jos arvo ei ole 0, käyttäjälle tulostetaan "Sorry, no bonus.".

Passtr ohitus

Seuraavaksi sama passtr binäärille. Toimintalogiikka on sama.

passtr

Tehtävänä on ratkaista tämä ohittamalla ohjelman toimintalogiikka meidän omalla. Eli lähdetään etsimällä string: ’password’ muistista (pikanäppäin s).

passtr

Avaan myös kohdan windows - function graph niin näen tapahtumataulun.

passtr

Taulun viimeinen tapahtuma on JNZ hyppy jossa hypätään ilman nollaa kohtaan jossa salasana on oikein.

Eli vaihdetaa Jump non zero = jump zero. Jolloin toimintalogiikka olisi päinvastainen. Ainoastaan oikea salasana ei toimisi.

Patch instuctions = JZ

passtr

Tämän jälkeen exporttasin, annoin toimintaoikeudet ja testasin toimivuuden.

Toimii

Toimii

Nora CrackMe

1

Seruraavaksi yritetään selvittää Noran CrackMe tehtäviä.

Gitillä sisään ja lähdetään. Mukana on pelkät C-sorsat joten ykkönen pystyyn komennolla.

gcc crackme01.c -o crackme01

Ohjelma 01 pyytää argumentin, joten lähdetään selvittämään. Crackme01

Ghidralla auki ja mainista näemme, että ohjelma kysyy salasanaa ”password1”.

Crackme01 Crackme01

Joka toimii.

1e

Oli sama, mutta salasanassa piti käyttää ’!’ pelkän ! tilalta. Crackme01e

2

Auki ghidralla ja toimintaselvitys Mistralilla.

Crackme02

Tässä siis (osin mistralin kautta selvitys) ’if (param_1 == 2) {’ varmistaa, että käyttäjältä tulee TASAN yksi salasana-argumentti. Muuten tulee virhe 0xffffffff.

Salasana vertaillaan ja jos lukumäärä on oikein, ohjelma aloittaa iteroinnin merkkijonon ”password1” läpi ja vertaa jokaista merkkiä käyttäjän antamaan salasanan vastaavaan merkkiin.

Kohdassa if ("password1"[i] + -1 != (int)*(char *)((long)i + (long *)param_2 + 8)) { printf("No, %s is not correct.\n", *(undefined8 *)argv + 8); return 1; }

vertailun tulos on oltava -1 merkistä, tai ohjelma lopettaa.

Voidaan periaatteessa vaihtaa param_1 ja _2, mutta sillä ei niin väliä. Local_c on selvästi i. Tehdään se.

Crackme02- korjattu

Eli kyseessä on ASCII merkkijonosta joka täytyy muuttaa suunnassa -1. Jolloin jokainen merkki pitää muuttaa yksitellen. Pyydän Mistrallilta pelkkää merkkijonoa ilman kommentteja.

p	112	111	o
a	97	96	`
s	115	114	r
s	115	114	r
w	119	118	v
o	111	110	n
r	114	113	q
d	100	99	c
1	49	48	0

Eli vastauksessa muistettava erikoismerkin eteen \ = o\’rrvnqc0. Myös ’sisään’ käy.

Crackme02- korjattu

Ja sehän toimi!

Kommentit

Ghidra on todella hyvä työkalu ja vasta tässä parin viikon jumppaamisellakin ymmärtänyt sen tärkeyttä. Näitä ollut kiva ratkoa.

Lähteet

Teron binäärit https://terokarvinen.com/sovellusten-hakkerointi/

John Hammond - Ghidra https://www.youtube.com/watch?v=oTD_ki86c9I

Dokumentissa käytetty apuna C-koodin ymmärryksessä ja ASCII taulukon tekemisessä LLM mistra-small3.2:24b mallia. Rautana käytössä ollut Macbook pro m2 max 64gb ja kääntäjänä LM-studio. https://huggingface.co/mistralai/Mistral-Small-3.2-24B-Instruct-2506 https://lmstudio.ai

UPX https://upx.github.io

JNZ selvite https://stackoverflow.com/questions/14841169/jnz-cmp-assembly-instructions

Crackmes tehtävät https://github.com/NoraCodes/crackmes

Kuvat optimoitu https://optimage.app

Käytetty aika 3h 20min