TokenVault1.md 3.6 KB
Newer Older
Cool Fire's avatar
Cool Fire committed
1
2
# TokenVault 1

Cool Fire (HN)'s avatar
Cool Fire (HN) committed
3
For TokenVault 1 we are given the [source](https://git.insomnia247.nl/coolfire/VincCTF-2018/blob/master/tokenvault1.py) of the application, but of course the flag and encryption key have been stripped out in our copy. (You will need to install the pycrypto package to run it.)
Cool Fire's avatar
Cool Fire committed
4

Cool Fire (HN)'s avatar
Cool Fire (HN) committed
5
6
7
8
9
When digging into the source we quickly find we need to pass the `verify_token` function with the input we pass to the application. The `verify_token` function is pretty simple, it just decrypts the string we give it and returns `True` if our decrypted text is **flag: 1**.

We can also find that the example token given to us when we connect to the application is pretty close to that; `conn.send('Token example: ' + generate_token(0) + '\n')` generates an encrypted token with the correct key for us, except that the plaintext is **flag: 0** instead of **flag: 1**. So close.

Let's investigate the token encryption routine and see if we can find some clues.
Cool Fire's avatar
Cool Fire committed
10
```python
Cool Fire (HN)'s avatar
Cool Fire (HN) committed
11
12
13
14
def generate_token(authorized):
    iv = Random.new().read(16)
    return b64encode(iv + AES.new(KEY, AES.MODE_CBC, iv).encrypt(pad('flag: ' + str(authorized))))
```
Cool Fire's avatar
Cool Fire committed
15
The IV looks like it's probably plenty random, but if we need it, it's prepended to our ciphertext anyway so no need to try and recover it. Next we see it uses **AES** in **CBC** mode. Searching for known attacks against this we quickly find out about the [AES CBC byte flipping attack](https://resources.infosecinstitute.com/cbc-byte-flipping-attack-101-approach/). This should give use the ability to change a character in our ciphertext to predictably change what the decrypted plaintext will be. Great! That sounds exactly like what we need.
Cool Fire (HN)'s avatar
Cool Fire (HN) committed
16
17
18
19
20

The really short and over-simplified thing we need to know about this attack is that we can XOR a known byte in the original ciphertext with the byte we want to change it to, and then XOR that with the byte at the same offset in the IV. For us this is the easiest possible case where we have just an IV block followed by a single block of encrypted data.

Now let's grab an example ciphertext from the application. I got `xJ0Lym6r18nO2s9EWON1PBGvuMfx8gsNlMH+mEDkzOc=`. We'll use that as our example from now on. Now we'll write a script to do a little decoding and encoding for us, and of course XOR all the right bytes.

Cool Fire's avatar
Cool Fire committed
21
```python
Cool Fire (HN)'s avatar
Cool Fire (HN) committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env python2
# -*- coding:utf-8 -*-

from base64 import b64encode, b64decode

inpt    = 'xJ0Lym6r18nO2s9EWON1PBGvuMfx8gsNlMH+mEDkzOc=' # This is our example ciphertext containing the IV and the encrypted data for 'flag: 0'
decoded = b64decode(inpt)                                # First we base64-decode
data    = list(decoded)                                  # Then make it a list so it's easier to work with

diff    = ord('0') ^ ord('1')                            # First XOR our '0' and '1' bytes, since we want to change the 0 to a 1 here.
newval  = ord(data[6]) ^ diff                            # Then xor that with the byte in 7th position, where the '0' char is in the encrypted block.
data[6] = chr(newval)                                    # And overwrite that byte in our list/array.

print inpt                                               # Print original for easy comparing
print b64encode(''.join(data))                           # Make our list/array a string again, base64-encode it, and print
```

If all goes well, you should see something like;
```
$ python2 flip.py
xJ0Lym6r18nO2s9EWON1PBGvuMfx8gsNlMH+mEDkzOc=
xJ0Lym6r1snO2s9EWON1PBGvuMfx8gsNlMH+mEDkzOc=
```

Cool Fire (HN)'s avatar
Cool Fire (HN) committed
46
If you stare at this output long enough you'll see that indeed an `8` was changed to an `s`. Now feed your modified ciphertext to the application and bask in the glory of your flag!