For the first part of Wannasmile, we need to get the
./wannasmile program on hexionCTF’s shell server to give us a flag. We are given a version of this executable with the flag stripped out, and are not given read permissions to the real version of the program. Looking at radare2’s graph-view disassembly for this program shown below, we can see what this program does before printing the flag.
Given the name of the challenge, you might be reminded of the infamous Wannacry ransomware. It wrecked havoc, automatically spreading across computer networks and encrypting files, until security researcher Marcus Hutchins found that it had a built-in killswitch. The worm would check for a certain domain name’s non-existance before kicking into action, so registering its kill-switch domain stopped it in its tracks. Here, we have a similar kind of routine. The program decodes a seemingly random 16-char buffer into a hostname, and will print a flag if it resolves.
gdb can be used to find the value of the hostname after decoding, but take care while setting the breakpoint and running the program, as this is malware after all. Here are the steps I took to do this:
- Starting the program with
startiwill only load it, so we can tell what offset the code loaded at (PIE is enabled) without it having to run.
info proc maptells us the program’s base address after loading, which we can add to offset 0x1a8b to stop right before calling
b *0xaddris used to set the breakpoint. Make sure you get no errors and that
x/8i 0xaddrshows the instructions that you expect at that location, which in this case should start with
call 0x555555554f10 <[email protected]>.
- Then, use
cto run the program until the breakpoint, and you can
x/s $rdito see the hostname the malware is trying to resolve.
(gdb) starti Starting program: /home/ungato/wannasmile Program stopped. 0x00007ffff7fd1100 in _start () from /lib64/ld-linux-x86-64.so.2 (gdb) info proc map process 12275 Mapped address spaces: Start Addr End Addr Size Offset objfile 0x555555554000 0x555555556000 0x2000 0x0 /home/ungato/wannasmile 0x555555756000 0x555555758000 0x2000 0x2000 /home/ungato/wannasmile 0x7ffff7fcc000 0x7ffff7fcf000 0x3000 0x0 [vvar] 0x7ffff7fcf000 0x7ffff7fd0000 0x1000 0x0 [vdso] 0x7ffff7fd0000 0x7ffff7ffb000 0x2b000 0x0 /lib/x86_64-linux-gnu/ld-2.30.so 0x7ffff7ffc000 0x7ffff7ffe000 0x2000 0x2b000 /lib/x86_64-linux-gnu/ld-2.30.so 0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0 0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack] 0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall] (gdb) b *0x555555555a8b Breakpoint 1 at 0x555555555a8b (gdb) x/8i 0x555555555a8b 0x555555555a8b: call 0x555555554f10 <[email protected]> 0x555555555a90: test rax,rax 0x555555555a93: jne 0x555555555aad 0x555555555a95: mov rdx,QWORD PTR [rbp-0x20] 0x555555555a99: mov eax,DWORD PTR [rbp-0x14] 0x555555555a9c: mov rsi,rdx 0x555555555a9f: mov edi,eax 0x555555555aa1: call 0x55555555589f (gdb) c Continuing. [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, 0x0000555555555a8b in ?? () (gdb) x/s $rdi 0x555555757020: "uaresuchacrybaby" (gdb)
And so we know that we need to have
uaresuchacrybaby resolve to an IP. But how? We have very limited access to the server we need to make this happen on, it’s not like we can just edit
/etc/hosts. The answer lies in the man page for
HOSTALIASES allows us to make
gethostbyname check a file controlled by us for resolving hostnames before resorting to /etc/hosts or the DNS server. It turns out that even with our limited access, we can still read and write files in /tmp. In
/tmp/rgbpwn-hosts, the line
uaresuchacrybaby google.com can be placed. Now, when we use
HOSTALIASES=/tmp/rgbpwn-hosts ./wannasmile at the shell,
gethostbyname will find that
uaresuchacrybaby is an alias for google.com which will resolve because the server is connected to the internet.
localhost would have probably also worked.
After running wannasmile with our HOSTALIASES, we get the flag: