# Internetwache CTF 2016 : Bank
**Category:** Crypto**Points:** 90**Solves:** 79**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.> > > Attachment: [crypto90.zip](./crypto90.zip)> > > Service: 188.166.133.53:10061
## Write-up
On connection, we are provided with an account and a limit of 20 transactions.There is a limit of 5000 that we are allowed to add to our account in one transaction,but we are greedy and want to get 1000000!
A transaction is initiated by typing 'create \<a\>' to add \<a\> coins to your account.After doing so, the server provides us with a transaction id and a verification code.To complete the transaction we must then type 'complete \<tid\> \<hash\>'.
Looking at the code, we see that the hash is obtained by encrypting the string"TRANSACTION: [amount]" using a XOR cipher with a stream generated by the Randomizer class.```pythondef encrypt(self, t):	self.__r.set_x(t.get_k())	ct = ""        s = str(t)        l = len(s)        for c in s:        	ct += chr( ord(c) ^ (self.__r.get_next() % 2**7) )	return ct.encode('hex')```
When a new transaction is created, the transaction gets a random secret k. The k is thenused as a seed to initialize the Randomizer stream.
When calling 'complete <tid> <hash>', the server decrypts the verification code usingthe seed associated with the tid, and adds the amount specified to our account.But they don't check if this hash is the same as the hash generated during the 'create ' command.```pythondef decrypt(self, t, ct):        self.__r.set_x(t.get_k())        try:                ct = ct.decode('hex')                pt = ""                for c in ct:                        pt += chr( ord(c) ^ (self.__r.get_next() % 2**7) )                if(not "TRANSACTION" in pt):                        return None                a = int(pt.replace("TRANSACTION:",""))                t.set_a(a)                return t        except:                return None```
So we can modify the verification code to encode a different value in the transaction amount.In order to do that, we need to recover the secret k of the transaction.We did this by a simple brute force (the original k is 32 bytes long, but the Randomizeronly works with values mod 2^32, so we only need to brute force 2^32 values for k).
For this, we create a valid transaction with amount 5000. The server gives a verification codeassociated to this transaction. We then use the following script to bruteforce the seed k:
```pythonimport sys
class Randomizer:	def __init__(self, a, c, m, s):		self.__a = a		self.__c = c		self.__m = m		self.__x = s
	def get_next(self):		self.__x = (self.__a*self.__x + self.__c) % self.__m		return self.__x
	def get_a(self):		return self.__a 	def set_a(self, a):		self.__a = a
	def get_c(self):		return self.__c 	def set_c(self, c):		self.__c = c
	def get_m(self):		return self.__m 	def set_m(self, m):		self.__m = m
	def get_x(self):		return self.__x 	def set_x(self, x):		self.__x = x
def decrypt(ct, r):	ct = ct.decode('hex')	pt = ""
	for c in ct:		pt += chr(ord(c) ^ (r.get_next() % 2**7))
	return pt
def encrypt(pt, r):	ct = ""
	for c in pt:		ct += chr(ord(c) ^ (r.get_next() % 2**7))
	ct = ct.encode('hex')	return ct
def find_k(code):	r = Randomizer(1664525, 1013904223, 2**32, 0)
	for k in xrange(2**32):		r.set_x(k)
		if decrypt(code, r) == "TRANSACTION: 5000":			return k
	return None
def modify_transaction(code):	k = find_k(code)	r = Randomizer(1664525, 1013904223, 2**32, k)
	return encrypt("TRANSACTION:99999", r)
print modify_transaction(sys.argv[1])```We use this k to generate a new verification code which contains the string"TRANSACTION:99999". The length of the new verification code must be at most34 hex chars, corresponding to 17 bytes, 12 of which are taken by the"TRANSACTION:" prefix. Normally this would leave us with only 4 digits if thespace was also included in the prefix, but notice the space is ignored duringdecryption, allowing us to replace it with another digit for a larger amount!.
```pythondef modify_transaction(code):       k = find_k(code)       r = Randomizer(1664525, 1013904223, 2**32, k)
       return encrypt("TRANSACTION:99999", r)```
We can then send the obtained code to add 99999 coins per transaction!It takes 11 transactions to reach 1000000, and then we get the flag:> IW{SHUT_UP_AND_T4K3_MY_M000NEYY}
## Other write-ups and resources
* <https://www.xil.se/post/internetwache-2016-crypto90-kbeckmann/>* <https://cryptsec.wordpress.com/2016/02/22/internetwache-ctf-write-up-2016-bank-crypto-90/># CTF-Writeups