# Challenge example

## Source code example

```python
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import json
import os

FLAG = ?
KEY = ?

def admin():
    print("welcome admin")
    print(f"Flag = {FLAG}")


def guest():
    print("welcome guest")


def auth():
    user = dict()
    username = input("username : ")
    password = input("password : ")
    user["is_admin"] = int(username == "admin" and password == FLAG)
    
    plaintext = json.dumps(user).encode()
    padded = pad(plaintext, 16)
    iv = os.urandom(16)
    cipher = AES.new(KEY, AES.MODE_CBC, iv)
    try:
        encrypted = iv + cipher.encrypt(padded)
    except ValueError as e:
        return {"error": str(e)}

    print(f"Here is your token : {encrypted.hex()}")

    return user


def authToken():
    token = input("Token : ")
    token = bytes.fromhex(token)
    iv = token[:16]
    token = token[16:]

    cipher = AES.new(KEY, AES.MODE_CBC, iv)
    try:
        plaintext = cipher.decrypt(token)
        unpadded = unpad(plaintext, 16)
        user = json.loads(unpadded)
    except ValueError as e:
        return {"error": str(e)}

    return user


print("Welcome !")
print("Please login first.")

choice = input("How would you login ?\n1) Token\n2) Credentials\n\nChoice :")

if choice == "1":
    user = authToken()
elif choice == "2":
    user = auth()
else:
    print("error... goodbye")
    exit(0)

if "error" in user:
    print(f"ERROR : {user['error']}")
    exit(0)

elif user["is_admin"] == 1:
    admin()
else:
    guest()
```

The challenge objective is to authenticate as admin using an arbitrary token forged using bit flipping attack.

## Exploitation

First, a legit token is needed.

```bash
$ python3 chall.py
Welcome !
Please login first.
How would you login ?
1) Token
2) Credentials

Choice :2
username : a
password : a
Here is your token : 9cdc43fb9d2fed9a0b5ccc837d4a5badf1b4b1731bcca9977bc862f3e2033970
welcome guest
```

The token contains two blocks, the IV and the ciphertext block.

As explain [here](/cryptography/symmetric-cryptography/aes/mode-of-operation/cbc.md), plaintext is xored with the precedent cipherblock ( the IV for the first block ) before encryption. As we can control the ciphertext, we can control the plaintext.

The original plaintext is :

```python
b'{"is_admin": 0}\x01'
```

{% hint style="info" %}
The json data + [padding](/cryptography/general-knowledge/padding/pkcs-7.md)
{% endhint %}

The targeted data is :

```python
b'{"is_admin": 1}\x01'
```

The IV can be replace with the value `9cdc43fb9d2fed9a0b5ccc837d4b5bad` obtaned using the following operation :

```python
xor(iv, b'{"is_admin": 0}\x01', b'{"is_admin": 1}\x01')
```

And then using the new token, the admin access is granted :

```
$ python3 chall.py
Welcome !
Please login first.
How would you login ?
1) Token
2) Credentials

Choice :1
Token : 9cdc43fb9d2fed9a0b5ccc837d4b5badf1b4b1731bcca9977bc862f3e2033970
welcome admin
Flag = FLAG{CBCBitFlipping}
```

## Exploitation Script

```python
from pwn import *
import string

context.log_level = 'error'

def getToken(username, password):

    p = remote("127.0.0.1", 1337)
    p.recvuntil(b":")
    p.sendline(b"2")
    p.recvuntil(b": ")
    p.sendline(username.encode())
    p.recvuntil(b": ")
    p.sendline(password.encode())
    p.recvuntil(b": ")
    token = p.recvline()[:-1].decode()

    p.close()
    return token


def authToken(token):
    p = remote("127.0.0.1", 1337)
    p.recvuntil(b":")
    p.sendline(b"1")
    p.recvuntil(b": ")
    p.sendline(token.encode())

    print(p.clean().decode())

    p.close()

padding = 0
token = bytes.fromhex(getToken("",""))

iv = token[:16]
blocks = token[16:]

original = b'{"is_admin": 0}\x01'
target = b'{"is_admin": 1}\x01'

iv = xor(iv, original, target)

token = (iv + blocks).hex()

authToken(token)
```

## Exercice

If you want to try this exploit by yourself, you can pull [this docker image](https://hub.docker.com/r/thectfrecipes/crypto/) :

```
docker pull thectfrecipes/crypto:CBCBitFlipping
```

Deploy the image using the followed command :

```
docker run --name thectfrecipes_crypto_CBCBitFlipping -it --rm -d -p 1337:1337 thectfrecipes/crypto:CBCBitFlipping
```

The service is available on port 1337

```
nc 127.0.0.1 1337
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.ctfrecipes.com/cryptography/symmetric-cryptography/aes/mode-of-operation/cbc/bit-flipping/challenge-example.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
