Bank
[Internetwache CTF, 2016]
- Category: Crypto
- Points: 90
- Solves: 104
- Description:
Description: Everyone knows that banks are insecure. This one super secure and only allows only 20 transactions per session. I always wanted a million on my account.
Write-up
Given was a python script which contained an implementation of a custom bank. It provided us with two commands, 'create X' and 'complete N X'. The 'create' commands opens a new transaction for a given amount and presents you with a verification code. The 'complete' command takes a transaction number and a verification code and finalizes the transaction.
The goal is to get more than one million into your account, however we have two limitations: We cannot create more than 20 transactions and we cannot create a transaction with an amount larger than 5000. This limitation obviously means that we can only put 100000 into our account and have to look for a way to cheat the implementation.
Our first instinct was to look at the verification code, and rightly so: Upon inspecting the provided implementation, one can see that the verification code is the string "Transaction: <AMOUNT>" encoded with XOR of randomly generated values. When the 'complete' command is executed, the verification code is decrypted and the decoded amount is added to the account.
Even though we do not know the randomly generated values, since XOR is used, we can XOR our own changes into the verification code and they will persist even after the decryption.
This led to our plan: create a transaction with a given amount (1000) and use the space character to increase the amount. A space is ASCII character 0x20 so if we XOR it with 0x18, we get 0x38 which is ASCII character '8'. (Any other digit greater than or equal to 5 would have worked too). This increases the amount to 81000, which fulfills the goal of getting one million in 13 transactions and gives us the flag.
The full python code can be found below:
#/usr/bin/python2
from pwn import *
p = remote("188.166.133.53", 10061)
p.recvuntil("Command:")
balance = 0
for i in range(20):
p.sendline("create 1000")
line = p.recvline()
code = line[line.find("code: ")+6:-1]
old = code[24:26]
patch = chr(ord(old.decode("hex")) ^ 0x18).encode("hex")
newcode = code[:24] + patch + code[26:]
p.recvuntil("Command:")
p.sendline("complete {} {}".format(i, newcode))
balance += 81000
if balance >= 10**6:
break
p.recvuntil("Command:")
p.interactive()