Setup
Data
- URL: BitFriends’s admin_panel
- Language: C/C++
- Platform: Unix/Linux (ELF64)
- Description: “Welcome to my little crackme! Your goal is to get a shell!
As usual patching is not allowed. ld_preload, dll injection and rootkits are not allowed too. I hope the crackme is not overrated or underated. Have fun!”
Output
$ ./admin_panel Welcome to the admin panel! The program which admins can interact with on a guest computer to do admin stuff! status: (admin=false; shell=unavailable) *>
Analysis
Tools
Cutter/Radare2
Decompiler (Commented)
undefined8 main(void) { int32_t iVar1; int64_t iVar2; undefined8 uVar3; int64_t in_FS_OFFSET; char *src; char *dest; char *format; int64_t canary; canary = *(int64_t *)(in_FS_OFFSET + 0x28); strcpy(&dest, admin, admin); puts( "Welcome to the admin panel! The program which admins can\ninteract with on a guest computer to do admin stuff!\n" ); while( true ) { if (_admin != 0xe9a) { puts("status: (admin=false; shell=unavailable)\n"); } if (_admin == 0xe9a) { puts("status: (admin=true; shell=available)\n"); } printf(0x20cf); // 0x20cf:"*> " iVar2 = fgets(&format, 0x100, _reloc.stdin); if (iVar2 == 0) break; strtok(&format, 0x20d3); // 0x20d3:"\n"; Removes "\n" from &format iVar1 = strcmp(&format, 0x20d5); // 0x20d5:"shell" if ((iVar1 == 0) && (_admin == 0xe9a)) { system("/bin/bash"); } else { printf("input: "); printf(&format); puts(0x20d3); } } uVar3 = 0; if (canary != *(int64_t *)(in_FS_OFFSET + 0x28)) { uVar3 = __stack_chk_fail(); } return uVar3; }
Conclusion
The value of iVar1 has to be 0 and the value of admin (bss segment addr: 0x407c) has to be 0xe9a. To get iVar1 to 0 we have to enter “shell\n”. To get admin to 0xe9a we have to find a vulnerability to write that value. The app prints out what we have entered so we can possibly use a format string attack.
Attached gdb to running admin_panel process to resolve address.
$ pidof admin_panel 3915 $ sudo gdb ~/Downloads/admin_panel (gdb) attach 3915 (gdb) p &admin $1 = ( *) 0x559045ffb07c
That address (&admin) changes with every new startup.
Let’s find out if that address is currently stored on the stack.
*> %x %x %x %x %x %x %x %x input: 45ff90ec aff3c780 7 b014d700 7 2e5f26f2 45ffb07c b014d700
Indeed it is at position 7.
Solution
Format string
Let’s overwrite the value (to 0xe9a) to which the 7th parameter is pointing.
1. Let’s print out the 7th parameter
*> %7$x input: 45ffb07c
2. Let’s write a number to the 7th param
*> %7$n input:
(gdb) x/x &admin 0x559045ffb07c: 0x00000004
The value of 4 has been written to admin, cause there have been 4 characters (here: spaces) entered before %7$n.
3. Let’s write 0xe9a to the 7th param
*> %3738u%7$n status: (admin=true; shell=available)
E9A hex is 3738 dec. Also valid:
"%3737u %7$n", "%3736u %7$n", "%3735u %7$n", ...
(gdb) x/x &admin 0x559045ffb07c: 0x00000e9a
For more informations: Brad Daniels Blog
Output
*> %3738u%7$n status: (admin=true; shell=available) *> shell