Our task:
TryBankMe has launched a web application that will serve as its customer-
facing portal for digital banking services. Through this platform, customers
can sign up for accounts, apply for loans and cards, and manage financial
transactions.
Given the sensitive nature of financial applications, this component of the
assessment focuses on identifying security vulnerabilities that could
compromise user data, application integrity, or transactional accuracy. The
web application is considered a cornerstone of the TryBankMe offering, and
its security must be validated ahead of the fast-approaching public release.
Your task is to perform a penetration test of the web application for a wide
range of web-based vulnerabilities, confirm their impact through exploitation,
and report them in a structured, professional format.
here is the scope:
Exam –Scope
Assessment target: http://10.200.150.100/
The application makes use of a supporting API that is in-scope as well.
Vulnerability Name: Business Logic Flaw — Negative Transaction Amounts
Risk Rating (Abstracted CVSS Score): High (7.5)
Flag Value: THM{e2e67e74-acb4-434b-9d4d-fdcfad28eb8b}
Description of Vulnerability:
The /api/v1.0/transaction endpoint fails to enforce business logic constraints
on the amount parameter. This flaw allows authenticated users to submit
negative transaction values, effectively crediting their own accounts or
debiting others in violation of intended financial workflows.
If exploited in a production environment, this could enable attackers to
bypass balance checks, perform fraudulent transfers, and manipulate
financial records without detection.
Attack Path
Step 1 – Reconnaissance and Authentication
While interacting with the /api/v1.0/transaction endpoint, I authenticated
using a valid Bearer token obtained from the application’s login process. This
confirmed that the API was accessible over the network with standard user
credentials.
Step 2 – Identifying the Transaction Endpoint
The application exposed the following POST endpoint for creating
transactions:
POST /api/v1.0/transaction
Content-Type: application/json
Authorization: Bearer <JWT>
Initial legitimate requests showed that the server processed JSON input
containing:
account_from
account_to
amount
message
Step 3 – Input Manipulation
Testing with valid positive amount values succeeded as expected. I then
deliberately altered the payload to include a negative amount ("amount": -1)
to evaluate server-side validation:
{
"account_from": "96a0aa58-8d03-428a-b99a-3213d9b749f7",
"account_to": "96a0aa58-8d03-428a-b99a-3213d9b749f7",
"amount": -1,
"message": "cdfdsf"
Step 4 – Exploiting Business Logic Flaw
The server accepted the transaction without rejecting the negative amount.
The API responded with HTTP 200 OK and returned a transaction record along
with sensitive information (in this case, the flag for the challenge):
HTTP/1.1 200 OK Server: Werkzeug/3.1.3 Python/3.12.3
Date: Sun, 10 Aug 2025 20:19:27 GMT
Content-Type: application/json
Content-Length: 334
Access-Control-Allow-Origin: http://10.200.150.100
Vary: Origin
Connection: close
{"details":{"account_from":"96a0aa58-8d03-428a-b99a-
3213d9b749f7","account_to":"96a0aa58-8d03-428a-b99a-
3213d9b749f7","amount":-1,"date":"Sun, 10 Aug 2025 20:19:27
GMT","message":"cdfdsf","transactionNumber":"d8a659f3-3ac0-40d6-8ebb-
a94e2d06c832"},"flag":"THM{e2e67e74-acb4-434b-9d4d-
fdcfad28eb8b}","message":"Transaction performed"}
Vulnerability Name: Stored Cross-Site Scripting (XSS) — Transaction
Description Field
Risk Rating (Abstracted CVSS Score): High (7.4)
Flag Value: THM{99a3a2f1-9c97-421f-bb3f-26a67707d7a6}
Description of vulnerability:
During testing of the /transactions functionality, I identified that the
application allowed free-text input for the transaction description field. This
input was later rendered back to other users without sanitization or HTML
encoding.
Attack Path
Step 1 – Locating User Input
While reviewing the /transactions functionality, I identified that the
application allowed a free-text description field for transactions. This content
was later displayed to other users without apparent sanitization or encoding.
Step 2 – Crafting a Malicious Payload
I submitted the following HTML payload in the transaction description:
<img src=x onerror=(document.cookie='XSS=XSS')>
Step 3 – Persistence and Trigger
The application stored the malicious payload in its database and rendered it
as raw HTML when the transaction details page was viewed. This resulted in
the payload being executed in the browser of any user (including
administrators) who opened the affected transaction URL.
Step 4 – Verification
When visiting:
http://10.200.150.100/transactions/b6cab4f6-6066-4e03-8cd1-f23c26ea1793
the JavaScript embedded in the description executed successfully, confirming
the XSS vulnerability. To confirm exploitation according to TryHackMe’s XSS
verification process, I executed:
curl -H 'Content-Type: application/json' \
-X POST \
-d '{ "username" : "user", "password" : "useruser" }' \
http://10.200.150.100:8080/api/v1.0/xss
Output:
{"flag":"THM{99a3a2f1-9c97-421f-bb3f-26a67707d7a6}","message":"XSS
Success"}
Vulnerability Name: Insecure Direct Object Reference (IDOR) — Unauthorized
Access and Modification of Card Data
Risk Rating (Abstracted CVSS Score): High (7.8)
Flag Value: THM{c92501d8-5aa3-49b1-9a4f-c44d05094901}
Description of vulnerability:
The /api/v1.0/card endpoints fail to enforce proper authorization checks on
the cardNumber parameter. This allows an authenticated user to supply
another user’s card number and retrieve or modify sensitive card data,
including PAN, CVV, expiry date, and account status.
As a result, any logged-in user can access or alter card information belonging
to other accounts without consent. This is a direct violation of access control
best practices and exposes sensitive payment card data.
Attack Path
Test Setup:
To verify this, I created two user accounts in the application (race1 and
race2). Each account was issued two card numbers:
Race1 user cards:
4297928360068775
4157161488196
Race2 user cards:
30094273509049
4767770313488396834
After recording these card numbers, I logged in with each account to confirm
that they could only see their own cards through the web interface. I then
used Burp Suite to intercept and modify API requests to test cross-account
access.
Testing Endpoint 1 — Card Details Disclosure (GET)
While authenticated as race1, I made a GET request to retrieve card details
for 4767770313488396834 (a card belonging to race2)
Request:
GET /api/v1.0/card?cardNumber=4767770313488396834
Authorization: Bearer <race1-token>
Response:
HTTP/1.1 200 OK
{"active":58,"cardNumber":"4767770313488396834","cvv":"510","expiry":"1
/1","flag":"THM{c92501d8-5aa3-49b1"}
The response contained:
The full Primary Account Number (PAN)
The CVV
The expiry date
The first half of the challenge flag: THM{c92501d8-5aa3-49b1
This confirmed that the endpoint allowed retrieval of another user's sensitive
card data.
Testing Endpoint 2 — Card Status Modification (PUT)
While authenticated as tester (a separate account), I attempted to change
the active status of the same race2 card
Request:
PUT /api/v1.0/card
Authorization: Bearer <tester-token>
Content-Type: application/json
{"cardNumber":"4767770313488396834","active":false}
Response:
HTTP/1.1 200 OK
{"details":
{"active":0,"cardNumber":"4767770313488396834","cvv":"510","expiry":"1/
1","flag":"49b1-9a4f-c44d05094901}"},"message":"Card updated"}
The endpoint accepted the request with tester account toekn and
deactivated the card of race2 user, returning the second half of the flag:
49b1-9a4f-c44d05094901}.
Flag Assembly:
By combining the two halves obtained from the GET and PUT requests, the
complete flag is:
THM{c92501d8-5aa3-49b1-9a4f-c44d05094901}
Vulnerability Title: Race Condition in /api/v1.0/loan
Severity: High – CVSS v3.1 Base Score: 8.1
Affecteded Host: 10.200.150.100:8080
Description of Vulnerability
During testing of the loan request API endpoint, it was observed that the
server exhibits inconsistent and prolonged response times when handling
multiple near-simultaneous requests from separate accounts.
Two test accounts, race1 and race2, were created and used to send multiple
parallel POST requests to the /api/v1.0/loan endpoint. The requests were sent
in alternating order (race1, race2, race1, race2, etc.) with minimal delays
between them.
Normal requests to the endpoint typically return within ~1 second. However,
when the above pattern was executed with 30 consecutive parallel requests,
certain requests took significantly longer to complete, ranging from 1,328
milliseconds to 2,338 milliseconds.
The inconsistent delays strongly indicate that the backend may not be
implementing adequate locking or transaction handling, potentially allowing
multiple requests to be processed simultaneously in a way that could alter
the intended business logic (e.g., issuing multiple loans, bypassing limits, or
double-spending).
Although repeated attempts were made to exploit this behavior to obtain the
challenge flag, it was not successfully retrieved within the testing timeframe.
The behavior remains exploitable under different conditions or with
optimized timing.
Proof of Concept
Normal request example:
POST /api/v1.0/loan HTTP/1.1
Host: 10.200.150.100:8080
Authorization: Bearer <JWT>
Content-Type: application/json
{"amount":1000,"description":"need for assurance"}
Observed behavior under race test:
Multiple requests taking ~1400ms to ~2300ms instead of the usual
~1000ms.
Alternating between accounts increased the probability of overlapping
transaction execution.
Test method:
Created two accounts: race1 and race2.
Sent 30 back-to-back requests alternating between the two accounts with
near-zero delay.
Measured server response times, identifying consistent anomalies.