Skip to main content

Exploiting a Banking Playground-Vulnerable Bank Application 🏦

·3673 words·18 mins·

I decided to spend some time playing around with a purposely vulnerable banking application. The goal of this walkthrough is to try replicate common issues I frequently encounter during real-world security assessments and document my thought process, testing approach, and findings.

Kudos to the lab creator, the vulnerabilities built into this project are highly relatable and mirror real scenarios in production environments. We will attempt to exploit them to gain hands-on experience and see how such flaws can be identified, exploited, and most importantly, remediated. At the end, I will be consolidating everything into a structured vulnerability table for easy reference including risk ratings, affected endpoints, and remediation recommendations.

Let the Hunt Begin

Lab Setup
#

For my setup I decided to to deploy using Docker as shown in below steps

docker-compose up build
sudo docker run -it --rm -p 5000:5000 vuln-bank

Take note of the Debugger PIN may be we can use it somewhere else: 627-198-522; may be we can use it somewhere

Key Application Features
#

Once the application launches, it’s immediately clear that it mimics the typical features you’d expect in a modern online banking platform. Users can register, log in, view account balances, transfer funds, pay bills, apply for loans, and manage cards. These are core workflows that real financial applications also implement, which makes the lab both engaging and realistic. Our goal here is explore not just the functionality, but also the common vulnerabilities that often accompany such features.

Methodology Approach
#

In practice, as an attacker the approach here is to start by mapping out the attack surface and identifying potential entry points. Typical attack vectors that came to my mind based on the features include:

  • Authentication Bypass Attempts: Testing for weak or misconfigured login mechanisms.
  • Enumeration Opportunities: Looking for differences in error messages or responses that reveal valid usernames or accounts.
  • Parameter Tampering: Modifying values in requests (e.g., account numbers, transfer amounts) to see if server-side validation exists.
  • Checking whether tokens are predictable, improperly scoped, or lacking secure flags well known as session hijacking
  • Probing for injection flaws in endpoints that handle transactions or search queries.
  • Business Logic issues: Exploring whether processes like loan approvals, manipulating account balance, unathorized transfer. or card creation can be bypassed or tricked by manipulating request flows.
  • LLM related vulnerabilties.

For this walkthrough, my review is going to simulate how a real adversary would approach this environment. Instead of following a rigid, structured methodology. I will take a more fluid approach. The idea is to engage with the application as an attacker would. This means

  • Reconnaissance will happen naturally as I interact with the app and discover features
  • Exploitation attempts will flow directly from observations, without waiting to complete a checklist.
  • Technical flaws (e.g., SQL injection, IDOR, broken access controls, weak session handling) will be called out as they appear.
  • Logic weaknesses (e.g., bypassing approval flows, manipulating transaction limits) we will attempt to exploit on the fo

APK Way
#

In addition to the web application, the lab also has set of vulnerable APK. This opens up an entirely different attack surface, mobile security testing. Unlike the web interface, mobile apps introduce unique vectors such as local storage issues, insecure use of device permissions, and reverse engineering opportunities so it will be good to explore that as well.

That said, it’s important to note that in most cases, the backend APIs remain the same. The mobile application is essentially another client communicating with the same API endpoints as the web interface. This means that weaknesses identified on the backend are often exploitable through both channels.

They also have some set of vulnerable APk, that will also be interesting to review as the mobile attack surface is quite different from the web but in most cases the backend API calls tend to be the same. I will drop a mobile application review soon

Swagger Documentation as a Map
#

Another key area of interest was the presence of Swagger documentation. This is essentially an interactive blueprint of the backend APIs, providing detailed definitions of available endpoints. Swagger not only reveals the API structure but also expected Payload, data types, response models an in some cases hidden functionality. What I can say is , from a security perspective, this is incredibly valuable.

Beginning the Security Review
#

Having explored the frontend of the application, we can now begin our application security review with the goal of hunting for vulnerabilities. You can fire up proxy tool of your choice, for my case I will be using HTTP Toolkit and configured it with an upstream proxy to Burp Suite.

When it comes to AppSec one of the most crucial steps is to understand the requests being sent and the responses being returned. By analyzing API calls, we uncover what is happening behind the scenes. I always say “”studying request/Response is an intriguing exercise and necessary when it comes to application security.""

User Registration
#

To begin, we’ll approach the application from the perspective of a normal user. The most logical starting point is the registration process, since this is often the first interaction any user has with a banking application. Creating an account will help us establish a baseline for how the application logic works and allows us to start interacting with the core features identified earlier.

Issue 1: Insecure Password Acceptance
#

The application accepts weak or insecure passwords without enforcing any complexity requirements. For instance, passwords such as 12345 or password are allowed without warning or rejection as indicated above.

Issue 2.: Username Enumeration
#

When attempting to register an account with an existing username, the application responds with a message such as “username already exists.” Attackers can use this to enumerate valid users by automating registration attempts with a list of common usernames or leaked credentials. This greatly aids targeted brute-force or credential-stuffing attacks.

Issue 3: Excessive Data Exposure
#

Upon intercepting the registration request, I observed that the application returns excessive and sensitive information in the response payload. This included fields such as accountNumber, debuginfo, account_number, is_admin, and user_ID, these values should never be returned at the point of registration, as they provide unnecessary insights into backend logic and internal identifiers.

Issue 4: Mass Assignment
#

Using the information exposed in the registration response (such as is_admin, user_id, and balance), I attempted to manipulate the request body by including additional fields that should not be user-controlled.For my test cases I injected the balance value in the request body (“balance”: 5000) that should not be user-controlled. And just like that the backend accepted this unvalidated parameter and updated the account balance directly of the new user

Issue 5: Privilege Escalation via Mass Assignment
#

Since mass assignment is possible, it was also feasible to tamper with the request body by adding an introduce additional parameter, and for my test case I injected is_admin": true and the backend processed this field without validation and created the user with administrative privileges.

Login
#

With the registration complete, the next step is to authenticate and explore the login functionality. Since login endpoints are high-value targets for attackers, I decided to test for potential SQL Injection (SQLi) vulnerabilities. I saved the login request (login.req) in my proxy tool, capturing the username and password parameters in the POST body. These fields are prime candidates for injection since they are used directly in the authentication logic.

To automate testing,we can leverage SQLMap, a powerful SQL injection exploitation framework. Because we already have an idea of the backend database engine powering the application, I specified it in the command to speed up detection.

sqlmap -r login.req -p username --technique=B --delay=5 --time-sec=10 --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" --level=5 --risk=3 --dbs  --ignore-code 500,401 --batch --dump-all

Issue 6: SQL Injection in Login (Boolean-Based Blind)
#

Based on the results we can see that the username parameter in the JSON body of the login request is vulnerable to SQL Injection. The parameter is injectable through a Boolean-based blind SQL injection technique using a WHERE/HAVING clause. TThis can allows an attacker to manipulate the SQL queries executed by the backend, enabling database enumeration and data extraction.

Issue 7: Weak Password Reset Mechanism (Brute Forceable PIN)
#

Another sensitive functionality in banking applications is the password reset process. In this case, the application uses a 3-digit Reset PIN for verification. This by by design is a red flags, as the total keyspace is only 1,000 possibilities (000–999) trivially brute-forceable by an attacker

I created a simple Python script that generates all possible 3-digit PINs and writes them to a wordlist file as shown below
Using this wordlist, we can perform fuzzing against the reset endpoint to test all possible PINs until the correct one is found. This can be done with tools like Burp Suite Intruder, ffuf, or a custom script. I used ffuf for my case and was able to a get a valid Reset PIN. In worst-case scenario, If administrative or high-value accounts are targeted, full compromise of the platform is possible.

 ffuf -u http://192.168.100.37:5000/api/v2/reset-password -X POST -H "Accept-Language: en-US,en;q=0.9" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36" -H "Content-Type: application/json" -H "Accept: */*" -H "Origin: http://192.168.100.37:5000" -H "Referer: http://192.168.100.37:5000/reset-password" -H "Accept-Encoding: gzip, deflate, br" -H "Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJ1c2VybmFtZSI6InNwbG9pdEBnbWFpbC5jb20iLCJpc19hZG1pbiI6ZmFsc2UsImlhdCI6MTc1ODM5NDQ1N30.r8NjR54xFsph1cUc296w5pD_LosZThhLi7ulSbCnCTw" -H "Connection: keep-alive" -d '{"username":"sploit@gmail.com","reset_pin":"FUZZ","new_password":"password1"}' -w 3_digit_pins_with_zero.txt

Authenticated Exploration
#

Upon successful login, we are presented with the application homepage. From here,we can interact with typical banking features. At this stage, the focus shifts to capturing and analyzing all API calls made by the frontend as we click around and interact with each feature. Using the proxy setup, every request/response pair is logged for review. This provides us with a complete map of the application’s functionality and backend endpoints.

With this data in hand, we can now proceed to review each feature focusing on what parameters are accepted, what responses are returned, OWASP Top 10 issues, and potential business logic isssues.

Funds Transfer Feature
#

Since the application includes a funds transfer functionality, which requires both a sender account and a recipient account number. I registered a second account so I could perform transfers between the two accounts.

Tuff Account: 3502134460
Sploit Account: 9605833681

When performing a transfer, the backend request is structured as follows, we can observe how the server processes transfer parameters. With this we can attempt to manipulate values (like amount) to test for potential flaws in transaction validation.

Issue 8: Transfer of Negative Amounts (Business Logic Flaw)
#

We can see the aplication allows negative values to be processed as valid transfer inputs. When a negative amount is entered, instead of being rejected, the appkication incorrectly adjusts the account balance. For instance in our case , in our account it had an initial balance of 900 but after making number of “transfer” –100. Instead of reducing the balance, the application recalculated the account balance incorrectly and reflected a new balance of 100, effectively allowing an illegitimate credit.

Beyond negative amount manipulation, another critical test for we can perform is to see if the application is resilient against race condition attacks. A race condition occurs when multiple requests are sent to the server concurrently, and the backend fails to properly synchronize or enforce consistency. In the context of funds transfers, this could lead to scenarios where fraudulent transactions slip through before validation checks completed

Issue 9: Race Conditions in Transfers & Bill Payments
#

Using Burp Suite, I intercepted a normal transfer request between the Sploit Account and the Tuff Account.I configured Burp to queue multiple identical transfer requests targeting the same transaction. Instead of forwarding them immediately, burp held them until I forwarded them all at once.By forwarding all the requests simultaneously, the backend is forced to handle multiple transfer operations on the same account balance at the exact same time. This is con be confirmed in due the reference number

You will note the application accepts proceses all payments and reuses the same transaction reference

Loan Application & Administrative Workflows
#

While testing the loan application process, I observed that the request is accepted upon submission but still requires approval before it is finalized. This indicates the presence of a maker–checker workflow, where administrative users (e.g., loan officers or managers, administrators) must authorize or reject loan requests.

From an attacker’s perspective, the question should be Can I escalate privileges to register as an administrator? or Can I identify and abuse hidden administrative endpoints?

Admin Account Creation Attempt 1:
#

While reviewing the previously exposed Swagger documentation, I identified an endpoint /admin/create_admin. This is an indication that administrative accounts could be created via the API. I attempted to interact with the endpoint using the following request:

curl -X POST "http://192.168.45.143:5000/admin/create_admin" -H "Content-Type: application/json" -d '{"username":"newadmin","password":"adminpass123"}'  
{  
 "error": "Token is missing"  
}

In our attempt the application needs a valid token, let add a token from the authenticated user, but after adding the token the application still does not accept the request and we get access is denied.

It seems the application verifies the token is valid, and also enforces a role or privilege check before allowing access to administrative functionality. Lets actually review decode the token to see the actual values and see if we can pull any jwt based attacks
From our review in the payload we can see special claim is_admin that is set to false,we can attempt to tamper with it and set it to true to see if we can get admin access.Also there is a posibility if we tamper with the ID we can get another users account and possibly lead to account takeover

For this we are going to forge the jwt token. JWTs are signed using a secret key to ensure integrity. If we modify the payload (is_admin or user_id), the signature will no longer match, and the server should reject the token.

To successfully exploit this, we need to obtain or crack the secret signing key used by the application. Using tools like jwt_tool.py or hashcat, we can attempt to brute-force the JWT secret key if it is weak or predictable and hulla just like that we have a secret key

[+] secret123 is the CORRECT key! We can verify this using burp suite and re-sign arbitrary JWTs after tampering with the payload claims.

Now lets go ahead an tamper with the payload claim and set admin to true and then retry sending the request again for admin creation

Armed with the forged token, I retried the previously blocked request to create an admin user and this time, the request succeeded, confirming that administrative functionality is now accessible with the tampered token.

curl -X POST "http://192.168.100.37:5000/admin/create_admin" -H "Content-Type: application/json" -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJ1c2VybmFtZSI6InNwbG9pdEBnbWFpbC5jb20iLCJpc19hZG1pbiI6dHJ1ZSwiaWF0IjoxNzU4MjIzODIwfQ.H4NlPfYu9842IK1egO2raAymb_nEHFazlaFbt0re5qk" -d '{"username":"newadmin","password":"adminpass123"}'

{
  "message": "Admin created successfully",
  "status": "success"
}

Let’s verify the credentials are working, and holla we are in. with this it open up a whole around of other attack vectors we can pull up

Issue 10: JWT Forgery Enables Privilege Escalation
#

The application uses JWTs for session management but relies on a weak secret (secret123) to sign tokens. Once the secret is discovered, attackers can forge arbitrary tokens. By modifying the is_admin claim, I escalated privileges from a normal user to an administrator and successfully created a new admin account.

After confirming that the JWT secret was weak and could be cracked (secret123), I explored whether it was possible to tamper with other claims beyond is_admin.I modified the JWT payload to replace my own user_id with that of another known user:

New Token

 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjozLCJ1c2VybmFtZSI6InNwbG9pdEBnbWFpbC5jb20iLCJpc19hZG1pbiI6ZmFsc2UsImlhdCI6MTc1ODIyNjA1NX0.6jBr0tnbr2A61HKV9BNCK6Ag29JWG2xTNUnvGRQaYE4

With the tampered token, I attempted to perform actions as the victim. Specifically, I issued a request to create a virtual card on behalf of this other account.

Issue 11: Account Takeover via JWT user_id Manipulation
#

Because JWTs are signed with a weak secret, attackers can re-sign modified tokens. By tampering with the user_id claim, I was able to impersonate another user and perform operations on their behalf, including sensitive actions like creating virtual cards.

Transactions History
#

While reviewing the transaction history feature, I observed that the application makes API calls that include an account_id parameter to fetch transaction records. By intercepting and modifying this parameter, I was able to access transaction history records of other customers.

Tampering of Account B with ID and we note we can be able see other users transaction history

Issue 12: Insecure Direct Object Reference (IDOR) in Transaction History
#

Description:
The transactions endpoint is vulnerable to Insecure Direct Object Reference (IDOR). By tampering with the account_id parameter in the request, an attacker can retrieve transaction records belonging to other customers.

Virtual Cards
#

While testing the virtual card creation and management functionality, I noted below issues

Issue 13: Lack of Encryption for Sensitive Parameters
#

When creating a virtual card, sensitive parameters (such as card type and card details) are transmitted unencrypted within API requests. This makes them susceptible to interception and manipulation if network traffic is compromised.

Issue 14: Lack of Input Validation in Card Creation
#

The API accepts arbitrary values for the card_type parameter. Although only two types are valid (Standard and Premium), tampering with the request (e.g., “card_type”: “Gold”) still results in successful card creation.

In the virtual cards created the application has quite a number of actions that can be performed in the card such updating the limit, freeze the card and checking the card details

When performing operations on a virtual card (e.g., updating the limit), the application responds with excessive information such as current balance, Card status and other backend metadata. The data discloses unnecessary insights into the card system’s inner workings.

Issue 16: Mass Assignment in Card Limit Update (Broken Access Control)
#

The endpoint /api/virtual-cards/{id}/update-limit is vulnerable to mass assignment. By adding unexpected parameters such as “balance”: 5000 in the request body, I was able to update the current balance of the card, even beyond the limit that had been specified. Tampered Request

the application successfully handles the request and updates the current balance in the card which is not meant to be greater than the limit that has been specified meaning there is a broken access control.

Bill Payments Review
#

Issue 17: Unauthenticated Access to Billers Endpoint
#

The /api/billers endpoint responds to requests even without an authentication token. This means attackers can directly query the endpoint without logging into the application Request A

Request B- After removing the token the application still gives a valid response. The category_id parameter within the request can be manipulated to reveal details of different billers in the system

Appendix
#

Vulnerability Tables
#

Issue No.TitleRisk RatingAffected Endpoint / FeatureImpactRecommendation
1Weak Password PolicyMedium/registerAllows weak/insecure passwords, leading to account compromise.Enforce strong password policy and server-side validation.
2Username EnumerationMedium/registerAttackers can confirm valid usernames.Return generic error messages and apply rate-limiting.
3Excessive Data ExposureHigh/register responseLeaks sensitive data (account_number, balance, user_id, password in clear text).Return only minimal data and mask sensitive fields.
4Mass Assignment in RegistrationCritical/registerAttackers can set unauthorized fields like balance.Implement input whitelisting and enforce server-side validation.
5Privilege Escalation via Mass AssignmentCritical/registerAttackers can set "is_admin": true to gain admin privileges.Restrict sensitive fields and enforce RBAC.
6SQL Injection in LoginCritical/loginBoolean-based blind SQLi enables DB enumeration and bypass.Use parameterized queries and input sanitization.
7Weak Password Reset MechanismHigh/resetBrute-forceable 3-digit PIN leads to account takeover.Use strong reset tokens, MFA, and rate-limiting.
8Transfer of Negative AmountsHigh/transferBusiness logic flaw allows illegitimate credits.Validate transaction inputs and enforce positive values only.
9Race Condition in TransfersHigh/transferDouble-spending or inconsistent balances possible.Implement atomic transactions and idempotency checks.
10JWT Forgery via Weak SecretCriticalAll authenticated endpointsAttackers can forge tokens and escalate to admin.Use strong secrets, rotate keys, and avoid client-side privilege claims.
11JWT Tampering leading to Account TakeoverCriticalAll authenticated endpointsAttackers can impersonate other users by changing user_id.Store IDs server-side and enforce strict access control.
12IDOR in Transaction HistoryHigh/transactionsAttackers can view other users’ transaction history.Enforce authorization checks and use opaque identifiers.
13Lack of Encryption in Card CreationMedium/virtual-cards/createSensitive parameters sent unencrypted.Enforce TLS and secure transmission.
14Lack of Input Validation in Card CreationMedium/virtual-cards/createArbitrary card types can be created.Strict server-side validation of card type.
15Excessive Data Exposure in Card ManagementMedium/virtual-cards/*Responses leak sensitive balance and card state info.Minimize response data to only what’s necessary.
16Mass Assignment in Card Limit UpdateCritical/virtual-cards/{id}/update-limitAttackers can inflate balances beyond limit.Whitelist update fields and enforce server-side validation.
17Unauthenticated Access to Billers EndpointHigh/billersEndpoint responds without token.Enforce authentication on all endpoints.
18Information Disclosure via Category ManipulationMedium/billers?category_id=Attackers can enumerate billers by tampering category IDs.Validate inputs, apply authorization, and limit disclosure.

Conclusion
#

Overall, the application is good for leaning application security. I’ve enjoyed hunting down some of the same issues I’ve run into during real-world engagements. The fun part? I explored it from scratch, no guides, just recon, tampering, and attempting to breaking things What I’ve shared here is just the surface. There are definitely more bugs hiding in the code that I didn’t touch or didn’t manage to pick up this round. If you’re reading this, go ahead and dig deeper. you’ll likely find your own paths to break it.

For me, this wasn’t just about the usual web bugs. I’m also keen on diving into LLM vulnerabilities and seeing how the attack surface evolves as AI gets integrated into real-world applications. The game keeps changing, and so does the hunt. Stay curious. Stay breaking. If I get some time , I intend to perform source code review to uncover the insecure coding practices that make the application exploitable and how to fix them , am taking it as a challenge.

Reference https://github.com/Commando-X/vuln-bank