Reverse Engineering Golang With Ghidra

Last Update Article: 2024-07-27 02:04:42


Reverse Engineering Golang With Ghidra

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.

Untitled

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.

Cracking the Challenge

Untitled

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.

Untitled

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

Untitled

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).

Komparasi C compiled dengan Go compiled

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.

Untitled

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.

  1. Buka ELF yang ada dengan Ghidra

    Untitled

  2. Import File

    Untitled

  3. Analyze Saja agar lebih mudah

    Untitled

    Centang semua agak lambat tapi nanti memudahkan kok.

    Untitled

  4. Hasil

    Untitled

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.

Untitled

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:

  1. Mencari password yang valid di dalam binary
  2. Merubah flow aplikasi agar menginputkan password salah akan tetap mendapatkan ‘hadiah’ (flag)

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

  1. Symbol Recovery dengan GoReSym

Untitled

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 😭😭

  1. Instalasi Plugin GoReSym Ghidra

    Untitled

    Pada repository ini teman-teman dapat mengunduh dan menyimpan pada mesin Ghidra agar dapat diloads

Untitled

  1. Klik pada tombol tersebut pada Ghidra atau menu Display Script Manager

Untitled

  1. Pilih python

    Untitled

  2. Beri nama file

    Untitled

  3. Simpan

    Untitled

  4. Load output.json untuk di-mapping

    Untitled

    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

    Untitled

Dengan begini kita sudah kembali memastikan simbol-simbol pada ‘folder’ ‘function’ sudah dapat sedikit dipahami maksud dan tujuannya

Untitled

Winning the Challenge by Patching

Pertama-tama tentu saja kita cari main function yang ada dengan bantuan GoReSym kita sudah dapat melakukan hal ini

Untitled

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?

Untitled

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.

Untitled

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

Untitled

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

Untitled

Untitled

Untitled

Untitled

Untitled

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.

Untitled

Setelahnya kita akan mendapatkan ELF baru dan kita dapat menjalankannya untuk mendapatkan Flag-nya.

Untitled

Kita sudah mendapatkan flag yang dicari 1buK07a-Ne9@ra

Penutup

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