Skip to content

Latest commit

 

History

History
194 lines (170 loc) · 8.64 KB

tutorial-cybertalents-simple_reverse.md

File metadata and controls

194 lines (170 loc) · 8.64 KB

[Writeup] Cyber Talents: Simple Reverse

Tutorial kali ini akan membahas solusi untuk soal CTF Cyber Talents: Simple Reverse yang termasuk ke dalam kategori reverse engineering. Berikut ini adalah petunjuk untuk soal tersebut:

Only a plaintext password would be easier...

Soal ini disertai aplikasi yang harus kita unduh pada tautan ini. Unduh terlebih dahulu soal tersebut, lalu kita periksa tipenya:

% file simple_reverse
simple_reverse: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8a0dd1d8dbda08a213ac68dd9cd9a5f4836f95cf, not stripped

Selanjutnya, kita akan menggunakan radare2 yang dilengkapi plugin ghidra untuk melakukan analisis. Anda juga dapat menggunakan ghidra saja. Load soal tersebut pada radare2:

% r2 -A simple_reverse
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x00400530]>

Selanjutnya, kita akan melakukan dekompilasi terhadap fungsi main:

[0x00400530]> pdg @main

undefined8 main(undefined8 argc, char **argv)
{
    int32_t iVar1;
    undefined8 uVar2;
    char **var_10h;
    undefined8 var_4h;

    if ((int32_t)argc < 2) {
        sym.imp.printf("Usage:%s <password>\nYou need to enter the password to get the flag!\n", *argv);
        uVar2 = 1;
    } else {
        iVar1 = sym.check_password(argv[1]);
        if (iVar1 == 0) {
            sym.print_flag(argv[1]);
        } else {
            sym.imp.puts("Wrong password");
        }
        uVar2 = 0;
    }
    return uVar2;
}

Berdasarkan hasil dekompilasi di atas, kita dapat melihat bahwa kita harus memasukkan password sebagai parameter pertama ketika menjalankan soal tersebut. Password yang kita masukkan kemudian akan dijadikan parameter ketika memanggil fungsi sym.check_password. Selanjutnya, kita akan melakukan dekompilasi terhadap fungsi sym.check_password.

[0x00400530]> pdg @sym.check_password

undefined8 sym.check_password(char *arg1)
{
    int32_t iVar1;
    undefined8 uVar2;
    int64_t in_FS_OFFSET;
    char *s;
    int32_t var_28h;
    int64_t var_20h;
    int64_t var_18h;
    int64_t var_10h;
    int64_t canary;

    canary = *(int64_t *)(in_FS_OFFSET + 0x28);
    var_20h = -0x4c0d201e200b4f12;
    var_18h = -0x4c170f161c204e1f;
    var_10h._0_2_ = 0xf2;
    iVar1 = sym.imp.strlen(arg1);
    if (iVar1 == 0x11) {
        var_28h = 0;
        while (var_28h < 0x11) {
            if (*(uint8_t *)((int64_t)&var_20h + (int64_t)var_28h) != (uint8_t)(arg1[var_28h] ^ 0x80U)) {
                uVar2 = 0xffffffff;
                goto code_r0x004006bf;
            }
            var_28h = var_28h + 1;
        }
        uVar2 = 0;
    } else {
        uVar2 = 0xffffffff;
    }
code_r0x004006bf:
    if (canary != *(int64_t *)(in_FS_OFFSET + 0x28)) {
        uVar2 = sym.imp.__stack_chk_fail();
    }
    return uVar2;
}

Terdapat 2 buah variabel dengan nilai yang cukup besar pada fungsi tersebut. Agar lebih jelas, kita akan membandingkan dengan disassembly fungsi tersebut:

[0x00400530]> pdf @sym.check_password
            ; CALL XREF from main @ 0x4007fe
┌ 175: sym.check_password (char *arg1);; var char *s @ rbp-0x38
│           ; var signed int64_t var_28h @ rbp-0x28
│           ; var size_t var_24h @ rbp-0x24
│           ; var int64_t var_20h @ rbp-0x20
│           ; var int64_t var_18h @ rbp-0x18
│           ; var int64_t var_10h @ rbp-0x10
│           ; var int64_t canary @ rbp-0x8
│           ; arg char *arg1 @ rdi
│           0x00400626      55             push rbp
│           0x00400627      4889e5         mov rbp, rsp
│           0x0040062a      4883ec40       sub rsp, 0x40
│           0x0040062e      48897dc8       mov qword [s], rdi          ; arg1
│           0x00400632      64488b042528.  mov rax, qword fs:[0x28]
│           0x0040063b      488945f8       mov qword [canary], rax
│           0x0040063f      31c0           xor eax, eax
│           0x00400641      48b8eeb0f4df.  movabs rax, 0xb3f2dfe1dff4b0ee
│           0x0040064b      488945e0       mov qword [var_20h], rax
│           0x0040064f      48b8e1b1dfe3.  movabs rax, 0xb3e8f0e9e3dfb1e1
│           0x00400659      488945e8       mov qword [var_18h], rax
│           0x0040065d      66c745f0f200   mov word [var_10h], 0xf2    ; 242
│           0x00400663      488b45c8       mov rax, qword [s]
│           0x00400667      4889c7         mov rdi, rax                ; const char *s
│           0x0040066a      e871feffff     call sym.imp.strlen         ; size_t strlen(const char *s)
│           0x0040066f      8945dc         mov dword [var_24h], eax
│           0x00400672      837ddc11       cmp dword [var_24h], 0x11
│       ┌─< 0x00400676      7407           je 0x40067f
│       │   0x00400678      b8ffffffff     mov eax, 0xffffffff         ; -1
│      ┌──< 0x0040067d      eb40           jmp 0x4006bf
│      ││   ; CODE XREF from sym.check_password @ 0x400676
│      │└─> 0x0040067f      c745d8000000.  mov dword [var_28h], 0
│      │┌─< 0x00400686      eb2c           jmp 0x4006b4
│      ││   ; CODE XREF from sym.check_password @ 0x4006b8
│     ┌───> 0x00400688      8b45d8         mov eax, dword [var_28h]
│     ╎││   0x0040068b      4898           cdqe
│     ╎││   0x0040068d      0fb64405e0     movzx eax, byte [rbp + rax - 0x20]
│     ╎││   0x00400692      8b55d8         mov edx, dword [var_28h]
│     ╎││   0x00400695      4863ca         movsxd rcx, edx
│     ╎││   0x00400698      488b55c8       mov rdx, qword [s]
│     ╎││   0x0040069c      4801ca         add rdx, rcx
│     ╎││   0x0040069f      0fb612         movzx edx, byte [rdx]
│     ╎││   0x004006a2      83f280         xor edx, 0xffffff80         ; 4294967168
│     ╎││   0x004006a5      38d0           cmp al, dl
│    ┌────< 0x004006a7      7407           je 0x4006b0
│    │╎││   0x004006a9      b8ffffffff     mov eax, 0xffffffff         ; -1
│   ┌─────< 0x004006ae      eb0f           jmp 0x4006bf
│   ││╎││   ; CODE XREF from sym.check_password @ 0x4006a7
│   │└────> 0x004006b0      8345d801       add dword [var_28h], 1
│   │ ╎││   ; CODE XREF from sym.check_password @ 0x400686
│   │ ╎│└─> 0x004006b4      837dd810       cmp dword [var_28h], 0x10
│   │ └───< 0x004006b8      7ece           jle 0x400688
│   │  │    0x004006ba      b800000000     mov eax, 0
│   │  │    ; CODE XREFS from sym.check_password @ 0x40067d, 0x4006ae
│   └──└──> 0x004006bf      488b75f8       mov rsi, qword [canary]
│           0x004006c3      644833342528.  xor rsi, qword fs:[0x28]
│       ┌─< 0x004006cc      7405           je 0x4006d3
│       │   0x004006ce      e81dfeffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
│       │   ; CODE XREF from sym.check_password @ 0x4006cc
│       └─> 0x004006d3      c9             leave
└           0x004006d4      c3             ret

Dari informasi di atas, kita bisa menarik kesimpulan sementara berikut ini:

  • Password berupa karakter dengan panjang 17 byte (0x11 dalam hexadesimal).
  • Setiap byte pada password akan di-XOR dengan nilai 0x80.
  • Hasil XOR akan dibandingkan dengan nilai yang telah ditentukan, yaitu: ** 0xb3f2dfe1dff4b0ee ** 0xb3e8f0e9e3dfb1e1 ** 0xf2
  • Perlu diingat bahwa, nilai yang telah ditentukan tersebut formatnya adalah Little Endian

Untuk memperoleh password yang benar, maka kita dapat membalikkan fungsi tersebut. Jika menggunakan python 3, maka akan seperti ini:

>>> print("".join(chr(a ^ 0x80) for a in bytes.fromhex("eeb0f4dfe1dff2b3e1b1dfe3e9f0e8b3f2")))
n0t_a_r3a1_ciph3r

Bisa terlihat, bahwa passwordnya adalah n0t_a_r3a1_ciph3r. Selanjutnya kita akan menjalankan soal tersebut dengan memasukkan password tersebut sebagai parameter seperti ini:

% ./simple_reverse n0t_a_r3a1_ciph3r
Your flag:
flag{xor_is_pretty_simple}

Nah, itu dia flag untuk soal kali ini, yaitu flag{xor_is_pretty_simple}. Sekian tutorial kali ini, semoga bermanfaat. Terima kasih kepada Allah SWT, dan Anda yang telah membaca tutorial ini.