Source code: https://drive.google.com/open?id=1uLeYsqnLNVNMurQ11q2ustvW2o_V7IPl

Server: http://ec2-13-229-142-46.ap-southeast-1.compute.amazonaws.com:9999

The website simply asks for our name, then it welcomes us and asks whether we are administrator or not. It decides if we are administrator or not using the cookie created which is named as token.

Let’s analyze the given source code of the application to understand it further.

As we guessed, it uses our name to generate a token using the gen_token function. After removing any occurence of “:” in our name, it appends “:user” to our name and keeps it as data. In order to create MAC for the cookie, it uses HMAC to calculate the hash of secret+data as hexadecimal string. It also uses AES in default mode, which is ECB and not safe, to encrypt data+secret after padding it. Then, it base64 encodes the encrypted bytes. Finally, it appends the MAC string to the base64 encoded string and sets it as cookie.

Since it uses ECB mode, we know that each block is encrypted independently and the block size is 16. The padding function uses PKCS7 padding which simply fills missing N bytes with chr(N). However, if we look at the implementation carefully, we see that if the data length is multiply of 16, it appends a new block which is full of \x10 bytes. Another thing we should notice is that it just reads our name by reading the leftside of the rightmost “:” in the decrypted data. It doesn’t even care about the rightside of “:” which can be “user” or “admin”. Instead, it first appends “:user” to our name and try to validate the MAC. If it fails, then it tries again with appending “:admin” this time. Other than these issues, it also reads the secret from the cookie which means it trusts the user instead of using its own secret.

Let’s move on to what we can achieve here. First, we’d like to use our own secret, but first we need its encrypted bytes using the server’s key. Thanks to ECB mode, we can simply use a name whose length is 11 to make the data size 16 bytes (it appends “:user” which is also 5 bytes). Then, we can decode the cookie and read its first 16 bytes which is the encrypted version of our name + “:user”. Now, we have a plain 16 bytes string whose encrypted 16 bytes are known. We can use this string as secret in our new cookie. Now, all we have to do is calculate a new mac such that it will be valid when the server checks it using our name + “:admin”. Since the server uses the secret from our cookie, we can simply calculate the valid mac using our own secret. After the validation, we will be logged in as administrator.

Here is the python script I created to do the job:

Let’s run the script and get the flag.

Here is our flag matesctf{ECB_M0d3_1s_Ins3cur3}.