Introduction
While conducting vulnerability research on a private program, which I’ll refer to as «Redacted» for confidentiality reasons, I discovered several intriguing security flaws. These included broken access controls and a vulnerable JSON Web Token (JWT) implementation. This chain of vulnerabilities allowed me to orchestrate a «0-click account takeover» and gain access to private information belonging to millions of users, as well as sensitive data.
Identification
Applications nowadays use tokens to communicate with their services and manage sessions, request resources, etc. In this case, the application Redacted used JWT as a means of session management in its API. Typically, the way to obtain a valid token is by generating one through some form of authentication or similar means. However, in this specific case, we were able to obtain a JWT through valid authentication. The utilized flow was as follows:
At this point, we managed to obtain a valid token like the following:
Request :
POST /api/v2/login HTTP/2
Host: redacted.com
Content-Type: application/x-www-form-urlencoded
User-Agent:
Connection: Keep-Alive
Accept-Encoding: gzip, deflate, br
Content-Length: 88
password=passwordExample&username=usernameTest
Response
HTTP/2 200 OK
Date: Sat, 15 Jun 2024 00:07:06 GMT
Content-Type: application/json;charset=UTF-8
Pragma: no-cache
Cache-Control: no-store
X-Content-Type-Options: nosniff
X-Xss-Protection: 1; mode=block
{"access_token":"eyJhbGciOiJIUzI1NiJ9.eyJkdCI6IjIwMjMtMDctMTUgMDA6MDc6MDYuMzQiLCJ1c2VyX25hbWUiOiJkdW1teUBtYWlsLmNvbSIsInNjb3BlIjpbInJlYWQiXSwibmFtZSI6IlJPQkVSVE8iLCJleHAiOjE2MjEwMDMwMzcsImF1dGhvcml0aWVzIjpbIlJFREFDVEVEIl0sImp0aSI6ImNndWkxYjgzLTQ5NzgtODc5OS1hOWQ5LWRmNjI5NmZnODk2MSIsImVtYWlsIjoiZHVtbXlAbWFpbC5jb20iLCJhY2NvdW50IjoiMjg4NzQ1MzY0MCJ9.6XIkjdGPbPVMr-2F7Mn6PbejTgzjOojdrfYUTfgHVbC","token_type":"bearer","refresh_token":"eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX25hbWUiOiJkdW1teUBtYWlsLmNvbSIsImF1dGhvcml0aWVzIjpbIlJFREFDVEVEIl0sImNsaWVudF9pZCI6InJlZGFjdGVkIiwiZHQiOiIyMDIzLTA3LTE1IDAwOjA3OjA2LjM0Iiwic2NvcGUiOlsicmVhZCJdLCJhdGkiOiJjZWVjMWI4My00OTc4LTQ3OTktYTlkOS1kZjYyOTZkYzc4OSIsIm5hbWUiOiJyb2JlcnRvIiwiZXhwIjoxNzIzNTk0MDI2LCJqdGkiOiJmMjhiYzg3Ny1hMDczLTQzYjMtYWFlMi05NzNhNmRlYTJkOTMiLCJlbWFpbCI6ImR1bW15QG1haWwuY29tIiwiYWNjb3VudCI6IjI4ODc0NTM2NDAifQ.YYUcz3KjTo0gbKvpbQrg4UY_V6N5Fi8P7k_WMa1Tyfd"}
access_token : A short-lived token used to authenticate a user and grant access to specific resources within a computer system. Typically, it contains information about the authenticated user and associated permissions, and is used in each service or resource request to demonstrate the user’s authorization.
{"alg":"HS256"}{"dt":"2023-07-15 00:07:06.34","user_name":"dummy@mail.com","scope":["read"],"name":"ROBERTO","exp":1621003037,"authorities":["REDACTED"],"jti":"cgui1b83-4978-8799-a9d9-df6296fg8961","email":"dummy@mail.com","account":"2887453640"}
refresh_token : A long-lived token used to obtain a new access token when the current one expires. Unlike the access token, the refresh token is kept on the client and is not sent with every service request. It is typically used to keep the session active without requiring the user to re-authenticate each time the access token expires.
{"alg":"HS256"}{"user_name":"dummy@mail.com","authorities":["REDACTED"],"client_id":"redacted","dt":"2023-07-15 00:07:06.34","scope":["read"],"ati":"ceec1b83-4978-4799-a9d9-df6296dc789","name":"roberto","exp":1723594026,"jti":"f28bc877-a073-43b3-aae2-973a6dea2d93","email":"dummy@mail.com","account":"2887453640"}
Common JWT vulnerabilities :
- None Algorithm: Configuration where the JWT token is not signed, allowing attackers to modify the token’s content without detection.
- Brute Force Attacks: Repeated attempts to guess the JWT token contents or signing keys.
- Token Replay: Reusing a previously issued JWT token to access resources or perform actions for which authorization should no longer be granted.
- Token Expiration Bypass: Using a JWT token after its expiration period has passed.
- Data Injection: Manipulating the data contained within the JWT token to escalate privileges or access unauthorized resources.
Once we obtained a valid JWT, we could conduct tests or even use a tool called JWT_TOOL to audit the JWT’s security. After conducting thorough tests, the previous token showed no signs of vulnerability.
but why are you talking about JWT vulnerabilities?…..
The vulnerability
Although the token generated in the authentication flow was not vulnerable, upon understanding the application’s functionality and business logic, it had a feature that allowed account sharing with third parties, which is common in applications where additional authentication is not required.
To enable the account sharing feature, it first needed to be activated within an administrative panel. At this point, I identified an endpoint, /api/v2/accounts/share/redacted
, where, for some reason, the response to the request was another JWT token. This facilitated the exchange of information.
Request :
POST /api/v2/accounts/share/redacted HTTP/2
Host: redacted.com
auth: eyJhbGciOiJIUzI1NiJ9.eyJkdCI6IjIwMjMtMDctMTUgMDA6MDc6MDYuMzQiLCJ1c2VyX25hbWUiOiJkdW1teUBtYWlsLmNvbSIsInNjb3BlIjpbInJlYWQiXSwibmFtZSI6IlJPQkVSVE8iLCJleHAiOjE2MjEwMDMwMzcsImF1dGhvcml0aWVzIjpbIlJFREFDVEVEIl0sImp0aSI6ImNndWkxYjgzLTQ5NzgtODc5OS1hOWQ5LWRmNjI5NmZnODk2MSIsImVtYWlsIjoiZHVtbXlAbWFpbC5jb20iLCJhY2NvdW50IjoiMjg4NzQ1MzY0MCJ9.6XIkjdGPbPVMr-2F7Mn6PbejTgzjOojdrfYUTfgHVbC
Origin: client.redacted.com
Content-Type: application/json
Connection: Keep-Alive
Accept-Encoding: gzip, deflate, br
Content-Length: 0
Content-Type: application/json
Connection: Keep-Alive
Accept-Encoding: gzip, deflate, br
Content-Length: 0
Response :
HTTP/2 200 OK
Date: Sat, 15 Jun 2024 05:09:51 GMT
Content-Type: application/json
X-Ratelimit-Limit-Second: 80
X-Ratelimit-Remaining-Second: 71
{"code":"200","message":"OK","response":[{"account":"2887453640","account":"Main","link_account":"true","token":"eyJhbGciOiJIUzUxMiJ9.eyJhbGciOiJIUzUxMiJ9eyJzaGFyZV9hY2NvdW50IjoidHJ1ZSIsImVtYWlsIjoiZHVtbXlAbWFpbC5jb20iLCJhY2NvdW50IjoiMjg4NzQ1MzY0MCIsIm5hbWUiOiIiLCJleHAiOjE3MjE0NTIxOTF9.TypuHsZfNt2eHciY8ovQNclQrSJ9xzAeICHbkOlA4g8rHEAiOwfSGyoM_YlN1RRGtwzof7-T0OwXPmHwHT5ihG"}]}
New token :
{"alg":"HS512"}{"alg":"HS512"}{"share_account":"true","email":"dummy@mail.com","account":"2887453640","name":"","exp":1721452191}....
Once I identified the newly generated JWT, I proceeded to conduct further tests and attempted to attack the JWT. Before doing so, I questioned the following:
- Can the new JWT make requests to other endpoints?
- If it’s vulnerable, to what extent do I have access?
- Can this token generate more tokens?
The Impact
Accessing personal data
Account take over (ATO)
Reset password functionalitty