This is the final test of Wanna.W1n club, somewhere around June 2023

The only Crypto challenge that I solved is AES - CBC related

Flipping login (250pts)

Description: Login System using authenticated token. Only admin can read the secret!

This is the server.py code:

import json
import os
import signal
from base64 import b64decode, b64encode

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from secret import flag

key = os.urandom(32)

def menu_choice() -> str:
    print(
        """Valid choices:
    1. Login
    2. Register
    3. Quit"""
    )
    return input(">> ").strip()

def handler(_signum, _frame):
    print("Time out!")
    exit(0)

def encrypt(msg):
    iv = os.urandom(16)
    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    return iv+cipher.encrypt(pad(msg, 16))

def decrypt(iv, msg):
    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    return unpad(cipher.decrypt(msg), 16)

def login():
    enc_token = b64decode(input("Login token: ").strip())
    print(enc_token)
    token = decrypt(enc_token[:16], enc_token[16:])
    token = json.loads(token)
    print(token)
    return token['name'], token['admin']

def register():
    name = input("Nickname: ").strip()
    token = {
        "admin": False,
        "name": name
    }
    token = json.dumps(token).encode()
    print(token)
    enc_token = b64encode(encrypt(token)).decode()
    print("Here is your login token: " + enc_token)

def main():
    name = 'N.A'
    is_admin = False
    print("Welcome to my under-development program. Who are you?")
    while True:
        choice = menu_choice()
        match choice:
            case '1':
                name, is_admin = login()
                break
            case '2':
                register()
                print('')
            case '3':
                print("Bye bye!")
                break
            case _:
                print("??????????????")
                raise RuntimeError("I found a hacker")
    if is_admin:
        print(f"Hello {name}! Here is your secret: " + flag)
    else:
        print(f"Hello {name}! Sorry, only admin can read my secret!")

try:
    main()
except Exception as E:
    print(str(E))

This python code mimics a login system using authenticated token, which is encrypted and decrypted with AES mode CBC, which is the second worst mode just after ECB.

As we can see from the code, it allows us register to generate a token and login using that token. The only catch is that the generated tokens will always have admin = false . If we just register by pressing 2, this will never be solved.

Then we just have to do something, somehow to turn admin=True . This is the part explain why CBC mode is no longer be used.

Untitled

Looking at the encrypt(msg) and decrypt(msg) we can see that IV is sent with the ciphertext, which is important for us.

Since this is CBC mode and we have IV, then we can perform Bit Flipping Attack.

Remember the is_admin part is at the start of the token? So the ciphertext of that part is also at the beginning of the ciphertext

Let’s divide the plaintext and ciphertext into blocks of 16 byte:

$$ P1,P2,P3,...,Pn $$

$$ C1,C2,C3,...Cn $$

The picture has clearly shown that at the start of decryption, we have

$$ IV ⊕ dec(C1) = P1\\or\\P1 = IV ⊕ dec(C1) $$

where P1 is the part that store is_admin = False .

To turn it into P1’:is_admin = True , we simply do this: