Skip to main content

[LeHack] - Poor

·3 mins· 0 · 0 ·
CTF Web LeHack
JustinType
Author
JustinType
Auditor - Pentester @ Wavestone
Table of Contents
LeHack2025 - This article is part of a series.
Part 2: This Article

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:

intro

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:

doc

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).

burp1

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:

jwt1

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.
    jwtool
A JWT is encoded in base64, the jwtools script allows you to decode the token directly but it is also possible to do this from the [jwt.io] site ( https://jwt.io/) or directly from the command 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:

error

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:

read_all

This is therefore accepted in the production environment and enables us to obtain the flag :

flag

🚩 Flag : leHACK{n0lI73_73_84S74Rd3s_c4R80RunD0RuM}

LeHack2025 - This article is part of a series.
Part 2: This Article