Write-up - RSSIL 2011 - RCE chimay_rouge
by @Jonathan Salwan - 2011-05-29Classical reverse in Linux x86-64 bits. We need to found the good serial.
First glimpse
jonathan@pentest [RSSIL] $ file ./chimay_rouge chimay_rouge: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped jonathan@pentest [RSSIL] $ ./chimay_rouge serial : test FAIL ! jonathan@pentest [RSSIL] $
Let's go, we open gdb and we begin to reverse the binary.
(gdb) disass main Dump of assembler code for function main: [...] 0x000000000040072f <+54>: mov $0x4008d5,%eax {0x4008d5: "serial : "} 0x0000000000400734 <+59>: mov %rax,%rdi 0x0000000000400737 <+62>: mov $0x0,%eax 0x000000000040073c <+67>: callq 0x400530 <printf@plt> <= on affiche "serial : " 0x0000000000400741 <+72>: mov $0x4008df,%eax {0x4008df: "%25s"} 0x0000000000400746 <+77>: lea -0x20(%rbp),%rdx 0x000000000040074a <+81>: mov %rdx,%rsi 0x000000000040074d <+84>: mov %rax,%rdi 0x0000000000400750 <+87>: mov $0x0,%eax 0x0000000000400755 <+92>: callq 0x400580 <__isoc99_scanf@plt> <= calls scanf() 0x000000000040075a <+97>: lea -0x20(%rbp),%rax 0x000000000040075e <+101>: mov %rax,%rdi 0x0000000000400761 <+104>: callq 0x400570 <strlen@plt> <= calls strlen on serial 0x0000000000400766 <+109>: cmp $0x18,%rax <= compares the serial with 0x18 0x000000000040076a <+113>: je 0x400780 <main+135> <= if equal, we jump on main+135 0x000000000040076c <+115>: mov $0x4008e4,%edi {0x4008e4: "FAIL !"} 0x0000000000400771 <+120>: callq 0x400540 <puts@plt> 0x0000000000400776 <+125>: mov $0x1,%edi 0x000000000040077b <+130>: callq 0x400550 <exit@plt> <= exit(1) 0x0000000000400780 <+135>: lea -0x20(%rbp),%rax [...]
Now, we know that the serial need to be 24 characters.
0x0000000000400780 <+135>: lea -0x20(%rbp),%rax 0x0000000000400784 <+139>: mov %rax,%rdi 0x0000000000400787 <+142>: callq 0x400684 <chiffre> 0x000000000040078c <+147>: lea -0x40(%rbp),%rcx 0x0000000000400790 <+151>: lea -0x20(%rbp),%rax 0x0000000000400794 <+155>: mov $0x18,%edx 0x0000000000400799 <+160>: mov %rcx,%rsi 0x000000000040079c <+163>: mov %rax,%rdi 0x000000000040079f <+166>: callq 0x400590 <memcmp@plt> 0x00000000004007a4 <+171>: test %eax,%eax
Then, we encode the serial and compares it with memcmp(). We found a interesting function called chiffre(), so we reverse it.
Below the function wich decrypt the serial.
0x00000000004006be <+58>: jmp 0x4006f1 <chiffre+109> 0x00000000004006c0 <+60>: mov -0x4(%rbp),%eax 0x00000000004006c3 <+63>: cltq 0x00000000004006c5 <+65>: add -0x28(%rbp),%rax 0x00000000004006c9 <+69>: mov -0x4(%rbp),%edx 0x00000000004006cc <+72>: movslq %edx,%rdx 0x00000000004006cf <+75>: add -0x28(%rbp),%rdx 0x00000000004006d3 <+79>: movzbl (%rdx),%ecx 0x00000000004006d6 <+82>: mov -0x4(%rbp),%edx 0x00000000004006d9 <+85>: lea (%rcx,%rdx,1),%edx 0x00000000004006dc <+88>: mov %edx,%ecx 0x00000000004006de <+90>: mov -0x4(%rbp),%edx 0x00000000004006e1 <+93>: movslq %edx,%rdx 0x00000000004006e4 <+96>: movzbl -0x20(%rbp,%rdx,1),%edx 0x00000000004006e9 <+101>: xor %ecx,%edx 0x00000000004006eb <+103>: mov %dl,(%rax) 0x00000000004006ed <+105>: addl $0x1,-0x4(%rbp) 0x00000000004006f1 <+109>: cmpl $0x17,-0x4(%rbp) 0x00000000004006f5 <+113>: jle 0x4006c0 <chiffre+60>
We put a breakpoint on "<+101>: xor %ecx,%edx" and see what's going on and recover the clef.
(gdb) b* 0x00000000004006e9 Breakpoint 2 at 0x4006e9 (gdb) r Starting program: /home/jonathan/RSSIL/chimay_rouge serial : aaaaaaaaaaaaaaaaaaaaaaaa Breakpoint 2, 0x00000000004006e9 in chiffre () (gdb) i r $edx $ecx edx 0xf4 244 {key[0]} ecx 0x61 97 {a} (gdb) c Continuing. Breakpoint 2, 0x00000000004006e9 in chiffre () (gdb) i r $edx $ecx edx 0x86 134 {key[1]} ecx 0x62 98 {b} (gdb) c Continuing. Breakpoint 2, 0x00000000004006e9 in chiffre () (gdb) i r $edx $ecx edx 0x95 149 {key[2]} ecx 0x63 99 {c} (gdb)
%edx contains the key and %ecx our character. Below, the key which is used for uncrypt our string.
char key[] = "\xf4\x86\x95\x5d\x52\xb9\x97\x95\x0e\x6d\x67\x4d\x11\xcf\x7d\xdb\x51\x38\x00\x2c\x1d\x65\xa5\x4d";
Now, we need to know what's going on with memcmp() to know which is the good serial.
0x0000000000400799 <+160>: mov %rcx,%rsi 0x000000000040079c <+163>: mov %rax,%rdi 0x000000000040079f <+166>: callq 0x400590 <memcmp@plt> (gdb) b *0x000000000040079f Breakpoint 3 at 0x40079f (gdb) r Starting program: /home/jonathan/RSSIL/chimay_rouge serial : aaaaaaaaaaaaaaaaaaaaaaaa Breakpoint 3, 0x000000000040079f in main () (gdb) i r $rsi $rdi rsi 0x7fffffffea90 140737488349840 rdi 0x7fffffffeab0 140737488349872 (gdb) x/s 0x7fffffffea90 0x7fffffffea90: "\267\267\345\067$\200\355\024i\020\065\071n\243*Y>\275zjn\345\354=" (gdb) x/s 0x7fffffffeab0 0x7fffffffeab0: "\225\344\366\071\067\337\360\375g\a\f!|\241\022\253 JsXh\023\322\065" (gdb)
Simple xor with the string for know what is the good serial.
hex((0xf4 ^ 0xb7) - 0) hex((0x86 ^ 0xb7) - 1) hex((0x95 ^ 0xe5) - 2) hex((0x5d ^ 0x37) - 3) hex((0x52 ^ 0x24) - 4) hex((0xb9 ^ 0x80) - 5) hex((0x97 ^ 0xed) - 6) hex((0x95 ^ 0x14) - 7) hex((0x0e ^ 0x69) - 8) hex((0x6d ^ 0x10) - 9) hex((0x67 ^ 0x35) - 10) hex((0x4d ^ 0x39) - 11) hex((0x11 ^ 0x6e) - 12) hex((0xcf ^ 0xa3) - 13) hex((0x7d ^ 0x2a) - 14) hex((0xdb ^ 0x59) - 15) hex((0x51 ^ 0x3e) - 16) hex((0x38 ^ 0xbd) - 17) hex((0x00 ^ 0x7a) - 18) hex((0x2c ^ 0x6a) - 19) hex((0x1d ^ 0x6e) - 20) hex((0x65 ^ 0xe5) - 21) hex((0xa5 ^ 0xec) - 22) hex((0x4d ^ 0x3d) - 23) jonathan@pentest [RSSIL] $ echo -e "\x43\x30\x6e\x67\x72\x34\x74\x7a\x5f\x74\x48\x69\x73 \x5f\x49\x73\x5f\x74\x68\x33\x5f\x6b\x33\x59" C0ngr4tz_tHis_Is_th3_k3Y jonathan@pentest [RSSIL] $ echo -n "C0ngr4tz_tHis_Is_th3_k3Y" | ./chimay_rouge serial : Bravo vous pouvez valider
The key is C0ngr4tz_tHis_Is_th3_k3Y