Pwn2win2020 Androids Encryption

Challenge Info
The challenge is a crypto challenge from the pwn2win event , it’s focused on the symmetric cryptography and especially the aes block cipher.So we are given remote connection nc encryption.pwn2.win 1337 and the python script that is running in the remote server.py .
Writeup Summary
-
gain general information
-
deep look into encrypt your secret
-
Solution
gain general information
By the first look at the server.py script we notice there are 3 main functions first one is def encrypt(txt, key, iv) where you pass the plaintext the key and iv this function will check that the plaintext length is multiple of Block Size which is 128 and then it will encrypt the plaintext with custom implementation of AES , the second one is enc_plaintextthis function that we will interact with it will take our plaintext and decode it as a base64 and pass it to encrypt with key1 and iv1 which are secrets . The last function is enc_flag() it will encrypt the flag with key2 and iv2 which their difinition is :
|
|
by looking at the xor function we noticed that if two parametres a,b are passed then it will calculate a xor b else if one parametre a is passed it will return a[0] xor \x00 *len(a[0]) so it will return the first block xored with 00 and that meen it will return the first block .
deep look into encrypt your secret
After looking in the function i noticed it doing 2 things interesting :
-
first thing is that it is returning to us the iv passed in parametre + the cipher so for example if we passed
iv2to the function than we get as a resultiv2+ cipher1base64.b64encode(iv+ctxt)PS: of course all inputs and outputs are encoded with base64
-
the second interesting thing is that it is overriding the
iv2andkey2that are used in encrypting the flag :1 2iv2 = AES.new(key2, AES.MODE_ECB).decrypt(iv2) key2 = xor(to_blocks(ctxt))so the new
iv2is the decryption of the previousiv2withkey2and the newkey2is the xor of the cipher calculated and as we have discussedxorfunction when we pass one parametre it will return the first block of the passed object sokey2 = cipher[0]so from the resultiv+ctxwe can getiv1andkey2from the cipher and to get the next value ofiv2we need the value ofkey2before change .so the idea of the challenge is to try to guess theiv2andkey2that will be used next time we encrypt the flag .
Solution
after trying in a paper the different combination of commandes that will allow us to get the key and initial vector i finnaly found the solution it is bit tricky so what we will do is :
-
we will send a random payload with 16 bytes to the oracle that will return us
iv1 + cipherand from the cipher we can get the new valuekey2because as we saidkey2 = a[0]the new key is the first block of cipher -
next we will send the encrypt flag command that will return to us
iv2 + flag_cipherand here we can use the result of the first step which is key2 and get the new value ofiv2because it will be changed byiv2 = AES.new(key2, AES.MODE_ECB).decrypt(iv2)and also we update the value ofkey2now we have thekey2andiv2values and we can use it to decipher the flag next time because this value will be used next time -
we will send the encrypt flag command and decrypt the cipher :
1 2 3 4 5 6 7 8aes = AES.new(key2, AES.MODE_ECB) curr = iv2 bs = len(key2) text=b"" for block in blocks: text +=xor(curr, aes.decrypt(block)) curr = xor(text[-bs:], block) print(text)the challenge used a modified version of aes ecb it work like this
cipher1 = aes(text1 xor iv)thencipher2 = aes(text2 xor (text1 xor cipher1))and it do this for each block . so for the decryption part we can do thistext1 = iv xor aes.decrypt(cipher1)and for other blockstextI= (cipherJ xor textJ) xor aes.decrypt(cipherI)whereJ = I-1.
and finnaly we got the flag CTF-BR{kn3W_7h4T_7hEr3_4r3_Pc8C_r3pe471ti0ns?!?} . awesome challenge had so much fun solving it .