10 minutes
CyberJawara2020 | RE Writeup-Quals
BabyBaby
Description
Binary ini dapat digunakan untuk permulaan belajar reverse engineering.
Tips: Soal ini lebih mudah dikerjakan dengan static analysis seperti menggunakan Ghidra (gratis) atau IDA Pro (berbayar) dengan meng-generate kode C-like dari kode mesin yang ada di dalam binary.
Problem
Pada tantangan ini kita diberikan file binary BabyBaby, dan berikut ini adalah pseudocode dari fungsi main program tersebut.
sym.imp.printf(0x9e4); // ps @ 0x9e4 = "Masukkan 3 angka:"
sym.imp.__isoc99_scanf(0x9f7, &c, &var_14h); // ps @ 0x9f7 = "%d %d %d"
if (((c + var_14h == (uint32_t)var_10h * c) &&
((int32_t)var_14h / (int32_t)(uint32_t)var_10h == 0x14)) &&
((int32_t)var_14h / (int32_t)c == 3)) {
var_10h._4_4_ = 0;
sym.imp.puts(0xa00, c, (int32_t)var_14h % (int32_t)c); // ps @ 0xa00 = "Benar!"
var_10h._4_4_ = 0;
while (var_10h._4_4_ < 0x15) {
if (var_10h._4_4_ % 3 == 0) {
sym.imp.putchar(c ^ *(uint32_t *)("X" + (int64_t)var_10h._4_4_ * 4));
}
if (var_10h._4_4_ % 3 == 1) {
sym.imp.putchar(var_14h ^ *(uint32_t *)("X" + (int64_t)var_10h._4_4_ * 4));
}
if (var_10h._4_4_ % 3 == 2) {
sym.imp.putchar((uint32_t)var_10h ^ *(uint32_t *)("X" + (int64_t)var_10h._4_4_ * 4));
}
var_10h._4_4_ = var_10h._4_4_ + 1;
}
} else {
sym.imp.puts(0xa07); // ps @ 0xa07 = "Salah!"
}
Pengecekan kondisi :
if ((first + third == second * first)
&& (third / second == 0x14)
&& (third / first == 3))
Seperti yang kita lihat scanf
menerima 3 masukan sebagai integer, masing-masing masukan akan dihitung dalam kondisi if
. jika hasilnya true
maka
program akan mencetak string “Benar” dan juga Flag.
Solution
Untuk menyelesaikan tantangan ini kita dapat menggunakan library python z3-solver.
>>> from z3 import *
>>>
>>> inp = [BitVec(f'input_{i}',8)for i in range(1,4)]
>>>
>>> s = Solver()
>>> s.add(inp[0] + inp[1] == inp[0] * inp[2], inp[1] / inp[2] == 20, inp[1] / inp[0] == 3)
>>> s.check()
sat
>>> s.model()
[input_2 = 81, input_3 = 4, input_1 = 27]
┌──(unknow㉿unknow)-[~/…/2020/CJ2020/Reverse/BabyBaby]
└─$ ./BabyBaby
Masukkan 3 angka: 27 81 4
Benar!
CJ2020{b4A4a4BBbb7yy}
FLAG : CJ2020{b4A4a4BBbb7yy}
Holmes Code
Description
This Code Secret Dr. Watson to Holmes, Please check message on the Code
Problem
Pada tantangan kali ini kita diberikan file code.zip yang berisi file binary sejumlah 287 file. Berikut ini adalah sedikit potongan disassembly dari beberapa program binary tersebut.
┌──(unknow㉿unknow)-[~/…/CJ2020/Reverse/Holmes Code/code]
└─$ objdump -d -M intel code0
...
00000000006000b0 <.shellcode>:
...
6000c2: 48 8b 44 24 10 mov rax,QWORD PTR [rsp+0x10]
6000c7: 8a 10 mov dl,BYTE PTR [rax]
6000c9: 80 ea 1e sub dl,0x1e
6000cc: 80 fa ec cmp dl,0xec
...
┌──(unknow㉿unknow)-[~/…/CJ2020/Reverse/Holmes Code/code]
└─$ objdump -d -M intel code1
...
00000000006000b0 <.shellcode>:
...
6000c2: 48 8b 44 24 10 mov rax,QWORD PTR [rsp+0x10]
6000c7: 8a 10 mov dl,BYTE PTR [rax]
6000c9: 80 ea 35 sub dl,0x35
6000cc: 80 fa 1f cmp dl,0x1f
...
┌──(unknow㉿unknow)-[~/…/CJ2020/Reverse/Holmes Code/code]
└─$ objdump -d -M intel code2
...
00000000006000b0 <.shellcode>:
...
6000c2: 48 8b 44 24 10 mov rax,QWORD PTR [rsp+0x10]
6000c7: 8a 10 mov dl,BYTE PTR [rax]
6000c9: 80 c2 19 add dl,0x19
6000cc: 80 fa 81 cmp dl,0x81
...
Setelah diamati ternyata setiap binary memiliki alur kode program yang mirip, namun masing-masing binary memiliki instruksi aritmatika yang berbeda-beda diantaranya (add/sub/xor).
Solution
Langkah-langkah yang perlu dilakukan untuk menyelesaikan tantangan ini:
- Membuat bash script untuk mengabil potongan kode dissassembly yang dibutuhkan.
┌──(unknow㉿unknow)-[~/…/CJ2020/Reverse/Holmes Code/code]
└─$ ./solve.sh > data.txt
┌──(unknow㉿unknow)-[~/…/CJ2020/Reverse/Holmes Code/code]
└─$ head data.txt
code0
6000c9: 80 ea 1e sub dl,0x1e
6000cc: 80 fa ec cmp dl,0xec
code1
6000c9: 80 ea 35 sub dl,0x35
6000cc: 80 fa 1f cmp dl,0x1f
code2
6000c9: 80 c2 19 add dl,0x19
6000cc: 80 fa 81 cmp dl,0x81
code3
- Membuat python script untuk menyelesikan tantangan berdasarkan kode disassembly yang sudah kita dapatkan sebelumnya.
┌──(unknow㉿unknow)-[~/…/CJ2020/Reverse/Holmes Code/code]
└─$ python solver.py
The story is notable for introducing the character of Irene Adler, who is one of the most notable female characters in the Sherlock Holmes series, despite appearing in only one story.[1] Doyle ranked CJ2020{A_ScaNdal_in_B0h3mia} fifth in his list of his twelve favourite Holmes stories.
FLAG : CJ2020{A_ScaNdal_in_B0h3mia}
Home Sherlock
Description
Number Home Sherlock Holmes ?
Please check on the File
Download home : https://drive.google.com/file/d/14P7xZ4XIsEm6HU5WMvOVw6E0BFRH6CuH/view
Problem
Di tantangan kali ini kita diberikan file binary dari golang home. Berikut ini adalah pseudocode dari binary tersebut.
[0x00454ed0]> pdg@sym.main.main
void sym.main.main(int64_t arg1, int64_t arg2)
{
...
auStack24 = CONCAT88(0x4e9270, 0x4ab9c0);
sym.fmt.Fprintln(arg1, arg2, (int64_t)obj.go.itab._os.File_io.Writer);
sym.runtime.newobject();
auStack40 = CONCAT88(placeholder_3, 0x4a5ca0);
sym.fmt.Fscanln();
if (*placeholder_3 == 0x9dbdf7f4c117ec) {
sym.runtime.convTstring(arg1, arg2, arg3, placeholder_3, in_R8, in_R9);
sym.fmt.Fprintln(arg1, arg2, arg3_00);
} else {
sym.fmt.Fprintln(arg1, arg2, arg3);
}
sym.fmt.Fscanln();
...
Jika file binary tersebut di eksekusi maka program akan meminta inputan, jika di perhatikan setelah pemanggilan fungsi sym.fmt.Fscanln();
terdapat perbandingan perintah if
yang membandingkan pointer "*placeholder_3" dengan nilai hexadesimal “0x9dbdf7f4c117ec”.
[0x00454ed0]> pdf@sym.main.main
; CODE XREF from sym.main.main @ 0x4997a0
;-- sym.go.main.main:
┌ 597: sym.main.main (int64_t arg1, int64_t arg2);
...
...
│ │╎ 0x00499643 48c744242001. mov qword [var_20h], 1
│ │╎ 0x0049964c e8afa2ffff call sym.fmt.Fscanln
│ │╎ 0x00499651 48b8ec17c1f4. movabs rax, 0x9dbdf7f4c117ec
│ │╎ 0x0049965b 488b4c2440 mov rcx, qword [var_40h]
│ │╎ 0x00499660 483901 cmp qword [rcx], rax
│ ┌───< 0x00499663 0f85d5000000 jne 0x49973e
│ ││╎ 0x00499669 488d052bb803. lea rax, [0x004d4e9b] ; "Q0oyMDIwezIyMUJfQmFrZXJfU3RyMzN0fQofile type does not support deadlinefindfunc: bad findfunctab entry idxfindrunnable: netpoll "
│ ││╎ 0x00499670 48890424 mov qword [rsp], rax
│ ││╎ 0x00499674 48c744240823. mov qword [var_8h], 0x23 ; '#'
...
[0x00454ed0]> ps 35 @ 0x004d4e9b
Q0oyMDIwezIyMUJfQmFrZXJfU3RyMzN0fQo
Pada saat kami melihat fungsi main dengan tampilan kode disassembly pada radare2, kita dapat melihat dengan jelas terdapat sebuah string yang aneh.
Solution
Dari informasi yang sudah kita dapat sebelumnya selama melakukan static analysis, terdapat dua cara untuk menyelesaikan tantangan ini.
- Decode “Q0oyMDIwezIyMUJfQmFrZXJfU3RyMzN0fQo” kedalam base64.
┌──(unknow㉿unknow)-[~/…/2020/CJ2020/Reverse/Home Sherlock]
└─$ echo 'Q0oyMDIwezIyMUJfQmFrZXJfU3RyMzN0fQo' | base64 -d
CJ2020{221B_Baker_Str33t}
base64: invalid input
- Ubah nilai hexadesimal “0x9dbdf7f4c117ec” kedalam desimal lalu jadikan sebagai inputan.
┌──(unknow㉿unknow)-[~/…/2020/CJ2020/Reverse/Home Sherlock]
└─$ python -c 'print(0x9dbdf7f4c117ec)'
44400444004440044
┌──(unknow㉿unknow)-[~/…/2020/CJ2020/Reverse/Home Sherlock]
└─$ ./home
Sherlock Holmes Home
44400444004440044
Q0oyMDIwezIyMUJfQmFrZXJfU3RyMzN0fQo
┌──(unknow㉿unknow)-[~/…/2020/CJ2020/Reverse/Home Sherlock]
└─$ echo 'Q0oyMDIwezIyMUJfQmFrZXJfU3RyMzN0fQo' | base64 -d
CJ2020{221B_Baker_Str33t}
base64: invalid input
FLAG : CJ2020{221B_Baker_Str33t}
Pawon
Description
Yet another reverse engineering challenge
Problem
Pada tantangan berikut ini kita diberikan file binary pawon, dan berikut ini adalah potongan pseudocode kode dari fungsi main
program tersebut yang sudah saya modif sedikit.
...
sym.banner();
sym.imp.printf(" Enter Your Mail\n > ");
sym.imp.std::basic_istream_char__std::(reloc.std::cin, &s);
sym.imp.printf(" Enter Serial\n > ");
sym.imp.std::basic_istream_char__std::(reloc.std::cin);
var_18h._0_4_ = 0;
while( true ) {
uVar7 = SEXT48((int32_t)var_18h);
uVar3 = sym.imp.strlen(&s);
if (uVar3 <= uVar7) break;
if (*(char *)((int64_t)&s + (int64_t)(int32_t)var_18h) == '@') {
var_18h._7_1_ = '\x01';
}
var_18h._0_4_ = (int32_t)var_18h + 1;
}
if (var_18h._7_1_ == '\x01') {
uVar3 = sym.imp.strlen(&s);
if (3 < uVar3) goto code_r0x0000138d;
}
sym.seret();
...
Ketika saat mengeksekusi program tersebut kita akan diminta untuk memasukan dua inputan, yaitu Mail dan Serial. Terdapa pengecekan Mail yang mana inputan kita harus memiliki karakter "@" dan panjangnya harus lebih dari 3.
...
code_r0x0000138d:
uVar3 = sym.imp.strlen();
if (uVar3 < 0x19) {
sym.seret();
}
if (((var_430h._5_1_ != '-') && (var_425h != '-')) && (var_41eh != '-')) {
sym.seret();
}
if ((char)var_430h != var_426h) {
sym.seret();
}
if (var_430h._1_1_ != 'e') {
sym.seret();
}
if (var_430h._3_1_ != 'P') {
sym.seret();
}
if ((char)var_417h != '\0') {
sym.seret();
}
if (var_430h._2_1_ != 'm') {
sym.seret();
}
if (var_430h._4_1_ != var_430h._1_1_) {
sym.seret();
}
if (var_430h._6_1_ != 'j') {
sym.seret();
}
if (var_430h._7_1_ != 'o') {
sym.seret();
}
if (var_428h != var_427h) {
sym.seret();
}
if (var_427h != 'S') {
sym.seret();
}
cVar2 = sym.check_char__char__int
((uint64_t)(uint32_t)(int32_t)var_430h._5_1_, (uint64_t)(uint32_t)(int32_t)var_424h, 9);
if (cVar2 != '\x01') {
sym.seret();
}
if ((int32_t)var_419h != var_41fh + 3) {
sym.seret();
}
if (var_423h != var_41ch) {
sym.seret();
}
if (var_422h != 'z') {
sym.seret();
}
cVar2 = sym.check_char__char__int
((uint64_t)(uint32_t)(int32_t)var_421h, (uint64_t)(uint32_t)(int32_t)var_420h, 0xffffff7a);
if (cVar2 != '\x01') {
sym.seret();
}
if (var_41bh != 'T') {
sym.seret();
}
if (var_420h != 'H') {
sym.seret();
}
if (var_41ch != 'u') {
sym.seret();
}
if (var_41fh != '5') {
sym.seret();
}
if (var_41dh != 'S') {
sym.seret();
}
if (var_41ah != '1') {
sym.seret();
}
if (var_426h != var_41bh) {
sym.seret();
}
cVar2 = sym.check_char__char__int
((uint64_t)(uint32_t)(int32_t)var_418h, (uint64_t)(uint32_t)(int32_t)var_41ch, 0xffffffc3);
if (cVar2 != '\x01') {
sym.seret();
}
Bagian ini adalah pengecekan dari inputan Serial.
Solution
Sama seperti tantangan BabyBaby yang sebelumnya, untuk menyelesaikan tantangan ini kita dapat menggunakan library python z3-solver.
┌──(unknow㉿unknow)-[~/…/2020/CJ2020/Reverse/Pawon]
└─$ python solver.py
TemPe-joSST-cuzgH5-SuT18Y
┌──(unknow㉿unknow)-[~/…/2020/CJ2020/Reverse/Pawon]
└─$ ./pawon
-------
CJ 2020
-------
Enter Your Mail
> test@mail.com
Enter Serial
> TemPe-joSST-cuzgH5-SuT18Y
CJ2020{r+jKctQn&m14l,.JBH8WckZj}
FLAG : CJ2020{r+jKctQn&m14l,.JBH8WckZj}
Ransomnware
Description
Reverse engineering berguna untuk mengetahui alur dari suatu program baik untuk riset binary exploitation, membuat crack/patch, membuat keygen, ataupun analisis malware.
Berikut adalah sebuah ransomware yang mengenkripsi berkas flag.txt. Dapatkah Anda mendekripsi berkas tersebut?
Problem
Pada tantangan ini kita diberikan file binary ransomnware dan juga sebuah file flag yang telah terenkripsi. Berikut ini adalah potongan-potongan pseudocode dari file binary tersebut.
Catatan : beberapa nama fungsi dan variabel telah kami ubah agar lebih mudah dibaca.
[0x000006e0]> pdg @ randomVal
void randomVal(int64_t arg1)
{
...
canary = *(int64_t *)(in_FS_OFFSET + 0x28);
fildes._0_4_ = sym.imp.open(0xcd5, 0); // /dev/urandom
sym.imp.read((undefined4)fildes, (int64_t)&fildes + 4, 0x20, (int64_t)&fildes + 4);
sym.imp.close((undefined4)fildes);
*(int64_t *)arg1 = stack0xffffffffffffffc8;
*(void **)(arg1 + 8) = var_28h;
*(int64_t *)(arg1 + 0x10) = Flag;
*(int64_t *)(arg1 + 0x18) = var_18h;
...
}
[0x000006e0]> pdg @ fillArr
undefined8 fillArr(void)
{
undefined8 I;
I = 0;
while (I < 0x100) {
*(FillArray + I) = I;
I = I + 1;
}
*VAR_1 = 0;
*VAR_2 = 0;
return 1;
}
[0x000006e0]> pdg @ swapVal
void swapVal(int64_t arg1, int64_t arg2)
{
...
uVar1 = *(undefined *)arg1;
*(undefined *)arg1 = *(undefined *)arg2;
*(undefined *)arg2 = uVar1;
return;
}
[0x000006e0]> pdg @ procSwap
void procSwap(int64_t arg1, int64_t arg2)
{
...
*VAR_2 = 0;
while (*VAR_2 < 0x100) {
iVar2 = *(FillArray + VAR_2) + *VAR_1 + *(arg1 + *VAR_2 % arg2);
uVar1 = (iVar2 >> 0x1f) >> 0x18;
*VAR_1 = (iVar2 + uVar1 & 0xff) - uVar1;
swapVal(*(FillArray + VAR_2), *(FillArray + *VAR_1));
*VAR_2 = *VAR_2 + 1;
}
*VAR_1 = 0;
*VAR_2 = 0;
return;
}
[0x000006e0]> pdg @ main
undefined8 main(undefined8 argc, char **argv)
{
...
canary = *(int64_t *)(in_FS_OFFSET + 0x28);
Flag._0_4_ = 1;
Flag._4_4_ = sym.imp.open("flag.txt", 0);
if (Flag._4_4_ == -1) {
// WARNING: Subroutine does not return
sym.imp.exit(0xffffffff);
}
FlagEnc = sym.imp.open("flag.txt.enc", 0x41);
if (FlagEnc == 0xffffffff) {
// WARNING: Subroutine does not return
sym.imp.exit(0xffffffff);
}
randomVal(RandArr);
var_14h = 0x20;
fillArr();
procSwap(*0x202010, 0x10); // 0x202010 -> "rhcmem__c\xadem__\xdaC"
...
Setelah binary memuat file flag.txt
dan flag.txt.enc
, program memanggil fungsi randomVal(RandArr);
yang mana variabel RandArr
akan menyimpan nilai random sepanjang 32 byte dari /dev/urandom
.
Berikutnya fungsi fillArr();
akan membuat sebuah array yang memiliki nilai 0 s/d 255 dan disimpan pada FillArray
.
Selanjutnya terdapat pemanggilan fungsi procSwap(0x202010,16)
, pada fungsi ini setiap index dari FillArray
akan calculated 32 byte dari 0x202010
, lalu dengan swapVal
setiap indeks pada FillArray
posisinya akan ditukar.
[0x000006e0]> pdg @ getValFromArr
undefined getValFromArr(void)
{
uint32_t uVar1;
uVar1 = (*VAR_2 + 1 >> 0x1f) >> 0x18;
*VAR_2 = (*VAR_2 + 1 + uVar1 & 0xff) - uVar1;
*VAR_1 = *(FillArray + VAR_2) + *VAR_1;
uVar1 = (*VAR_1 >> 0x1f) >> 0x18;
*VAR_1 = (*VAR_1 + uVar1 & 0xff) - uVar1;
swapVal(*(FillArray + VAR_2), *(FillArray + VAR_1));
return *(FillArray (*(FillArray + VAR_1) + *(FillArray + VAR_2)));
}
...
var_14h = 16;
...
J = 0;
while (J < (int32_t)var_14h) {
var_25h = getValFromArr();
ptr = *(RandArr + J) ^ var_25h;
sym.imp.write(FlagEnc, &ptr, 1);
J = J + 1;
}
fillArr();
procSwap(RandArr, var_14h);
while( true ) {
Flag._0_4_ = sym.imp.read(Flag._4_4_, &buf, 1, &buf);
if ((int32_t)Flag < 1) break;
var_25h = getValFromArr();
ptr = buf ^ var_25h;
sym.imp.write(FlagEnc, &ptr, 1, &ptr);
}
sym.imp.close(Flag._4_4_);
sym.imp.close(FlagEnc);
...
Pada bagian ini terdapat looping sebanyak 16x, dimana setiap indeks yang ada pada RandArr
akan di XOR dengan nilai yang didapat dari fungsi getValFromArr();
. Setiap nilai yang ada pada indeks FillArray
akan swap, setiap kali terjadi pemanggilan pada fungsi getValFromArr();
. Setiap hasil XOR antara RandArr
dan var_25h
akan ditulis pada FlagEnc
.
Selanjutnya terdapat pemanggialn fungsi fillArr();
dan procSwap(RandArr,var_14h);
, kurang lebih penjelasnya hampir sama dengan yang sebelumnya. Namun kali ini variabel setiap indeks FillArray
akan di calculated dengan 32 byte dari RandArr
, kemudian setiap indeksnya akan swap dengan fungsi swapVal
.
Berikutnya terdapat looping dimana buf
akan menyimpan setiap 1byte dari Flag._4_4_
. Kemudian buf
di XOR dengan var_25h
yang nilainya didapat dari getValFromArr();
, hasil calculated buf
dan var_25h
akan ditulis pada FlagEnc
.
Solution
Cara untuk mendekripsi :
-
Membuat array[256].
-
Melakukan perhitungan setiap indeks pada array[256] dengan
0x202010
. -
Swap setiap posisi yang ada pada array[256].
-
Mengambil nilai dari array[256], lalu array[256] di swap kembali.
-
Melakukan xoring terhadap 32 byte pertama dari flag dengan nilai yang telah dapat dari array[256].
Catatan: kita telah berhasil mengembalikan nilai 32 byte dari
/dev/random
-
Ulangi kembali langkah 1 s/d 4. Namun pada langkah kedua array[256] akan di perhitungkan dengan
/dev/urandom
yang telah kita dapatkan sebelumnya. -
Melakukan xoring terhadap sisa dari 32 byte pertama pada flag dengan nilai yang kita dapat dari array[256].
Catatan: selamat kita telah berhasil mengembalikan flag seperti semula
Berikut ini adalah hasil dari solver saya.
┌──(unknow㉿unknow)-[~/…/2020/CJ2020/Reverse/Ransomnware]
└─$ python solver.py
CJ2020{mamntap_gan_c71c416369bb6230}
FLAG : CJ2020{mamntap_gan_c71c416369bb6230}