Share
## https://sploitus.com/exploit?id=975D545B-C809-541F-8CDD-3A25A1C7E8DD
# NOISY_ECHIDNA β€” Race Condition CTF

This repository implements a small, intentional-toy web challenge that demonstrates a Time-of-Check–Time-of-Use (TOCTOU) race condition in a funds transfer API. The goal: build, run, and exploit the race window to achieve a negative balance and recover the flag.

---

## Quick facts

* **Category:** Web / API (TOCTOU race condition)
* **Primary language:** Python (Flask)
* **Flag:** `FLAG{echidnas_dig_fast_and_race_conditions_execute_faster}`
* **Ports:** 5000 (default)

---

## Contents

* `app.py` β€” Flask application (vulnerable transfer endpoint)
* `exploit.py` β€” simple threaded exploit that demonstrates the issue
* `Dockerfile`, `docker-compose.yml` β€” container configuration for easy testing
* `requirements.txt` β€” Python dependencies
* `README.md`, `BUILD.md`, `WALKTHROUGH.md` β€” documentation (this file consolidates and cleans up)
* `templates/index.html` β€” small landing page used by the app

---

## Quick start (Docker β€” recommended)

1. From the project root:

```bash
docker-compose up --build
```

2. Open the app in your browser: `http://localhost:5000`
3. Run the exploit (from another shell):

```bash
python exploit.py
```

4. When finished:

```bash
docker-compose down
```

---

## Quick start (Local Python)

1. Create and activate a virtualenv (recommended):

```bash
python -m venv venv
source venv/bin/activate   # Linux/macOS
venv\Scripts\activate     # Windows (PowerShell)
```

2. Install dependencies:

```bash
pip install -r requirements.txt
```

3. Run the app:

```bash
python app.py
```

4. Run the exploit in a second terminal:

```bash
python exploit.py
```

---

## Expected behaviour and outputs

* `GET /api/account/` returns a small JSON object for that account (username, name, balance, account number).
* `POST /api/transfer` performs a balance check then deducts funds. The app intentionally inserts a short sleep to create a race window.
* When the race is exploited the server will return the flag in the transfer response and `GET /api/stats` will report an account with a negative balance.

Example (successful exploit):

```json
{
  "status": "success",
  "message": "🎯 EXPLOIT SUCCESSFUL! Negative balance achieved! FLAG{...}",
  "transaction_id": 5,
  "from_balance": -20.0,
  "to_balance": 170.0,
  "flag": "FLAG{echidnas_dig_fast_and_race_conditions_execute_faster}"
}
```

---

## How the vulnerability works (short)

1. Server checks account balance (Time-of-Check).
2. The code then waits for a short time (`time.sleep(0.01)` by default).
3. The balance is deducted (Time-of-Use) without re-checking or using a lock.

Multiple concurrent requests can all pass the balance check before any deduction occurs, allowing the sum of successful transfers to exceed the original balance.

---

## Tuning the challenge

* To make exploitation easier or harder, modify the artificial delay in `app.py`:

```python
# default: 0.01 (10 ms)
time.sleep(0.01)
```

* Adjust starting balances in `app.py` under the `accounts` dictionary.
* Adjust the exploit parameters in `exploit.py`: `TRANSFER_AMOUNT` and `NUM_THREADS`.

---

## Commands & debugging

Check the service:

```bash
curl http://localhost:5000/api/account/dr_tachyglossus
```

Reset accounts:

```bash
curl -X POST http://localhost:5000/api/reset
```

View transactions:

```bash
curl http://localhost:5000/api/transactions
```

Check stats:

```bash
curl http://localhost:5000/api/stats
```

Docker troubleshooting:

```bash
# container status
docker ps
# logs
docker-compose logs --tail=200
# port conflicts
lsof -i :5000         # Linux/macOS
netstat -ano | findstr :5000   # Windows
```

---

## Short developer notes (for reviewers)

* The app uses an in-memory datastore (resets on restart) β€” this keeps testing deterministic for a CTF.
* The vulnerability is intentional for training purposes; do not deploy this code in production.
* A simple fix is to perform the balance check and deduction under a lock or use database transactions with row-level locking.

Suggested minimal fix:

```python
with balance_lock:
    if accounts[from_user]["balance"] < amount:
        return jsonify({"error": "Insufficient funds"}), 400
    accounts[from_user]["balance"] -= amount
    accounts[to_user]["balance"] += amount
```

---

## Submission checklist

* `app.py`
* `exploit.py`
* `Dockerfile` and `docker-compose.yml`
* `requirements.txt`
* `templates/index.html`
* `README.md` (short), `BUILD.md` (build steps), `WALKTHROUGH.md` (detailed solve steps)

---

## Contact / Author

Challenge author: Kirk

If anything is unclear or a command fails, mention the failing command and include logs β€” that makes debugging quick.