Admirer just retired on Hackthebox, it’s an easy difficulty Linux machine with a user difficulty rating of 5.2/10. While rated easy I wouldn’t recommended it for beginners since it’s easy to miss important information and get stuck at soon as foothold. While doing the box I found it a bit frustrating to gather all the pieces of the puzzle together properly. But once done and looking back the box feel very well designed and quite straightforward even though the few rabbits holes.
Tl;Dr: To get the user flag you had to find an instance of
Adminer Database, and, after a lot of enumeration to find credentials to get into an FTP server and grab a backup of the web app. Then you connect to AdminerDB using your own MySQL server and from there you can exploit a vulnerability allowing to read local files using SQL. This way you retrieve
waldo user MySQL credentials, and those credentials are working on SSH allowing us to retrieve the flag.
The root flag is accessible after overwriting the python library
PYTHONPATH environnement variable to make privilege escalation from a python script running as root.
Alright! Let’s get into the details now!
First thing first, let’s add the box IP to the hosts file:
[[email protected] ~]$ echo "10.10.10.187 admirer.htb" >> /etc/hosts
and let’s start!
Let’s start with the classic
nmap scan to see which ports are open on the box:
[[email protected] ~]$ nmap -sV -sT -sC admirer.htb
We have a classical web app running on port 80, the FTP port 21 and the SSH port 22 open.
Opening http://admirer.htb display a following page:
We don’t have a lot of informations on the homepage, however
nmap returned a interesting entry from
80/tcp open http Apache httpd 2.4.25 ((Debian))
http://admirer.htb/admin-dir return a
403 Forbidden so let’s try to use
gobuster with common file extension to find interesting files:
[[email protected] ~]$ gobuster dir -u "http://admirer.htb/admin-dir/" -w ~/SecLists/Discovery/Web-Content/big.txt -x php,txt
We get two interesting text files.
credentials.txt looks particularly promising. Let’s see what we have inside:
[[email protected] ~]$ curl http://admirer.htb/admin-dir/credentials.txt
Well that’s surprisingly a lot of credentials… Let’s start with the beginning, we have seen FTP server open on
nmap, let’s try to login using the credentials we just found:
[[email protected] ~]$ ftp admirer.htb
The FTP server looks looks like a backup folder, since we can see it contains a SQL database dump (
dump.sql) and an archive of what seems to be the website source code (in
Let’s download both files to investigate:
ftp> get dump.sql
dump.sql doesn’t contains any useful informations so let’s directly skip to the
[[email protected] ~]$ tar -xf html.tar.gz
w4ld0s_s3cr3t_d1r seems to be the previous name of the
/admin-dir we found earlier. The
robots.txt file extracted from the archive confirms the theory:
[[email protected] ~]$ cat robots.txt
Another folder catch the attention:
[[email protected] ~]$ ls -l utility-scripts/
db_admin.php contains database credentials, let’s note them for later:
Something odd is that the main
index.php found in the archive contains different database credentials (which should throw error since the password contains unescaped password):
Out of curiosity I tried both of these password on
waldo ssh account but none worked.
Let’s go back to our
admin_tasks.php contains an interesting app:
If we could bypass this
if condition we could achieve remote code execution… Unfortunately even if using weak comparaison (
==) I couldn’t find a Type Juggling kind of exploit nor find any other way to bypass the check and achieve remote code execution from there.
Well since we don’t have other entry point so far let’s enumerate a bit more. We know that this archive is old since some folder were renamed and some files are not available anymore on the web server. Maybe new files have been added ? Let’s run
gobuster to the only folder we didn’t check yet:
[[email protected] ~]$ gobuster dir -u "http://admirer.htb/utility-scripts" -w ~/SecLists/Discovery/Web-Content/big.txt -x php
We got a new one in reference to the box name:
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.
Sounds good we have access to a database management tool. Unfortunately none of the credentials we founds seems to work:
Yet we notice something useful on the page, the version used is
4.6.2 while the latest version is
4.7.7. Searching about this version on Google returns an interesting result:
Adminer 4.6.2 File Disclosure Vulnerability
Adminer is a popular PHP tool to administer MySQL and PostgreSQL databases. However, it can be lured to disclose arbitrary files. Attackers can abuse that to fetch passwords for popular apps such as Magento and Wordpress, and gain control of a site’s database.
Exploitation happens in three stages. First, the attacker needs a modified MySQL server, which is altered to send out data import requests to any client that connects.
Second, the attacker can instruct the victim Adminer to connect to his rigged MySQL server (external connections are actually a feature of Adminer).
Third – With access to the database the attacker could read sensitive information, such as customer details.
Sounds like a very interesting vulnerability, which actually goes back up to 2018 in a little different scenario.
Let’s give it a try.
Following the vulnerability writeup we need to first set our own MySQL instance. We have to make sure it allows external connections with something like:
GRANT ALL PRIVILEGES ON *.* TO 'hg8'@'10.10.10.187' IDENTIFIED BY '<password>' WITH GRANT OPTION;
Then create a table that will hold our extracted data:
CREATE TABLE `test` (
Once our MySQL is all set and running let’s connect to it using
Alright we are in and we can execute SQL queries. Let’s see if we can abuse the SQL query
LOAD DATA LOCAL INFILE to retrieve servers data. Let’s start with the classical
LOAD DATA LOCAL INFILE '/etc/passwd'
Unfortunately we get blocked by PHP restrictions:
Error in query (2000): open_basedir restriction in effect. Unable to open file
Then maybe we can try on files in the webroot directory ? Let’s check for the
index.php since we know the file contains credentials, maybe we could find up-to-date passwords:
123 rows affected, that looks good! We should now find the file content in the
Bingo! We got new credentials, let’s try them on
waldo SSH account:
[[email protected] ~]$ ssh [email protected]
During the usual recon, an interesting
sudo config catch the eye:
[email protected]:~$ sudo -l
Looks like an homemade administration script. If we can find a vulnerability there it’s our way to root.
Let’s take a look at this script:
[email protected]:~$ cat /opt/scripts/admin_tasks.sh
If you noticed, the
sudo configuration informs us that environnement variable we set are kept when running
sudo /opt/scripts/admin_tasks.sh, thanks to
SETENV. At first when seeing this I was thinking we could modify our path to make the script run one of our script named
uptime for example (like we did a few time in the past, on Writeup box for example).
Unfortunately the script author got careful about this and used only absolute path making it impossible for us to use this trick to elevate our privileges.
Digging a bit more we notice a call to a
backup.py script. Let’s take a look:
That’s interesting, what if we keep our idea of PATH hijaking and apply it to Python library
As far as I know when importing a library (
from shutil import make_archive), Python looks in a defined folder to find the library files. Maybe it’s possible to ask Python to search for libraries in a folder we control and inject a rogue library ? Since
backup.py is run as
root we could achieve privilege escalation.
Looking through the Python Documentation we quickly find what we are looking for:
PYTHONPATH is an environment variable which you can set to add additional directories where python will look for modules and packages. For most installations, you should not set these variables since they are not needed for Python to run. Python knows where to find its standard library.
The only reason to set PYTHONPATH is to maintain directories of custom Python libraries that you do not want to install in the global default location (i.e., the site-packages directory).
To put that in practice, first let’s write a very simple python script as
make_archive function to open a reverse shell:
Let’s save it to a folder we control with
shutil.py as name. I will use
Now we open our listener:
[[email protected] ~]$ nc -l -vv -p 8585
And finally we run the backup script as
root while setting the
PYTHONPATH environnement variable to point to our rogue library in
/tmp/.hg8/ first, then to the real lib directory to make sure the library used by our reverse shell can work properly:
[email protected]:~$ sudo PYTHONPATH=/tmp/.hg8:/usr/lib/python3.5/ /opt/scripts/admin_tasks.sh 6
And we get a new connection on our listener:
[[email protected] ~]$ nc -l -vv -p 8585
Let’s add our SSH key to
~/.ssh/authorized_keys in order to get a proper shell:
And grab our flag:
[[email protected] ~]$ ssh -i id_rsa_htb [email protected]
That’s it folks! As always do not hesitate to contact me for any questions or feedbacks!
See you next time ;)