Assalamualaikum Warahmatullahi Wabarakatuh, halo teman-teman pada artikel kali ini saya ingin mendokumentasikan cara yang saya lakukan untuk Reverse Engineering program yang dibangun dengan bahasa pemrogramman Golang, sebenarnya artikel ini tidak akan ada banyak bedanya dengan yang ada di publik seperti biasa ini adalah tempat dokumentasi saya.
Jadi ceritanya begini, saya beberapa hari ini sejak (26 Juli 2024) tergabung dalam sebuah komunitas Discord beranama Skill-Issue
meskipun namanya seperti itu di dalamnya berisi orang-orang yang kemampuannya lebih pantas mengisi sebuah workshop dengan harga yang sama seperti 17 Juta, di dalamnya sih bukan “Legendary White Hacker” tapi saya bisa pastikan kemampuannya jauh di atas “Legendary White Hacker”. Singkatnya di dalam komunitas ini ada sebuah Challenge yang dibuat untuk “Fun” diposting tanggal 22 Juli 2024 jadi sudah ada 4 hari sejak Challenge ini diunggah masih hanya ada 10 orang yang berhasil menyelesaikannya termasuk saya yang pertama.
Ringkasan singkat tentang Challenge ini kita diberikan sebuah binary lengkap sesuai arch dan os yang tersedia mulai dari Windows - Linux dari x86 sampai ARM65. Singkatnya kita disuruh mencari sebuah password yang dicompile dan pasti ada di dalam binary-nya dan akan mendapatkan sebuah Flag atau jawaban yang dicari dengan mendapatkan point 8, jadi objektifnya jelas kita melakukan cracking ke aplikasi yang ada.
Di dalam tautan download terdapat PE dan Binary dar berbagai arch, karena saya ini lebih ke binary sentris saya akan mentargetkan binary ibu-kota-negara_linux_amd64_v1
yang mana ELF 64-bit x86-64.
Jika ELF itu dijalankan, kita ELF tersebut akan meminta sebuah password yang mana akan dibandingkan dengan hardcoded password yang ada di dalam ELF tersebut, begini bentuk aplikasinya
Aplikasinya akan “panic” jika tidak menerima password yang benar, jika diterjemahkan menjadi pseudocode seperti ini notasinya
password_asli = "xxxxxxxxx"
password_input = input-user
jike password_asli sama dengan password_input
maka keluarkan jawaban benar
jika tidak sama
maka keluarkan panuk password salah
Sesederhana ini saja Challenge program kali ini, namun pengerjaanya tidak seperti melakukan Reverse Engineering dari bahasa C/C++, dikarenakan Go Binary biasanya adalah static linked yang mana libary-library yang penting juga ikut dicompile menjadi satu binary hasilnya akan membuat binary Golang size-nya akan lebih besar dan lebih “sulit” (setidaknya bagi saya) untuk dilakukan Reverse Engineering. Lalu untuk tools yang saya gunakan adalah Ghidra tentu saja karena OpenSource dan alsan besar lainnya karena saya tidak punya IDA-PRO haha 😭😭😭 tools Ghidra dapat diunduh dari sini atau di sini (meskipun keduanya memang satu jalur).
Agar tergambar “susah”-nya melakukan Reverse Engineer untuk Go Binary adalah seperti berikut ini, saya mereplikasi pseudocode di atas menjadi ELF juga dalam membukanya dengan Ghidra.
Secara “flow” kode di atas sudah sama persis dengan Challenge yang ada, jika dibuka dengan dengan decompiler Ghidra maka hasilnya akan seperti ini langkah-langkah yang bisa dijalankan.
Buka ELF yang ada dengan Ghidra
Import File
Analyze Saja agar lebih mudah
Centang semua agak lambat tapi nanti memudahkan kok.
Hasil
Pada tab Symbol Tree
Terlihat ada sebuah ‘folder’ bernama Function
yang mana terdapat daftar fungsi yang ada di dalam binary tersebut, dengan menggunakan bahasa C yang di-compile akan langsung terlihat Entry Point
kita melakukan analisa kode-nya yaitu main
dan hasil dekompilasinya juga sangat mirip dengan bahasa C yang mana kita bisa langsung paham bagaimana algoritmnya. Hal ini tidak dapat disamakan dengan compiled Golang yang mana menemukan ‘main’ sebagai Entry Point
akan sangat-sangat ‘Challenging’.
Jika di atas kita sudah melihat bagaimana ‘gampang’-nya melakukan Reverse Engineering Binary dengan Bahasa C, mari kita lihat bagaimana hasil Golang jika dilakukan decompile dengan Ghidra.
Nah di atas adalah hasil dekompilasi dengan menggunakan Ghidra untuk program Golang, akan terlihat banyak sekali ‘folder’ dengan awalan FUN_ yang mana kita akan cukup sangat kesulitan untuk mencari Entry Point
main
lalu apakah ada solusi paling praktis untuk mencari di mana main
yang digunakan oleh program? cara yang saya lakukan adalah melakukan Recovery Symbol dengan tools bernama GoReSym
dengan begini akan ‘dicarikan jalan’ oleh tools tersebut di mana letak main
-nya. Sebelum membahas tools tersebut mari merencanakan kita sebenarnya mau dengan cara apa ‘memenangkan’ Challenge* ini yang terpikirkan ada 2 cara yaitu:
Saya sejujurnya lebih terbiasa dengan cara yang ke-2, karena dengan begitu saya bisa menginputkan apapun agar tetap menang, hal ini yang sering saya lakukan juga untuk melakukan penetration testing alasannya kenapa? biasanya lebih praktis tapi juga memiliki resiko jika aplikasi-nya memiliki proteksi integrity check kita akan lebih lama lagi prosesnya. Secara teknis bagaimana cara 1 dan 2 bekerja yang pasti cara 1 akan melakukan effort
untuk mencari password yang benar, cara 2 akan merubah seperti pseudocode di bawah ini
password_asli = "xxxxxxxxx"
password_input = input-user
jike password_asli sama dengan password_input
maka keluarkan jawaban benar
jika tidak sama
maka keluarkan jawaban benar
Kita akan memaksa binary tetap mengeluarkan ‘jawaban benar’ meskipun password yang dimasukan salah, apakah itu bisa? tentu pasti bisa. Berikut ini langkah-langkah yang teman-teman dapat tempuh.
Unduh binary GoReSym
pada repostiry ini
GoReSym -t -d -p /path/binary
Dengan perintah di atas, kita akan mendapatkan simbol-simbol yang dapat mempermudah proses Reverse Engineering kita yang hasilnya berada di output.json yang panjangnya 41 Ribu Lines 😭😭
Instalasi Plugin GoReSym Ghidra
Pada repository ini teman-teman dapat mengunduh dan menyimpan pada mesin Ghidra agar dapat diloads
Pilih python
Beri nama file
Simpan
Load output.json untuk di-mapping
Jalankan script yang telah kita simpan sebelumnya, setelah dijalankan script tersebut akan meminta input berupa output.json path dari hasil GoReSym. Dengan begini kita dapat mengawasi output console dan melihat banyak simbol-simbol yang di-Recovery
Dengan begini kita sudah kembali memastikan simbol-simbol pada ‘folder’ ‘function’ sudah dapat sedikit dipahami maksud dan tujuannya
Pertama-tama tentu saja kita cari main
function yang ada dengan bantuan GoReSym
kita sudah dapat melakukan hal ini
Dari tangkapan layar di atas, kita sudah dapat mencari fungsi asli ‘main’ dan hasil dekompilasi yang ada sudah benar-benar menunjukan flow yang ada, jika dilihat dari proses dekompilasi yang ada kode-nya sudah menunjukan ‘core’ dari Challenge yang diberikan
if (DAT_00546d98 == DAT_00546d88) {
*(undefined8 *)((long)register0x00000020 + -0x98) = 0x48e7dc;
bVar1 = runtime.memequal();
uVar4 = extraout_RDX_00;
if (!bVar1) goto LAB_0048e7e4;
*(undefined8 *)((long)register0x00000020 + -0x98) = 0x48e7ef;
skill-issue.org/ibu-kota-negara/pkg/flag.Get(param_3,param_4);
uVar4 = extraout_RDX_01;
}
Dalam kode tersebut DAT_00546d98
akan dibandingkan dengan DAT_00546d88
yang mana hasilnya akan diterima oleh bVar1 = runtime.memequal();
yang mana dalam pengecekan terakhir pada baris
if (!bVar1) goto LAB_0048e7e4;
*(undefined8 *)((long)register0x00000020 + -0x98) = 0x48e7ef;
skill-issue.org/ibu-kota-negara/pkg/flag.Get(param_3,param_4);
uVar4 = extraout_RDX_01;
Jika hasil dari bVar1
adalah tidak benar akan dilempar ke LAB_0048e7e4
dan jika benar maka program akan memanggil fungsi skill-issue.org/ibu-kota-negara/pkg/flag.Get(param_3,param_4);
yang mana jika diliat dari nama fungsinya adalah Flag
kemenangan kita.
Dari flow di atas sesuai dengan cara-cara yang saya utarakan maka kita akan membuat hasil dari bVar1
benar atau salah akan memanggil skill-issue.org/ibu-kota-negara/pkg/flag.Get(param_3,param_4);
bagaimana caranya?
Pertama kita tekan Display Function Graph, setelah di tekan Ghidra akan mengeluarkan tab baru yang mana berisikah Graph dari fungsi yang kita tuju. Di sana kita dapat melakukan analisa dengan membaca kode ASM dari fungsi yang kita targetkan.
Pada baris ini, terlihat ada instruks i CALL
menuju pada memequal
yang mana akan melakukan TEST AL, AL
ekspetasinya adalah dari operasi TEST sebenarnya tidak menghasilkan nilai apapun hanya mengatur flag CPU tapi agar dapat dipahami bisa dianggap intruksi TEST AL, AL
akan menghasilkan 1/True
jika nilainya SAMA atau 0/False
jika nilai inputnya berbeda, paling gampang bisa digambarkan seperti
IF TEST AL, AL == 1
GO LAB_0048e7ea
ELSE
GO PANIC
Dengan begini kita hanya perlu melakukan patch pada hasilnya yaitu JNZ
(Jump Not Zero) instruksi ini akan dipanggil pada saat hasil operasi TEST AL, AL
memiliki flag True
maka JNZ
akan dipanggil, agar kita selalu dapat ‘Menang’ maka kita perlu merubah intruksi JNZ
menjadi JZ
(Jump if Zero) dengan begini kita tidak peduli lagi input TEST AL, AL
hasilnya tidak sama kita akan tetap akan jump ke Flag
Di sini letaknya, kita dapat melakukan hooking dengan menggunakan tools seperti Frida tapi hal paling mudah kita dapat langsung mengganti menjadi JZ
dengan Ghidra caranya untuk Windows user tekan kombinasi tombol CTRL + SHIFT + G
untuk kombinasi selain Windows silahkan dicari sendiri,ya akan menghasilkan ouput seperti ini
Kita tinggal ubah saja JNZ
menjadi JZ
untuk melakukan patching pada binary ini, setelahnya tekan o
untuk menyimpan pada Binary baru. Setelahnya kita akan mendapatkan versi patch yang sudah kita simpan sesuai nama.
Setelahnya kita akan mendapatkan ELF baru dan kita dapat menjalankannya untuk mendapatkan Flag-nya.
Kita sudah mendapatkan flag yang dicari 1buK07a-Ne9@ra
Terima kasih teman-teman telah membaca artikel yang telah saya tulis, saya mohon maaf jika ada sebuah hal teknis yang saya salah tuliskan dan maksudkan saya menerima semua bentuk kritik atau saran yang mana dapat memberikan informasi yang lebih benar ke pembaca! Jika ada cara lain untuk melakukan Reverse Engineering ke aplikasi Golang, saya ingin diberikan informasinya oleh teman-teman, kita bisa berbincang di Telegram @rainysm