Metasploit Community CTF
Hosted by Rapid7 from 4 Dec to 7 Dec 2021
Last updated
Hosted by Rapid7 from 4 Dec to 7 Dec 2021
Last updated
We placed 7th - managed to solve all but one challenge!
The organizers wrote a nice summary of the CTF here.
Since this year's challenges were sorted by difficulty (the higher the port number, the harder the challenge), I'll also sort my writeups by port number.
I only included writeups for challenges that I solved - the rest were solved by my teammates!
Card | Category | Port |
---|---|---|
Web | 8080 | |
Web | 10010 | |
Web | 11111 | |
Web | 12380 | |
Pwn | 15000 | |
Web | 15010 | |
Network Forensics | 20000, 20001 | |
Web | 20011 | |
Web | 20055 | |
Crypto | 20123 | |
Web | 33337 | |
Network Forensics | 35000 |
This was a simple cookie manipulation challenge. Cookies are set at every stage of authentication, and the following cookies grant us access to /admin
.
When we log into the application, we can see the following data in the page source. There seems to be a role
attribute that we need to change, in order to escalate our privileges.
Taking a closer look at the registration fields, we see that we are submitting an account
object with the username
and password
attributes.
Submitting with account[role] = admin
changes our role
, granting us access to /admin
.
This was a simple SQL injection in the login. The payload username=admin&password=' or '1
grants us access.
Our scan shows that this is a vulnerable version of Apache.
We can exploit the RCE vulnerability to obtain the contents of the flag.
This was a TCP service that we could interact with via Netcat, and appears to be managing text files.
The "Create" option allows us to create a text file in the format NAME_SURNAME.txt
. Validation is performed so that both fields are alphanumeric characters only.
The "Delete" option allows us to delete a file, similarly by entering the name and surname. However, after some fuzzing, we found that the surname wasn't properly validated.
While an error message is shown, the deletion operation seems to have gone through.
After some testing, we found that there was an additional validation for the filename before going ahead with the deletion, but this appears to be insufficient as well, only matching the start of the filename.
For instance, 1_22.txt
matches the created file 1_2.txt
.
I then created the three files below and tested a wildcard in the filename.
Surprisingly, all three files were deleted! It occurred to me that rm abc_abc*.txt
would have given this result, so we could hypothesise that a command injection could be performed.
Indeed, we received a shell! From here we can obtain the MD5 of the flag.
After registration, we get redirected to /users/<username>/files
, where we can upload files.
By testing with two accounts, we will also find that username enumeration is possible at /users/<username>
, since a valid username results in a 403 redirect to our own account, while an invalid username results in a 404 Not Found error.
Performing a username enumeration (using the dirb
wordlist) yielded the following valid usernames:
admin
root
builder
employee
staff
We will also find that while validation is performed on the /users/<username>
page, the application does not check whether we are the owner of the file when we request a file at /users/<username>/files/<filename>
. This constitutes an IDOR vulnerability.
I then scanned each username for potential files, and eventually found /users/employee/files/fileadmin
, which was the flag.
This was a game called Clicktracer. The client connects to the game server at port 20001, and winning the game gives us flags!
When playing in easy mode, the messages are logged to the console.
This was interesting, so I decided to spin up Wireshark to analyse the traffic.
The client-server communication appeared to be simple JSON messages. A client heartbeat is sent periodically to prevent the game from timing out, and the coordinates clicked by the user are sent as well. The server sends the client the coordinates of each target that is created.
We could beat the easy mode by implementing a custom client that "clicks" on each target that is received.
When we win the game, we get a URL to download the flag.
This was more complex, but we could still pick up some patterns if we look hard enough.
Some kind of TLV protocol is used, but the general idea remains the same. By capturing the traffic a few times, we can infer the meaning of each field!
The client starts the game with the following bytes. This is observed as the first packet in the capture. Note that the 4th byte is the "command" byte, which indicates which type of message this is. In this message, the command byte is 0x20.
A client heartbeat is periodically sent (command 0x14).
We could also observe that whenever we make a click, the following message is sent (command 0x2c). The only parts of this message that vary are the 4 bytes indicated by [ X ]
and [ Y ]
below - these are the coordinates that we clicked.
Similarly, the server acknowledges our clicks (with either a target hit or target missed message).
The server sends the next coordinates (command 0x38).
We could implement a similar client that solves the hard mode.
This is an SSRF in the galleryUrl
parameter. By requesting the /admin
internally, we gain access to the admin console: /gallery?galleryUrl=http://localhost:20011/admin
This wa PHP file upload challenge. We are provided with the following source code.
While most common PHP file extensions are blocked, .htaccess
was not!
We could upload a .htaccess
file to tell Apache to interpret some arbitrary file extension as a PHP file (e.g. .php16
).
Then, uploading any file with the .php16
extension results in RCE, and we can download the flag..
This was an SSH port, which we could access with root:root
. In the /challenge
directory, there was an encrypted flag and the Python program used to encrypt it.
In the history file, we could see the exact command that was used to encrypt it.
The vulnerability comes from the following part of the code:
While random.SystemRandom()
is cryptographically secure (it uses os.urandom()
), the behaviour when the debug flag is passed is interesting.
Note that getstate()
is called on the generator object, but the documentation clearly states that this will raise a NotImplementedError
.
This script was run with --debug
, resulting in getstate()
being called and NotImplementedError
being raised - so UNKNOWN_ERROR
= 1001 is the token.
We would therefore be able to reconstruct the key and obtain the flag.
In the Server
response header, we could see that the Apache Traffic Server (ATS) 7.1.1 was used,
This is vulnerable to CVE-2018-8004, a request smuggling vulnerability, and I came across a nice writeup here. The relevant patch we are looking at is here - a lack of validation for Content-Length
headers.
In the vulnerable version, even if the Transfer-Encoding
header exists, the Content-Length
header is used. This leads to a request smuggling vulnerability if the backend server processes the Transfer-Encoding
header instead of the Content-Length
header to decide where the request ends.
It was observed that whenever a request is made to /save.php
, an entry is appended to a "log file", which contains the cookies and the value of the X-Access
header.
Assuming that an admin visits the site, we could use a CL-TE request smuggling attack to direct the admin to /save.php
.
Consider the following payload:
The ATS server processes the Content-Length
header, and thus forwards the entire payload as a single request to the Nginx backend.
However, Nginx sees the Transfer-Encoding
header and decides that the first request ends early. This is a full, complete request.
This is then followed by a second request, which is not yet completed.
When the admin visits the site (the third request), his request is appended to the above incomplete request - the second and third request thus are processed as one single request.
Crucially, this request contains the admin's Cookie
and X-Access
headers.
In the log file, we can view the cookie:
Then, visit private.php
to view the flag.
We are provided with a PCAP file, containing some SMB traffic. There are some hints in the traffic:
What does this protocol use to align fields?
A lot of things can happen when structures are not properly aligned
But wait... is the actual value matter?
Not too much to find here... just regular backups
The content is not that useful as it looks like.
This prompted me to read up on the Microsoft documentation for SMB requests. One of the details was quite interesting, since the hint talked about alignment.
Optional padding follows the SMB_Data block of the SMB_COM_CLOSE. If present, the padding is used to align the SMB_Data.Bytes.Data block to a 16- or 32-bit boundary.
The padding byte in the SMB request exists in order to align the data that follows. But as the documentation specifies, the actual value of the padding byte doesn't matter.
Upon closer inspection, we will find that the padding in WriteX
(1 byte padding) and Trans2
(2 byte padding) requests contain the exfiltrated data.
The following script parses the PCAP and extracts the relevant data.
The result is the flag URL!
Here is the URL you are looking for: /U,rhbjaaCeDseVRQzEO.YsgXXtoGKpvUEkZXaoxurhdYnIlpJiGszZwUktVWTS,DabQAhvbEDQaNL_Dhsq.pposWkG-DtQdIVXNEWd.KbtYXvCek_gJuzIrDtMHfITFL/flag.png