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:

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

  1. Decode “Q0oyMDIwezIyMUJfQmFrZXJfU3RyMzN0fQo” kedalam base64.
┌──(unknow㉿unknow)-[~/…/2020/CJ2020/Reverse/Home Sherlock]
└─$ echo 'Q0oyMDIwezIyMUJfQmFrZXJfU3RyMzN0fQo' | base64 -d
CJ2020{221B_Baker_Str33t}
base64: invalid input
  1. 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.

solver.py

┌──(unknow㉿unknow)-[~/…/2020/CJ2020/Reverse/Pawon]
└─$ python solver.py
TemPe-joSST-cuzgH5-SuT18­Y
                                                                           
┌──(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 :

  1. Membuat array[256].

  2. Melakukan perhitungan setiap indeks pada array[256] dengan 0x202010.

  3. Swap setiap posisi yang ada pada array[256].

  4. Mengambil nilai dari array[256], lalu array[256] di swap kembali.

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

  6. Ulangi kembali langkah 1 s/d 4. Namun pada langkah kedua array[256] akan di perhitungkan dengan /dev/urandom yang telah kita dapatkan sebelumnya.

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