# It's as easy as access=0000
We can connect to a remote server and are given this Python script:
```pythonfrom Crypto.Util.Padding import pad, unpadfrom Crypto.Cipher import AESfrom Crypto.Random import get_random_bytesfrom datetime import datetime, timedelta
challenge_description("You can generate an access token for my network service, but you shouldn't be able to read the flag... I think.")challenge_name = "It's as easy as access=0000"FLAG = "ractf{XXX}"KEY = get_random_bytes(16)
def get_flag(token, iv):    token = bytes.fromhex(token)    iv = bytes.fromhex(iv)    try:        cipher = AES.new(KEY, AES.MODE_CBC, iv)        decrypted = cipher.decrypt(token)        unpadded = unpad(decrypted, 16)    except ValueError as e:        return {"error": str(e)}    if b"access=0000" in unpadded:        return {"flag": FLAG}    else:        return {"error": "not authorized to read flag"}
def generate_token():    expires_at = (datetime.today() + timedelta(days=1)).strftime("%s")    token = f"access=9999;expiry={expires_at}".encode()    iv = get_random_bytes(16)    padded = pad(token, 16)    cipher = AES.new(KEY, AES.MODE_CBC, iv)    encrypted = cipher.encrypt(padded)    ciphertext = iv.hex() + encrypted.hex()    return {"token": ciphertext}
def start_challenge():  menu = "Would you like to:\n[1] Create a guest token\n[2] Read the flag"  while True:    print(menu)    choice = str(input("Your choice: "))    while choice != "1" and choice != "2":        choice = str(input("Please enter a valid choice. Try again: "))    if choice == "1":      print(generate_token())    elif choice == "2":      token = input("Please enter your admin token: ")      while not token:        token = input("Tokens can't be empty. Try again: ")      iv = input("Please enter your token's initialization vector: ")      while not iv:        iv = input("Initialization vectors can't be empty. Try again: ")      print(get_flag(token, iv)) start_challenge()```
## Description
We have two different options:- generate a guest token- login as admin using an admin token.
Guest tokens are an AES-CBC mode encryption of `access=9999;expiry={expires_at}`. A token is considered as an admin token if `access=0000` is present in its decryption. This is a very simple example of malleability of AES-CBC (for the first block).
Let's recall how AES-CBC works: it selects a random IV (Initialization Vector), then uses AES as a block cipher to encrypt data. The plaintext is split into blocks (adding padding to get a multiple of the block length), and the ciphertext is generated as follows:
```c[i] = AES_Enc(c[i-1] XOR m[i])```
with `c[0]` being the IV. The ciphertext is `c` (including the IV). The decryption formula is the following:
```m[i] = AES_Dec(c[i]) XOR c[i-1]```
and the IV is discarded. 
## Solution
If we replace `IV` by `IV XOR D`, the corresponding first block of the plaintext will be decoded as `m[0] XOR D`. We can therefore XOR our IV with the corresponding values to change 9999 into 0000. When the server will decrypt our ciphertext, it will read `access=0000`.
```pythontoken = '606af8cd5c376066077ce589997aa89602a98905e123243aa4591a2291e4909e71cab0734fff1e71c21fee3f5e71a480'token = bytes.fromhex(token)
iv = token[:16]ct = token[16:]
for i in range(7,11):    iv = iv[:i] + bytes([(iv[i] ^ ord('0') ^ ord('9'))]) + iv[i+1:]
print(iv.hex())print(ct.hex())```
Flag: `ractf{cbc_b17_fl1pp1n6_F7W!}`