The following source code is provided in the task description :
```pythonfrom flask import Flask, render_template, request, url_for, redirect, make_response, flashimport jsonfrom hashlib import md5from base64 import b64decodefrom base64 import b64encodefrom Crypto import Randomfrom Crypto.Cipher import AES
app = Flask(__name__)app.secret_key = 'seed removed'flag_value = 'flag removed'
BLOCK_SIZE = 16  # Bytespad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * \                chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)unpad = lambda s: s[:-ord(s[len(s) - 1:])]
@app.route("/")def main():    return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])def login():    if request.form['user'] == 'admin':        message = "I'm sorry the admin password is super secure. You're not getting in that way."        category = 'danger'        flash(message, category)        return render_template('index.html')    resp = make_response(redirect("/flag"))
    cookie = {}    cookie['password'] = request.form['password']    cookie['username'] = request.form['user']    cookie['admin'] = 0    print(cookie)    cookie_data = json.dumps(cookie, sort_keys=True)    encrypted = AESCipher(app.secret_key).encrypt(cookie_data)    print(encrypted)    resp.set_cookie('cookie', encrypted)    return resp
@app.route('/logout')def logout():    resp = make_response(redirect("/"))    resp.set_cookie('cookie', '', expires=0)    return resp
@app.route('/flag', methods=['GET'])def flag():  try:      encrypted = request.cookies['cookie']  except KeyError:      flash("Error: Please log-in again.")      return redirect(url_for('main'))  data = AESCipher(app.secret_key).decrypt(encrypted)  data = json.loads(data)
  try:     check = data['admin']  except KeyError:     check = 0  if check == 1:      return render_template('flag.html', value=flag_value)  flash("Success: You logged in! Not sure you'll be able to see the flag though.", "success")  return render_template('not-flag.html', cookie=data)
class AESCipher:    """    Usage:        c = AESCipher('password').encrypt('message')        m = AESCipher('password').decrypt(c)    Tested under Python 3 and PyCrypto 2.6.1.    """
    def __init__(self, key):        self.key = md5(key.encode('utf8')).hexdigest()
    def encrypt(self, raw):        raw = pad(raw)        iv = Random.new().read(AES.block_size)        cipher = AES.new(self.key, AES.MODE_CBC, iv)        return b64encode(iv + cipher.encrypt(raw))
    def decrypt(self, enc):        enc = b64decode(enc)        iv = enc[:16]        cipher = AES.new(self.key, AES.MODE_CBC, iv)        return unpad(cipher.decrypt(enc[16:])).decode('utf8')
if __name__ == "__main__":    app.run()```
Now I didn't know much about cryptography before this task, but I learned a lotduring PicoCTF 2018, starting with this task.
So first things first, we can login to the target app with anyusername/password. When we do, the cleartext value of our cookie is displayed :
```javascript{'admin': 0, 'username': 'iodbh', 'password': ''} ```
The goal here is obviously to set the `admin` value to `1`. But the cookie isencrypted, so we have to figure out a way to alter the ciphertext in a way thatwill lead it to decrypt to the desired value.
Looking at the source code and the app, here are the informations we have :
- The Cipher is AES in CBC mode with a blocksize of 16- The IV is know (it is prepended to the ciphertext in the cookie)- We know the plaintext matching the ciphertext (it is returned by the app)
After a frenzied search engine querying session, I found[this cryptography stack exchange question](https://crypto.stackexchange.com/questions/30407/alter-plaintext-in-block-cipher-aes-in-cbc-mode)regarding a very similar problem, and skimming through the relevant wikipediapages gave me a superficial understanding of the issue at stake.
The problem here is that we know the IV (Initialization Vector) and that we canalter it.
### CBC Mode ?
Wikipedia has a [helpful page](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CBC)on the topic.
CBC stands for "Cipher Block Chaining" and refers to a mode of encryption/decryptionthat works as follow (for decryption) :
1. The message is split in "blocks" of equal size (the blocksize, here it's 16 bytes)2. Each block is decrypted3. The decrypted bytes are [XOR](decryption)'d with the previous block's   ciphertext (__the first block is XOR'd with the IV__)
Since we control the IV, we can alter the resulting plaintext in the firstblock. Since we know the plaintext, a simple way to do that is to construct thenew IV by XORing the known plaintext value with the desired plaintext value.That will create a masks that flips the necessary bits on decryption.
### Quick and dirty script
After experimenting a bit, I ended up with the following python3 script. It'snot pretty, but it does the job. I've added comments for this writeup.
```pythonfrom base64 import b64encode, b64decodefrom sys import argv
def xor(a, b):    """    return a bytearray constructed by XORing a and b    """    out = bytearray()    for i,c in enumerate(a):        out.append(c ^ b[i])    return bytes(out)
def construct_cookie(cookie_value):    # current and desired plaintext, obtained by observing the cookie    desired_plaintext = bytearray('{"admin": 0, "pa', 'utf8')    current_plaintext = bytearray('{"admin": 1, "pa', 'utf8')    # base64-decode the cookie value    decoded_cookie = b64decode(cookie_value)    # split the IV and the message    original_iv = decoded_cookie[:16]    # construct the mask for the first block    desired_iv = xor(xor(desired_plaintext, current_plaintext), bytearray(original_iv))    # prepend the new IV to the original ciphertext    altered_ciphertext = desired_iv+decoded_cookie[16:]    # base64-encode the cookie value    cookie = b64encode(altered_ciphertext).decode("utf8")    return cookie
if __name__ == '__main__':    try:        cookie = argv[1]    except IndexError:        print(f'usage: {argv[0]} [COOKIE]')    print(construct_cookie(cookie))```
Now, if we grab the original cookie value, pass it to this script and requestthe `/flag` path with the generated cookie, we get our flag :`picoCTF{fl1p_4ll_th3_bit3_7d7c2296}`