mHackeCTF - How I hacked a service of which I knew nothing

Writeup ott 20, 2020

Sometimes looking at the scoreboard you can see that some team has stolen flags from you, or rather, gave you the exploit.
This is what happened to me: arrived at a dead end on another challenge, I took a look at the scoreboard and I saw that they were starting to steal flags on this service, mhackeErp, which I had never looked at yet.

TL;DR

You can find the part of the traffic I analyzed and the final exploit in our writeup repository here

Exploiting

The first thing I did was download some of the ".pcap" files that were automatically created on the server to analyze the traffic. Once opened with Wireshark I applied two filters: destination port 5000, 8080 or 8081 (the three exposed ports of this service) and frame containing MHACK{.
Immediately, several packages jumped to the eye that can hardly belong to the judge bot, in fact very repetitive operations were performed in those communications. But let's go step by step.

Wireshark

I applied the filter (tcp.port == 5000 or tcp.port == 8080 or tcp.port == 8081) and frame contains "MHACK{" and randomly chose one of the packages found. I looked at all communications from that session (Right click > Follow > TCP stream) and noticed many POST calls to :8080/api/tickets/ containing an XML in the payload. The strange thing was that these XMLs contained two suspicious fields: captcha, containing a simple mathematical formula, and userInsertedCaptcha, containing the result, as if a captcha was required to perform operations, but was sent as a response to the API with his result, thus being able to make the attacker decide which formula to use.

Traffic

You can find the traffic shown here in the repository here

Looking at the payloads I also noticed that the first call to :8080/api/tickets/ contained a payload of the type

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><methodCall name="create"><arguments><type>com.mhackectf.erp.Api.dto.CreateTicketDto</type><value><CreateTicketDto><title>test</title><content>test</content><author>test</author><priority>critical</priority></CreateTicketDto></value></arguments></methodCall>

to which the server responds with

a6
{"id":20,"title":"test","status":"PENDING","content":"test","author":"test","assignedTo":null,"priority":null,"createdAt":"2020-10-17T14:19:48.254Z","updatedAt":null}
0

while the second was

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><methodCall name="get"><arguments><type>com.mhackectf.erp.Api.dto.GetTicketDto</type><value><GetTicketDto><ticketID>19</ticketID><captcha>1*1</captcha><userInsertedCaptcha>1</userInsertedCaptcha></GetTicketDto></value></arguments></methodCall>

In subsequent calls, the ticketID decreased by one on each call.

I thought that perhaps with the first call a new ticket was created with the function com.mhackectf.erp.Api.dto.CreateTicketDto to see its id and that in subsequent calls the tickets were read from that id going backwards varying ticketID using the com.mhackectf.erp.Api.dto.GetTicketDto function.

Before being able to perform these operations it was important to log in, in fact the first calls of this communication were made to /oauth2/authorization/custom. Unfortunately I couldn't find the previous calls to register and log in, so I decided, for the first time since I started the analysis, to finally open the site to understand how authentication worked.

I visited the :8080/ page and was redirected to :5000/login where I also had the option to register by visiting:5000/register. Once the account was created, I had to press a button to authorize my account. Well, once I figured out how authentication worked, I went back on traffic.

I looked for requests made to :5000/register and I noticed that many registered with the username admin: apparently it was possible to register several times with a username already used. I wasn't sure if I needed to be admin to access all tickets, but I didn't know the service, so I couldn't know 😉.
Actually, only at the end of the CTF I discovered that it was actually necessary to be called admin, unless the administrator username had not been changed in the service settings.

Let's write the exploit: in summary, I first had to register as admin, call a POST to:8080/oauth2/authorization/custom to request a new authorization, as seen in the analyzed traffic, follow the redirection and do another POST request on the redirected url to authorize the account. Finally, I had to create a ticket with the first XML seen before to find out how many tickets were in the database and then make several calls with the second XML by varying the ticketID going backwards to get their content.

If you want, you can find the full exploit here

Funny fact

For nearly an hour the exploit was running but it only stole flags from the NOP, so it took no points. After searching for the cause for a long time I realized that the host was inserted only in the first request, in the others I had left the IP of the NOP (10.10.1.1) used in the test phase 😅

Tags

Riccardo Tornesello

Co-founder of the r00tstici team and Information Engineering student at the Salento University.

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.