Follow along with my YouTube video below!
Visual Workflow Summary
Summary:
A JWT (Java web token) token challenge that initially has us re-writing the token to include a key identifier header (kid). Following, a red herring derived from comments about SQL front end operations. SQL injection was not possible due to the use of MD5 on the kid header, which prevents the passing of standard payload strings and parsing in the backend. This lead us to perform a known SQL md5 attack to leak the conductors signing key to ultimately sign our own ticket and retrieve the flag.
Technical Summary
Web app enumeration
Edit JWT token
Add the kid header
Identify vuln SQL MD5
Pass known payload
Receive conductor signing key
Sign own key and post
Receive flag
References:
Challenge
The challenge provides us with some ideas of what to expect. First there is talk about fare evasion, but more so is the comment about signing our own tickets this time.
Web Application Review
Our web application has a narrow surface of functionality and therefore a narrow attack surface initially. Two buttons, suggesting a possible higher permissions path through the conductor button. However later review of the web application reveals there is no known control over the conductor button and no corresponding function was found in the front end.
Clicking "I'm a Passenger" executes a later discovered "Pay function" which in turn prompts the upper right window with a message to the client application. This message suggests we might need to be a conductor and that we need to sign our own tickets. The final text block of the string is actually a signing key, minus the "?".
Reviewing the source code of the page, provided us with everything we needed to define the scope of our attack. Developer comments were found in the index.html file. Three comments were present eluding to the following:
1. SQL is present
2. Kid header is present in queries to the backend.
3. MD5 converts the kid header value before passing to the backend DB
At first, attempts to pass SQL injection payloads seems possible but if md5 will hash any queries we pass, then we can't pass standard queries. let's circle back to this in the exploitation phase and finish reviewing the web application.
Burping the Request
Here we have an access_token acting as our JWT token. The name helps us deduct this is a JWT token, as well had you put this token in cyberchef and decoded, you would have seen this was a JWT token.
With the access token, we can leverage a Java Web Token decoder to see what underlying information is provided.
While one might try passing SQL payloads in the JWT token, we have to remember that the token is converted into a MD5 Hash before then being passed to the SQL database. The error below suggests we have left our kid on the train. Well this is a clue related to using the kid header, which will require some research on our part. As well we can see an authentication check in the success field.
If we add the kid header, we get a different response from the server as seen below. The authentication check still remains false.
Researching the Vulnerability
At this stage we haven't clearly identified the vulnerability. Initial research suggests there is a possible vulnerability with regards to the kid header, which while not present in the initial JWT token, we can simply add it. However, we still can't pass a standard SQL injection payload.
This is where SQL injection via MD5 hash becomes a relevant research subject. This is somewhat of a classic security problem that was solved in a CTF challenge back in 2010. The idea was to generate a hash of an SQL payload short enough to be contained within a md5 hash and there is an entire writeup I referenced that I have added in the reference section if you want to read more.
Exploitation
Here is a relevant article with known MD5 hashed SQL payloads, seen in the image below. https://book.hacktricks.xyz/pentesting-web/sql-injection
We are dealing with the same structure of query as referenced in the above link under MD5 SQL bypass. The MD5 hash is used as raw output in relation to an authentication check which initially denotes false. The hacktricks article which outlines this raw hash authentication bypass can be seen in the image below. The key payload is ffifdyop.
Editing our JWT token and adding the ffidyop string in the kid header and passing through burpsuite returns with the conductors key.
We then sign our JWT token with the conductor's signing key and we receive the flag.
Comments