# Forgetful Commander---**Points:** 281 | **Solves:** 36/1035 | **Category:** Reverse
And you lost a key again. This time it's the key to your missiles command station. However, the command station got a silent password override. Even though your memory isn't that good, you don't remember the password either, your technical skills are!. You've already dumped the binary, which checks the password. Now you just have to reverse it!
[Download](ForgetfulCommander_85dcf6730d6936301904fc2218c77d6c.zip)---
[Bahasa Indonesia](#bahasa-indonesia)
## EnglishThe binary is `elf32-i386`. We have difficulty doing static analysis because the `.text` segment is not disassembled properly and it seems that the machine instructions are pretty random.
We decided to try to do dynamic analysis. The execution of the binary doesn't show clear behavior because there is no interaction whatsoever. Execution using strace shows that the program exited with code 1.
```$ strace ./forgetful_commander...open("/proc/self/maps", O_RDONLY)       = 3read(3, "5660d000-5660f000 r--p 00000000 "..., 16384) = 1528close(3)                                = 0exit_group(1)                           = ?+++ exited with 1 ++```
The binary is compiled as PIE (Independent Position-Executables). We try to use `gdb` and set `breakpoint` to the `.text` address in the hope that the correct instructions will be executed.
```$ gdb ./forgetful_commander...gdb-peda$ b *0x0Breakpoint 1 at 0x0gdb-peda$ rStarting program: /vagrant/forgetful_commanderWarning:Cannot insert breakpoint 1.Cannot access memory at address 0x0
gdb-peda$ del 1gdb-peda$ info filesSymbols from "/vagrant/forgetful_commander".Native process:	Using the running image of child process 28513.	While running this, GDB does not access memory from...Local exec file:	`/vagrant/forgetful_commander', file type elf32-i386.warning: Cannot find section for the entry point of /vagrant/forgetful_commander.	Entry point: 0xd000	0x56556194 - 0x565561a7 is .interp	0x565561a8 - 0x565561c8 is .note.ABI-tag	0x565561c8 - 0x565561fc is .hash	0x565561fc - 0x5655621c is .gnu.hash	0x5655621c - 0x5655629c is .dynsym	0x5655629c - 0x56556339 is .dynstr	0x5655633a - 0x5655634a is .gnu.version	0x5655634c - 0x5655637c is .gnu.version_r	0x5655637c - 0x565563bc is .rel.dyn	0x565563bc - 0x565563cc is .rel.plt	0x56557000 - 0x56557020 is .init	0x56557020 - 0x56557050 is .plt	0x56557050 - 0x56557321 is .text	0x56557324 - 0x56557338 is .fini	0x56558000 - 0x5655842c is .rodata	0x5655842c - 0x56558450 is .eh_frame_hdr	0x56558450 - 0x565584f0 is .eh_frame	0x56559eec - 0x56559ef0 is .init_array	0x56559ef0 - 0x56559ef4 is .fini_array	0x56559ef4 - 0x56559fec is .dynamic	0x56559fec - 0x5655a000 is .got	0x5655a000 - 0x5655a014 is .got.plt	0x5655a014 - 0x5655a01c is .data	0x5655a01c - 0x5655a020 is .bssgdb-peda$ x/10i 0x56557050   0x56557050:	cdq   0x56557051:	addr16 int 0x30   0x56557054:	movs   DWORD PTR es:[edi],DWORD PTR ds:[esi]   0x56557055:	add    bh,ah   0x56557057:	add    ebp,ebx   0x56557059:	xchg   ecx,eax   0x5655705a:	into   0x5655705b:	ins    DWORD PTR es:[edi],dx   0x5655705c:	xor    al,0x2c   0x5655705e:	daagdb-peda$ b *0x56557050Breakpoint 2 at 0x56557050gdb-peda$ cContinuing....Breakpoint 2, 0x56557050 in ?? ()gdb-peda$ s...gdb-peda$ s
Program received signal SIGSEGV, Segmentation fault.[----------------------------------registers-----------------------------------]EAX: 0xf7ffd918 --> 0x56555000 --> 0x464c457fEBX: 0xf7ffd000 --> 0x23f3cECX: 0xffffd694 --> 0xffffd7c3 ("/vagrant/forgetful_commander")EDX: 0xffffffffESI: 0xffffd69c --> 0xffffd7de ("XDG_SESSION_ID=221")EDI: 0x56562000 --> 0x819c6050EBP: 0x0ESP: 0xffffd690 --> 0x1EIP: 0x56557051 --> 0xb4895eedEFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------]   0x56557046:	push   0x8   0x5655704b:	jmp    0x56557020   0x56557050:	cdq=> 0x56557051:	in     eax,dx   0x56557052:	pop    esi   0x56557053:	mov    DWORD PTR [ebx+eax*4+0x5405f0e4],esi   0x5655705a:	push   edx   0x5655705b:	call   0x565570d7[------------------------------------stack-------------------------------------]0000| 0xffffd690 --> 0x10004| 0xffffd694 --> 0xffffd7c3 ("/vagrant/forgetful_commander")0008| 0xffffd698 --> 0x00012| 0xffffd69c --> 0xffffd7de ("XDG_SESSION_ID=221")0016| 0xffffd6a0 --> 0xffffd7f1 ("SHELL=/bin/bash")0020| 0xffffd6a4 --> 0xffffd801 ("TERM=xterm-256color")0024| 0xffffd6a8 --> 0xffffd815 ("SSH_CLIENT=10.0.2.2 56511 22")0028| 0xffffd6ac --> 0xffffd832 ("SSH_TTY=/dev/pts/0")[------------------------------------------------------------------------------]Legend: code, data, rodata, valueStopped reason: SIGSEGV0x56557051 in ?? ()```
As we can see, this looks strange because the execution of the random instructions still occurs and produces SIGSEGV. It seems like the program somehow use self-modifying code at one point.
Assuming that `__libc_start_main` will be called, we try to interrupt when call to `__libc_start_main` is occurs by hijacking the function using `LD_PRELOAD`. By raising `SIGINT`, `gdb` will capture the `signal` and we can check the `state` of the program at that time.
Here is the `hijack.c` code.
```C#define _GNU_SOURCE
#include <dlfcn.h>#include <signal.h>
int __libc_start_main(int (*main) (int,char **,char **),                      int argc, char **ubp_av,                      void (*init) (void),                      void (*fini)(void),                      void (*rtld_fini)(void),                      void (*stack_end)) {
    int (*original__libc_start_main)(int (*main) (int,char **,char **),                                     int argc, char **ubp_av,                                     void (*init) (void),                                     void (*fini)(void),                                     void (*rtld_fini)(void),                                     void (*stack_end));
    raise(SIGINT);
    original__libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main");    return original__libc_start_main(main, argc,ubp_av, init, fini,                                     rtld_fini, stack_end);}```
Compile the code to `hijack.so` (32 bit).
```gcc --shared -fPIC hijack.c -o hijack.so -ldl -m32```
Use that library in the `gdb`.
```$ gdb --args env LD_PRELOAD=/vagrant/hijack.so ./forgetful_commander...gdb-peda$ rStarting program: /usr/bin/env LD_PRELOAD=/vagrant/hijack.so ./forgetful_commanderprocess 28754 is executing new program: /vagrant/forgetful_commander
Program received signal SIGINT, Interrupt....Stopped reason: SIGINT0xf7fd8be9 in ?? ()gdb-peda$ info files...0x56557050 - 0x56557321 is .text...gdb-peda$ x/10i 0x56557050   0x56557050:	xor    ebp,ebp   0x56557052:	pop    esi   0x56557053:	mov    ecx,esp   0x56557055:	and    esp,0xfffffff0   0x56557058:	push   eax   0x56557059:	push   esp   0x5655705a:	push   edx   0x5655705b:	call   0x56557082   0x56557060:	add    ebx,0x2fa0   0x56557066:	lea    eax,[ebx-0x2ce0]```
It appears that the contents of the `.text` has changed and it seems like the instructions are correct. You can analyze the whole assembly. For easiness, you can also take the bytes from correct `.text` and override the `.text` in the binary file so that they can be decompiled by IDA to pseudo-code. Here, we try to figure out what the program is doing by just looking at the assembly.
By looking at the contents of the stack when the original `__libc_start_main` is called, we can know that `main` is located in `.text+320` or `0x56557190` in the case above.
Here are the first few instructions in the `main` function.
```asm   0x56557190:	push   ebp   0x56557191:	mov    ebp,esp   0x56557193:	push   ebx   0x56557194:	push   edi   0x56557195:	push   esi   0x56557196:	sub    esp,0x2c   0x56557199:	call   0x5655719e   0x5655719e:	pop    eax   0x5655719f:	add    eax,0x2e62   0x565571a5:	mov    ecx,DWORD PTR [ebp+0xc]   0x565571a8:	mov    edx,DWORD PTR [ebp+0x8]   0x565571ab:	mov    DWORD PTR [ebp-0x10],0x0   0x565571b2:	cmp    DWORD PTR [ebp+0x8],0x2   0x565571b6:	mov    DWORD PTR [ebp-0x28],eax   0x565571b9:	mov    DWORD PTR [ebp-0x2c],ecx   0x565571bc:	mov    DWORD PTR [ebp-0x30],edx   0x565571bf:	je     0x565571d1   0x565571c5:	mov    DWORD PTR [ebp-0x10],0x1   0x565571cc:	jmp    0x565572a8```
In the `cmp DWORD PTR [ebp + 0x8], 0x2` instruction, it will compare the contents of `[ebp+0x8]` where the number of arguments (argc) is located. So, the number of arguments must be two in order for the execution to go to `0x565571d1`. If not, the execution will continue to `0x565572a8` where the execution will go directly to `ret`.
The instructions after `0x565571d1` seem to be related to retrieving values in the argument, calling to `strlen`, and also checking the the argument. The following section looks interesting.
```asm   0x5655723f:	movsx  eax,BYTE PTR [ebp-0x21]   0x56557243:	mov    ecx,DWORD PTR [ebp-0x20]   0x56557246:	mov    esi,DWORD PTR [ebp-0x28]   0x56557249:	movsx  ecx,BYTE PTR [esi+ecx*1-0x1c0f]   0x56557251:	mov    edi,DWORD PTR [ebp-0x18]   0x56557254:	mov    ebx,DWORD PTR [ebp-0x20]   0x56557257:	imul   ebx,DWORD PTR [ebp-0x1c]   0x5655725b:	add    edi,ebx   0x5655725d:	movsx  edi,BYTE PTR [esi+edi*1-0x1ff8]   0x56557265:	xor    ecx,edi   0x56557267:	cmp    eax,ecx   0x56557269:	jne    0x56557278```
When the program reaches `0x5655723f`, the value of `[ebp-0x21]` is the first letter of the argument and stored to `eax`. Then at the `0x56557267`, the value of `eax` is compared to `ecx` which is the value from a xor operation.
By setting the `breakpoint` in `0x56557267` (`cmp eax, ecx`), we can know the value of `ecx` when compared to the argument's characters. For reasons that we have not explored further, this `breakpoint` must be set while still in `__libc_start_main`. If it is set in the middle of execution on `.text`, there will be `SIGTRAP` continuously.
From observations on the value of `ecx` in `0x56557267` one by one, we get **flag {Just_type__Please__and_the_missles_will_be_launched.}**.
Execution with this flag as the argument will make the program exit with code 0.
```$ strace ./forgetful_commander flag{Just_type__Please__and_the_missles_will_be_launched.}...open("/proc/self/maps", O_RDONLY)       = 3read(3, "56596000-56598000 r--p 00000000 "..., 16384) = 1594close(3)                                = 0exit_group(0)                           = ?+++ exited with 0 +++```
## Bahasa IndonesiaBinary yang diberikan adalah `elf32-i386`. Kami kesulitan untuk melakukan *static analysis* karena segmen `.text` tidak ter-*disassemble* dengan baik dan sepertinya bukan instruksi mesin yang akan dijalankan.
Kami memutuskan untuk mencoba melakukan *dynamic analysis*. Eksekusi pada binary tidak memperlihatkan perilaku yang jelas karena tidak ada interaksi apapun. Eksekusi menggunakan `strace` memperlihatkan bahwa program exit dengan kode 1.
```$ strace ./forgetful_commander...open("/proc/self/maps", O_RDONLY)       = 3read(3, "5660d000-5660f000 r--p 00000000 "..., 16384) = 1528close(3)                                = 0exit_group(1)                           = ?+++ exited with 1 ++```
Binary dikompilasi sebagai PIE (Position-Independent Executables). Kami mencoba untuk menggunakan `gdb` dan mengatur `breakpoint` pada alamat `.text`. Instruksi pada `.text` terlihat random tetapi mari coba untuk mengeksekusinya.	
```$ gdb ./forgetful_commander...gdb-peda$ b *0x0Breakpoint 1 at 0x0gdb-peda$ rStarting program: /vagrant/forgetful_commanderWarning:Cannot insert breakpoint 1.Cannot access memory at address 0x0
gdb-peda$ del 1gdb-peda$ info filesSymbols from "/vagrant/forgetful_commander".Native process:	Using the running image of child process 28513.	While running this, GDB does not access memory from...Local exec file:	`/vagrant/forgetful_commander', file type elf32-i386.warning: Cannot find section for the entry point of /vagrant/forgetful_commander.	Entry point: 0xd000	0x56556194 - 0x565561a7 is .interp	0x565561a8 - 0x565561c8 is .note.ABI-tag	0x565561c8 - 0x565561fc is .hash	0x565561fc - 0x5655621c is .gnu.hash	0x5655621c - 0x5655629c is .dynsym	0x5655629c - 0x56556339 is .dynstr	0x5655633a - 0x5655634a is .gnu.version	0x5655634c - 0x5655637c is .gnu.version_r	0x5655637c - 0x565563bc is .rel.dyn	0x565563bc - 0x565563cc is .rel.plt	0x56557000 - 0x56557020 is .init	0x56557020 - 0x56557050 is .plt	0x56557050 - 0x56557321 is .text	0x56557324 - 0x56557338 is .fini	0x56558000 - 0x5655842c is .rodata	0x5655842c - 0x56558450 is .eh_frame_hdr	0x56558450 - 0x565584f0 is .eh_frame	0x56559eec - 0x56559ef0 is .init_array	0x56559ef0 - 0x56559ef4 is .fini_array	0x56559ef4 - 0x56559fec is .dynamic	0x56559fec - 0x5655a000 is .got	0x5655a000 - 0x5655a014 is .got.plt	0x5655a014 - 0x5655a01c is .data	0x5655a01c - 0x5655a020 is .bssgdb-peda$ x/10i 0x56557050   0x56557050:	cdq   0x56557051:	addr16 int 0x30   0x56557054:	movs   DWORD PTR es:[edi],DWORD PTR ds:[esi]   0x56557055:	add    bh,ah   0x56557057:	add    ebp,ebx   0x56557059:	xchg   ecx,eax   0x5655705a:	into   0x5655705b:	ins    DWORD PTR es:[edi],dx   0x5655705c:	xor    al,0x2c   0x5655705e:	daagdb-peda$ b *0x56557050Breakpoint 2 at 0x56557050gdb-peda$ cContinuing....Breakpoint 2, 0x56557050 in ?? ()gdb-peda$ s...gdb-peda$ s
Program received signal SIGSEGV, Segmentation fault.[----------------------------------registers-----------------------------------]EAX: 0xf7ffd918 --> 0x56555000 --> 0x464c457fEBX: 0xf7ffd000 --> 0x23f3cECX: 0xffffd694 --> 0xffffd7c3 ("/vagrant/forgetful_commander")EDX: 0xffffffffESI: 0xffffd69c --> 0xffffd7de ("XDG_SESSION_ID=221")EDI: 0x56562000 --> 0x819c6050EBP: 0x0ESP: 0xffffd690 --> 0x1EIP: 0x56557051 --> 0xb4895eedEFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------]   0x56557046:	push   0x8   0x5655704b:	jmp    0x56557020   0x56557050:	cdq=> 0x56557051:	in     eax,dx   0x56557052:	pop    esi   0x56557053:	mov    DWORD PTR [ebx+eax*4+0x5405f0e4],esi   0x5655705a:	push   edx   0x5655705b:	call   0x565570d7[------------------------------------stack-------------------------------------]0000| 0xffffd690 --> 0x10004| 0xffffd694 --> 0xffffd7c3 ("/vagrant/forgetful_commander")0008| 0xffffd698 --> 0x00012| 0xffffd69c --> 0xffffd7de ("XDG_SESSION_ID=221")0016| 0xffffd6a0 --> 0xffffd7f1 ("SHELL=/bin/bash")0020| 0xffffd6a4 --> 0xffffd801 ("TERM=xterm-256color")0024| 0xffffd6a8 --> 0xffffd815 ("SSH_CLIENT=10.0.2.2 56511 22")0028| 0xffffd6ac --> 0xffffd832 ("SSH_TTY=/dev/pts/0")[------------------------------------------------------------------------------]Legend: code, data, rodata, valueStopped reason: SIGSEGV0x56557051 in ?? ()```
Seperti yang dapat kita lihat, ini terlihat aneh karena eksekusi pada instruksi random tersebut tetap terjadi dan menghasilkan SIGSEGV. Sepertinya program melakukan *self-modifying* pada satu titik dengan suatu cara.
Dengan asumsi bahwa `__libc_start_main` suatu saat terpanggil, kami mencoba untuk melakukan *interrupt* pada saat `__libc_start_main` dipanggil dengan melakukan *hijack* pada fungsi tersebut menggunakan `LD_PRELOAD`. Dengan memberikan `SIGINT`, maka `gdb` akan menangkap `signal` tersebut dan kita dapat memeriksa `state` program pada saat itu.
Berikut adalah kode `hijack.c`.
```C#define _GNU_SOURCE
#include <dlfcn.h>#include <signal.h>
int __libc_start_main(int (*main) (int,char **,char **),                      int argc, char **ubp_av,                      void (*init) (void),                      void (*fini)(void),                      void (*rtld_fini)(void),                      void (*stack_end)) {
    int (*original__libc_start_main)(int (*main) (int,char **,char **),                                     int argc, char **ubp_av,                                     void (*init) (void),                                     void (*fini)(void),                                     void (*rtld_fini)(void),                                     void (*stack_end));
    raise(SIGINT);
    original__libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main");    return original__libc_start_main(main, argc,ubp_av, init, fini,                                     rtld_fini, stack_end);}```
Kompilasi kode menjadi `hijack.so` (32 bit).
```gcc --shared -fPIC hijack.c -o hijack.so -ldl -m32```
Gunakan `library` tersebut pada `gdb` dan jalankan.
```$ gdb --args env LD_PRELOAD=/vagrant/hijack.so ./forgetful_commander...gdb-peda$ rStarting program: /usr/bin/env LD_PRELOAD=/vagrant/hijack.so ./forgetful_commanderprocess 28754 is executing new program: /vagrant/forgetful_commander
Program received signal SIGINT, Interrupt....Stopped reason: SIGINT0xf7fd8be9 in ?? ()gdb-peda$ info files...0x56557050 - 0x56557321 is .text...gdb-peda$ x/10i 0x56557050   0x56557050:	xor    ebp,ebp   0x56557052:	pop    esi   0x56557053:	mov    ecx,esp   0x56557055:	and    esp,0xfffffff0   0x56557058:	push   eax   0x56557059:	push   esp   0x5655705a:	push   edx   0x5655705b:	call   0x56557082   0x56557060:	add    ebx,0x2fa0   0x56557066:	lea    eax,[ebx-0x2ce0]```
Terlihat bahwa isi `.text` sudah berubah dan sepertinya instruksi yang benar. Anda dapat menganalis assembly-nya secara keseluruhan. Untuk mempermudah, Anda juga dapat mengambil nilai bytes dari `.text` yang sudah berubah dan menimpanya pada `.text` pada berkas binary sehingga dapat didekompilasi oleh IDA menjadi pseudo-code. Di sini, kami mencoba untuk mengira-ngira apa yang dilakukan oleh program dengan melihat assembly-nya saja.
Dengan melihat isi `stack` (parameter) pada saat `__libc_start_main` yang asli akan dipanggil, kita dapat mengetahui bahwa `main` terdapat pada alamat `.text+320` atau `0x56557190` pada kasus di atas. 
Berikut beberapa instruksi pertama pada fungsi `main`.
```asm   0x56557190:	push   ebp   0x56557191:	mov    ebp,esp   0x56557193:	push   ebx   0x56557194:	push   edi   0x56557195:	push   esi   0x56557196:	sub    esp,0x2c   0x56557199:	call   0x5655719e   0x5655719e:	pop    eax   0x5655719f:	add    eax,0x2e62   0x565571a5:	mov    ecx,DWORD PTR [ebp+0xc]   0x565571a8:	mov    edx,DWORD PTR [ebp+0x8]   0x565571ab:	mov    DWORD PTR [ebp-0x10],0x0   0x565571b2:	cmp    DWORD PTR [ebp+0x8],0x2   0x565571b6:	mov    DWORD PTR [ebp-0x28],eax   0x565571b9:	mov    DWORD PTR [ebp-0x2c],ecx   0x565571bc:	mov    DWORD PTR [ebp-0x30],edx   0x565571bf:	je     0x565571d1   0x565571c5:	mov    DWORD PTR [ebp-0x10],0x1   0x565571cc:	jmp    0x565572a8```
Instruksi `cmp DWORD PTR [ebp+0x8],0x2` akan membandingkan isi dari `[ebp+0x8]` di mana pada alamat tersebut tersimpan jumlah dari argumen (argc). Sehingga, jumlah argumen harus berjumlah dua agar program lanjut ke `0x565571d1`. Jika tidak, program akan lanjut ke `0x565572a8` yang mana program akan langsung menuju `ret`.
Instruksi-instruksi setelah `0x565571d1` sepertinya terkait dengan pengambilan nilai pada argumen, pemanggilan ke `strlen`, dan juga memeriksa isi argumen. Bagian pemeriksaan berikut terlihat menarik.
```asm   0x5655723f:	movsx  eax,BYTE PTR [ebp-0x21]   0x56557243:	mov    ecx,DWORD PTR [ebp-0x20]   0x56557246:	mov    esi,DWORD PTR [ebp-0x28]   0x56557249:	movsx  ecx,BYTE PTR [esi+ecx*1-0x1c0f]   0x56557251:	mov    edi,DWORD PTR [ebp-0x18]   0x56557254:	mov    ebx,DWORD PTR [ebp-0x20]   0x56557257:	imul   ebx,DWORD PTR [ebp-0x1c]   0x5655725b:	add    edi,ebx   0x5655725d:	movsx  edi,BYTE PTR [esi+edi*1-0x1ff8]   0x56557265:	xor    ecx,edi   0x56557267:	cmp    eax,ecx   0x56557269:	jne    0x56557278```
Pada saat program mencapai `0x5655723f`, isi dari `[ebp-0x21]` adalah huruf pertama dari argumen dan disimpan ke `eax`. Kemudian pada alamat `0x56557267`, isi dari `eax` dibandingkan dengan `ecx` yang merupakan suatu nilai dari operasi xor.
Dengan mengatur `breakpoint` pada `0x56557267` pada instruksi `cmp eax,ecx`, kita dapat mengetahui nilai `ecx` yang dibandingkan dengan argumen karakter demi karakter. Karena alasan yang belum kami eksplorasi lebih lanjut, pemasangan `breakpoint` ini harus dilakukan ketika masih di `__libc_start_main`. Jika dilakukan di tengah-tengah eksekusi pada `.text`, terjadi `SIGTRAP` terus menerus.
Dari observasi pada nilai `ecx` pada `0x56557267` satu persatu, didapatkan **flag{Just_type__Please__and_the_missles_will_be_launched.}**.
Eksekusi dengan flag tersebut sebagai argumen akan membuat program exit dengan kode 0.
```$ strace ./forgetful_commander flag{Just_type__Please__and_the_missles_will_be_launched.}...open("/proc/self/maps", O_RDONLY)       = 3read(3, "56596000-56598000 r--p 00000000 "..., 16384) = 1594close(3)                                = 0exit_group(0)                           = ?+++ exited with 0 +++```