Impossible Password
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