[LeHack] - Poor
Table of Contents
LeHack2025 - This article is part of a series.
Description #
The target of this challenge is the POOR (Proof of Overwhelming Richness) web application found at the url https://poor.wargame.rocks
.
The application appears to allow managing personalized Bitcoin wallets via the use of user information, as shown on its homepage:
Using the application #
To use the application, you need to obtain a token from a valid user and then interact with the API set up.
To retrieve a token, an example is available on the home page via a test user:
curl --request POST --url https://poor.wargame.rocks/cognito-proxy/oauth2/token --data grant_type=client_credentials --data client_id=1qconf4f2v146v0qi6kjn25l3m --data client_secret=ni1e9k9a25vp5eq2karankjn6atroof1r354s7havetpjunkj2d
Once the token has been retrieved, here’s the structure of the command used to interact with the API:
curl --request GET --url https://poor.wargame.rocks/[endpoint_api] --header 'Authorization: Bearer [TOKEN]' --header 'X-Env: dev'
The API documentation describes all available endpoints:
One endpoint is of particular interest here: /api/admin/bitcoin
, which retrieves the Bitcoin object of the user whose token has been supplied.
The Bitcoin object has only one key
attribute, which is a character string.
The key attribute most certainly stores the flag.
By sending a Burp request (corresponding to the curl request in CLI) to the endpoint /api/admin/bitcoin
, we obtain the value of the key
attribute of the test user’s Bitcoin object (here “–demo–”) and a message telling us that the same request on the production environment would give us access to the master key (certainly corresponding to the flag).
Our goal is now quite clear: to recover the test user’s Bitcoin object on the production environment.
Blocking the environment #
Using the command to retrieve a token with the test user results in a JWT:
This JWT has several fields, 2 of which are interesting:
- The scope**: this describes the environment in which this JWT is valid and the rights granted by this JWT. Here, the test user’s JWT gives all rights, but only in the env/dev environment.
- Issuer** or issuer: describes who issued the token, in this case a cognito proxy hosted on an AWS instance.
echo [JWT] | base64 -d
.If we try to change the X-Env
header directly in the request to endpoint /api/admin/bitcoin
, we get an error message:
An API verification is therefore performed on the issued token: if the token is issued for a given environment (here env), then it is not possible to modify it later.
The vulnerability therefore lies not in the verification of the scope by the API, but certainly in the allocation of the scope by the issuer.
Change of environment #
Attempting to modify the scope directly from the token generation command by adding the data --data scope='YoloSwag'
:
curl --request POST --url https://poor.wargame.rocks/cognito-proxy/oauth2/token --data grant_type=client_credentials --data client_id=1qconf4f2v146v0qi6kjn25l3m --data client_secret=ni1e9k9a25vp5eq2karankjn6atroof1r354s7havetpjunkj2d --data scope='YoploSwag'
The following error message appears:
{"error":"Should not happens, empty scope ? really ?!?"}
A hint from the test designer that we’re on the right track.
By changing the scope to “env/prod”, we obtain a JWT that no longer specifies the “env/dev” scope:
This is therefore accepted in the production environment and enables us to obtain the flag :
🚩 Flag : leHACK{n0lI73_73_84S74Rd3s_c4R80RunD0RuM}