Description#
The objective of this challenge is to find a way to get logged in as the user “administrator”.
This is the demo application for our new session management system based on military cryptography (namely CBC-MAC). You can log in as any user (except ‘administrator’) with the password ‘Password1’. We blocked access to ‘administrator’ account for security reasons.
Resolution#
Let’s log in with the username “test” and see how the authentication system keeps track of the currently logged in user.
There are 2 cookies encoded in base64. One just needs to decode them to see their real value and get a better understanding of what’s going on.
"dGVzdC0trPGLxEtxTi8=".decode("base64")
# 'test--\xac\xf1\x8b\xc4KqN/'
"bOHCrEKzfso=".decode("base64")
# 'l\xe1\xc2\xacB\xb3~\xca'
Excellent ! So the “auth” cookie is just the username followed by “–” and 8 bytes which corresponds to the output of the CBC-MAC algorithm. The “iv” cookie is, like its name says, the initialization vector used by the CBC-MAC algorithm to produce the above result.
A little bit of crypto#
CBC-MAC (Cipher Block Chaining Message Authentication Code) uses blocks of fixed length to encrypt a message and output only the last block of the resulting ciphertext. This is the one present at the end of the “auth” cookie and its size is 8 bytes.
Unlike other block ciphers, CBC-MAC uses a fixed IV, usually zero. The IV and the plaintext are then xored together. Since the IV and the plaintext can be modified, one can forge a first block that will output the same authentication code ! More information about why it’s insecure to have a variable IV is described in this blog post.
Ok, it’s possible to change the first 8 bytes of the plaintext without repercussions on the authentication code but “administrator” is 13 bytes long. Logging in with a username which is 13 bytes long and ends with “rator” will solve the problem. The less change needed, the quicker, that’s why using “Administrator” is a good choice, only the first letter will have to be changed.
iv = "Gzb5ZaA8QUo=".decode("base64")
iv
# '\x1b6\xf9e\xa0<AJ'
auth = "QWRtaW5pc3RyYXRvci0tzyp2t0HMVVI=".decode("base64")
auth
# 'Administrator--\xcf*v\xb7A\xccUR'
Before changing the first letter, the current value of the first byte of the first block must be calculated.
ord('A')^0x1b
# 90
The first letter of the username needs to be replaced with ‘a’, therefore the first byte of the IV needs to be changed to produce the same result as before:
ord('a')^90
# 59
chr(59)
# ';'
Now, the new values just have to be encoded in base64 and changed in the browser.
'administrator--\xcf*v\xb7A\xccUR'.encode("base64")
# 'YWRtaW5pc3RyYXRvci0tzyp2t0HMVVI=\n'
';6\xf9e\xa0<AJ'.encode('base64')
# 'Ozb5ZaA8QUo=\n'
Validation can be done with the flag: hackim18{'cbc_it_is_easy_as_one_two_three'}