El Bandito
Can you help capture El Bandito before he leaves the galaxy? - by l4m3r8
Last updated
Can you help capture El Bandito before he leaves the galaxy? - by l4m3r8
Last updated
The following post by 0xb0b is licensed under CC BY 4.0
If you finished the room with the help of a writeup I recommend doing the challenge again in a few months to forget about the path to take here. So you are able to improve on the topic of this challenge. Execution is easy, but detecting the right payloads is still hard and touchy.
We start with a Nmap scan, and discover four open ports: 22, 22, 80, 631, and 8080.
In addition to SSH, the server provides three web servers. Interesting. But we already know from the challenge that it is probably a pure web challenge. On 8080, we are dealing with a Spring Java Framework. No other versions can be detected. The endpoint on Port 80 runs on HTTPS.
We use Gobuster to determine the directories of the web applications. Unfortunately, we don't find much on endpoint 80; only /static/messages.js
seems to be interesting. For further information, the page is enumerated manually.
8080 provides a few more directories, most of them are forbidden and known for Java Spring Framework.
As a first entry point, 8080 is of interest because it offers more directories, we know what kind of framework we are dealing with in the background (Java Spring Framework), and the first visit to the index page promises more. The page seems to have several links, most of which are just anchor points. Accessible pages here are Services and Burn Token.
The Burn Token
page has a form that offers interaction.
The page source code tells us that a WebSocket is hidden behind it, which is used.
This can be seen when loading the page, but there do not appear to be any open connections.
We intercept the request on burn.html
and see an HTTP/1.1
WebSocket request in Burp Suite. Something I saw the day before in a freshly published walkthrough room on TryHackMe. Since we know that this is a pure web challenge, the theme of the bandit is continued from a previous challenge in which a part was also HTTP request smuggling, and the challenge itself writes:
"We request your help in smuggling all the flags."
This will probably be very much a challenge about request smuggling, especially WebSocket request smuggling, here.
The following resource gives guidance on WebSocket Request Smuggling:
Using WebSocket Request Smuggling, we can bypass proxy restrictions. By recalling spring actuator endpoints and the gobuster scan, we could be able to get access to sensitive information by accessing those restricted resources.
Spring Boot Actuators register endpoints such as
/health
,/trace
,/beans
,/env
, etc. In versions 1 to 1.4, these endpoints are accessible without authentication. From version 1.5 onwards, only/health
and/info
are non-sensitive by default, but developers often disable this security.
We send the /ws
request to the repeater and see that the path /ws
does not exist.
As described in https://tryhackme.com/r/room/wsrequestsmuggling
, we can enable request smuggling using WebSocket Upgrade. We create a malformed request so that the proxy assumes that a WebSocket upgrade has taken place - for example, with a higher version number, here 777
-, but the version in the backend remains the same. This causes the proxy to create a tunnel between client and server, which is unchecked and perceived as a WebSocket connection, but the backend still expects HTTP traffic.
With this, we are tying to access a restricted resource by specifying an incorrect version number and applying request smuggling, but this does not work here.
The server seems to be secured and checks whether the WebSocket upgrade was successful. We are not able to access /env
, for example.
Since we can't smuggle requests with just a simple malformed request, we need to find a way to fool the proxy into believing that a valid WebSocket connection has been established.
In other words, we have to somehow trick the proxy that the backend web server responds with a 101
Switching Protocols response without actually upgrading the connection in the backend to establish that 'upgrade'. So we are looking for an SSRF, also depicted here:
We come across Services
and see an online status for http://bandito.websocket.thm
and http://bandito.public.thm
.
We intercept the request, and lo and behold, we have the possibility to apply server-side request forgery. If we point to /isOnline?url=http://attacker-server/
and have a a server, that responds only with 101s, we could make use of this to upgrade our websocket.
Fortunately, THM has already provided a server in python:
We start the server...
... And edit our initial request and swap /
with /isOnline?url=http://attacker-server:attacker-port/
. We are able to retrieve restricted resources now. Nice.
Unfortunately, we have not found anything in /env
, but we do have other directories that could contain something sensitive. At the resource /trace
, we find two directories that we did not find in our Gobuster scan and are also not usual for the framework: /admin-creds
and /admin-flag
.
On accessing /admin-creds
we are able to retrieve some credentials, that might have been used for other stuff.
And at /admin-flag
we find our first flag.
A deep dive into the topic of WebSocket Request Smuggling can be found here:
We continue at the end point 80. The index page shows a nothing to see
, but that's not the case.
Like the Gobuster scan, the source reveals /static/messages.js
. This could be our entry point.
The JavaScript code manages a chat interface between two users, JACK
and OLIVER
. It handles message fetching, displaying, and sending functionalities. Users can switch between JACK
and OLIVER
's messages by clicking on their respective discussion tabs. When sending a message, the code distinguishes between regular user messages and those from a simulated bot
, which is indicated in the chat interface.
We know about a message board, and about directory /access
. If we visit this, we get a login mask. We have already harvested 8080 credentials, which we now use here to log in as hAckLIEN
.
We have a chat in front of us, between hAckLIEN
and Jack
. We can select the chats between Jack
and Oliver
, but there is none with Oliver
.
Let's take a look at what requests are made when we reload /messages
and sending messages.
In addition to the board, the messages are also loaded, as the structure of the script suggests.
We can send any messages with our session.
As this room stated, "We request your help in smuggling all the flags."
All flags could have something to do with HTTP Request Smuggling. Let's try to detect it.
All the requests we have made are HTTP/2
requests. There is not much smuggling possible unless we can downgrade to HTTP/1.1
. If this is not possible, we only have HTTP/2
request tunneling as another option. A good explanation with hands-on practices for HTTP/2
Request Smuggling is available at:
Let's switch to HTTP/1.1
in Burp Suite. And seeing that these requests are also supported is interesting. Perhaps a downgrade is possible.
The first tests for smuggling were carried out purely on HTTP/1.1
. At some point there was an error that I could no longer reproduce myself due to the abundance of payloads. We receive a 503
backend fetch failed, which tells us that we are dealing with a Varnish cache server
, which is known to be susceptible for some versions to request smuggling.
With the following request, this can be safely reproduced:
We set the Content-Length
now to 0
, disable the Content-Length
update in Burp Suite, and append a second request to retrieve all the messages after sending a message. The reply suggests, and confirms, that HTTP Request Smuggling is possible here.
We have seen that we can also send HTTP/1.1
requests successfully and chain requests by setting the Content-Length
to 0
for the first request. It is very likely that an HTTP/2
downgrade is possible.
This Downgrade of HTTP/2
to HTTP/1.1
requests via Content-Length Header is called H2.CL
and is pictured in the following Walkthrough-Room of TryHackMe - Task 3: HTTP2/Desync HTTP/2 Downgrading H2.CL:
HTTP/2 downgrading occurs when a reverse proxy serves content to the end user with HTTP/2 (front-end connection) but requests it from the back-end servers with HTTP/1.1 (back-end connection). The Content-Length header isn't significant for HTTP/2, as the length of the request body is clearly defined. But a Content-Length header can still be added to an HTTP/2 request. If an HTTP downgrade occurs, the proxy will pass on the added Content-Length header from HTTP/2 to the HTTP/1.1 connection and thus enable desynchronization. The proxy receives the HTTP/2 request on the frontend connection. When translating the request to HTTP/1.1, it simply passes the Content-Length header to the backend connection. The backend web server then reads the request andd acknowledges the injected Content-Length as valid, which enables HTTP Request Smuggling.
We switch back to HTTP/2
in our previously made request to /send_message
and try our first approach. We set the Content-Length
to 0
and appended the data SMUGGLED
to our POST
request. The automatic update of the Content-Length
in Burp Suite has to be disabled.
After multiple request we can see, that after a successful one we get a 405
Not Allowed Response. We can imagine, that our request after a successful one gets appended to SMUGGLED
which make the POST /send_message HTTP/2
request to a SMUGGLEDPOST /send_message HTTP/2
which results in a 405
.
The endpoint might be vulnerable to HTTP/2 Downgrade Via H2.CL
.
Since HTTP/2
smuggling is probably possible, we now have to think about how we can exploit it. We have a message board with at least two users and one bot. They may still communicate on this board. The idea is now to intercept the request of one of the users and retrieve sensitive information of the request made.
We can realize this by smuggling; we place an incomplete send_message
request on the server, with a sufficient content length. The request of the victim should serve as data, so that it can be posted on the message board, visible to us.
The following request executes exactly that: we adapt our send_message
request in the repeater so that we are querying /
instead of send_messages
.
Make sure that you have already intercepted the /messages
and /send_message
requests once in Burp Suite. Intercept the send_message
request via the proxy and forward it to the Burp Suite repeater. Here, we will now revise the entire request.
It is possible that it is an HTTP/1.1
request that you have intercepted; change this to HTTP/2
via the inspector panel. Then replace the request.
We send our initial request to /
, using Content-Length: 0
. We append an incomplete send_message
request to this request. This way we write the request of another user to our message board. With a sufficient content length of 900 or more, we ensure that everything from the user's request is taken into account as data
for the message.
A mistake has sneaked in here in my explanation.
Many thanks to huggi77 https://tryhackme.com/r/p/huggi77, who, when trying the steps below, realized that they did not lead to the desired result and pointed this out to me.
This request must be spammed again until the response is delayed. It is now necessary to wait until the 503 service unavailable response arrives. This is updates continuously. After approximately one minute, the victim should also have submitted a request, which we can now find on the message board /getMessages.
This is the updated version.
As shown below, we send the request described above until the response is delayed and finally returns a 503
. Make sure to set the correct carriage returns and line feeds, like in the image shown below:
We then resend it once again and receive a 200
response. It is important here that the content length does not exceed the length of the presumed request of the victim that we want to intercept.
We chose a Content-Length
of ~730
; previously it was 900
. The Content-Length
of 900
does not lead to consistent results. A possible explanation can be found in
Volta's (https://tryhackme.com/r/p/Volta) write-up
https://voltatech.in/blog/2024/tryhackme-elbandito/#weaponizing-the-smuggled-request:
If you set the
Content-Length
larger than the request made by the victim then the application will just timeout.
Now we have to wait about 2 minutes for the bot to make a request.
We call /getMessages
and find the expected response. We catched a login request. The second flag is in the cookie information.
Thank you, l4m3r8, for this awesome challenge. It took me some time, and in the end, it added some more brain wrinkles to my brain.
After completing the walkthrough rooms, I felt very prepared for the various request-smuggling techniques. But that's probably not quite the case. They are very easy to execute, but very difficult to recognize. Practice makes the difference. I think if I came across another smuggling challenge, I would still need hours to detect it and exploit it.
But this is the way.
We set sail with our trusty Nmap scanner, scouring the digital seas for treasures. Aye, we spy four open ports: 22, 80, 631, and 8080. But it's the promise of buried booty on ports 80 and 8080 that catches our keen pirate eyes.
Ahoy, me hearties! Port 8080 be teemin' with possibilities. Aye, we be dealin' with the Java Spring Framework, aye, a fine vessel to plunder. We spy a page called "Burn Token", hintin' at secrets beneath the surface.
We delve deep, sniffin' out a hidden WebSocket like a bloodhound on the scent of treasure. But the path be barred by a proxy, aye, a clever guardian protectin' the loot. Yet we be crafty pirates, and we spy a vulnerability in the proxy's defenses – aye, a server-side request forgery lurks, just waitin' for a scallywag like meself to exploit it.
With a bit o' trickery and a server of our own, we breach the defenses and plunder the forbidden directories. Aye, we find a trove of credentials in /admin-creds
, and our first flag be flyin' high at /admin-flag
.
But our quest be far from over, me hearties! We set sail for port 80, where a mysterious message board awaits. Aye, it be guarded by a login prompt, but fear not – we've got the keys to the kingdom from our earlier plunderin'.
We slip into the chat like shadows in the night, eavesdroppin' on conversations betwixt hAckLIEN
and Jack
. But the real treasure lies in the messages themselves, ripe for the plunderin'.
But wait – what be this? Our requests be met with a strange response, aye, a 503
error from a Varnish cache server. Methinks there be mischief afoot – aye, HTTP request smugglin' be the name of the game.
We splice the mainbrace and set our sights on smugglin' requests, usin' HTTP/2 trickery and downgrades to breach the defenses. Aye, we be slippery devils, slippin' past the guards and snatchin' flags from right under their noses.
And so, me hearties, we emerge victorious, flags in hand and treasure in our grasp. With our wits and our cunning, we've outsmarted the guardians of the digital realm and claimed our rightful booty.
But let this tale be a warnin' to ye – the seas of cyberspace be treacherous indeed, and only the boldest and the craftiest pirates can hope to navigate them unscathed. So set yer sails high, me hearties, and may the winds of fortune ever be at yer back! Argh!