Impossible Password
Impossible Password
January 27, 2020
Welcome to the new year! To start it off, here’s one of the easy CTF challenges from the reverse engineering category on HackTheBox. The binary asks for a password that’s supposedly impossible. Let’s see how impossible it really is.
β‘
TL;DR: Open the binary in radare2, disassemble
main, and you’ll see your input go straight into strcmp against the hardcoded string SuperSeKretKey.Tools
- radare2
- gdb
Analysis
First, load the binary in radare2, run the auto-analysis (aaa) and list the functions (afl):
$ r2 ./impossible_password.bin
[0x004006a0]> aaa
...
[0x004006a0]> afl
0x004006a0 1 41 entry0
0x00400610 1 6 sym.imp.__libc_start_main
0x004005f0 1 6 sym.imp.putchar
0x00400600 1 6 sym.imp.printf
0x00400620 1 6 sym.imp.srand
0x00400630 1 6 sym.imp.strcmp
0x00400650 1 6 sym.imp.time
0x00400660 1 6 sym.imp.malloc
0x00400670 1 6 sym.imp.__isoc99_scanf
0x00400680 1 6 sym.imp.exit
0x00400690 1 6 sym.imp.rand
0x0040085d 5 283 main
0x0040078d 7 208 fcn.0040078d
0x00400978 5 96 fcn.00400978
0x00400760 8 141 -> 99 entry.init0
0x00400740 3 28 entry.fini0
0x004006d0 4 41 fcn.004006d0
0x00400640 1 6 loc.imp.__gmon_start__
0x004005c0 3 26 fcn.004005c0π²
Note the imports
sym.imp.srand, sym.imp.rand and sym.imp.time. Randomness in a password check is a hint that part of this challenge isn’t meant to be guessed.The first key
Let’s start at the beginning and disassemble main:
[0x004006a0]> pdf @ main
...
0x0040085d 55 pushq %rbp
β 0x0040085e 4889e5 %rsp = %rbp
β 0x00400861 4883ec50 subq $0x50,%rsp
β 0x00400865 897dbc movl %edi,-0x44(%rbp) ; argc
β 0x00400868 488975b0 %rsi = var_50h ; argv
β 0x0040086c 48c745f8700a. $str.SuperSeKretKey = s2 ; 0x400a70 ; "SuperSeKretKey"
...
0x004008ce e82dfdffff callq sym.imp.printf ; int printf(const char *format)
β 0x004008d3 488d45e0 leaq s1,%rax
β 0x004008d7 4889c6 %rax = %rsi
β 0x004008da bf820a4000 movl $str._20s,%edi ; 0x400a82 ; "%20s" ; const char *format
β 0x004008df b800000000 movl $0,%eax
β 0x004008e4 e887fdffff callq sym.imp.__isoc99_scanf ; int scanf(const char *format)
β 0x004008e9 488d45e0 leaq s1,%rax
β 0x004008ed 4889c6 %rax = %rsi
β 0x004008f0 bf870a4000 movl $str.__s__n,%edi ; 0x400a87 ; "[%s]\n" ; const char *format
β 0x004008f5 b800000000 movl $0,%eax
β 0x004008fa e801fdffff callq sym.imp.printf ; int printf(const char *format)
β 0x004008ff 488b55f8 -8(%rbp) = %rdx
β 0x00400903 488d45e0 leaq s1,%rax
β 0x00400907 4889d6 %rdx = %rsi ; const char *s2
β 0x0040090a 4889c7 %rax = %rdi ; const char *s1
β 0x0040090d e81efdffff callq sym.imp.strcmp ; int strcmp(const char *s1, const char *s2)
...The flow is short:
s2is set to the string at0x400a70:"SuperSeKretKey".scanf("%20s", s1)reads our input.printf("[%s]\n", s1)echoes it back.strcmp(s1, s2)compares our input with the hardcoded key.
So the first key we need is SuperSeKretKey.
π
r2’s string references (
$str.*) give hardcoded secrets away immediately. Running strings on a crackme is always a cheap first check.Wrap-up
aaa+aflgives a quick map of the binary and its interesting imports.- Hardcoded comparison strings are visible right in the disassembly.
- The
srand/rand/timeimports suggest the second check is a different kind of puzzle.
Last updated on