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_name
which seems to bebase64
encoded. - Let’s
base64
decode it usingCyberchef
:
- As you can see, the result also seems to be
base64
encoded : - Let’s try decoding it one more time :
- This time, we have some gibberish, unreadable piece of text.
This indicates that the
cookie
wasencrypted
, as per the challenge description, andbase64
encoded 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 Encryption
makes 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 encryption
was 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
admin
user. - Another thing worth mentioning is that, if you take a closer look at the
Challenge Description , you will notice that the lettersC
,B
andC
are strangely capitalized, which is an indication thatCBC
orCipher Block Chaining
is 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
,192
or256
bits. - 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 algorithm
that takes a plaintext block of length n and a key, and use that to generate a ciphertext block of the same length n. AES
is the most popularblock cipher
, as i mentioned earlier it operates on128-bit blocks
with keys of128
,192
or156
bits.- The problem here is that, if you have a file of
2GB
and you are working with a128-bit
block cipher (AES for example), the algorithm is certainly not going to encrypt this large file in a single call. - This is where
modes of operation
comes 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
ECB
mode is that encrypting the same block of plaintext always yields the same block of ciphertext. - This can allow the attacker to detect whether two
ECB
encrypted messages are identical, or share a common prefix or substrings. - Additionally,
ECB mode
is notsemantically secure
, which means that observingECB
encrypted 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
ECB
mode and asemantically secure
cipher mode likeCBC
:
CBC
- In
CBC
mode, each block of plaintext isXORed with the previous ciphertext block before being encrypted. - In other words,
CBC
mode links the output of one block to the input of the next block, which essentiallyrandomise
the 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 bytes
that has the same length of the blocks.
Decryption
works 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
XOR
the result with the previous ciphertext block which gives us the second plaintext block - And So On …
Bit-Flipping Attack
- Now that we understand how
CBC
works, we can now talk aboutBit-Flipping
attack. - The main vulnerable part of
CBC
is that, it relies on the previous ciphertext block in order to encrypt/decrypt the next plaintext/ciphertext block, and this is exactly where theBit-Flipping
attack 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 mode
to encrypt theauth_name
cookie, we can assume that there is abit
, within the encrypted cookie, responsible of identifying admin users from normal users. There is most likely a
parameter
likeadmin=0
and 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
flip
every single bit until theflag
is shown. - To do so, let’s write a
Python Script
that will loop over all the bits in thecookie
and flips each one until theflag
is displayed.
Writing the exploit
- First things first, let’s :
- Establish a
session object
using therequests
module; - Send a
GET
request; - Grab the
auth_name
cookie and store it in aCookie
variable; Base64 decode
twice 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
Cookie
andRaw_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
exploit
where theBit-Flipping
process is going to take place.- First, we define a
loop
to iterate overevery single byte
in theRaw_Cookie
; - Then, we define another nested
loop
to iterate overevery single bit
in the current byte of every iteration, given that every byte contains 8 bits(1-Byte = 8-bits)
; - Then, we take
every byte of every iteration
andxor
it withanother byte
where all bits are set tozero
except the bit at the position ‘bit_index’ which going to be set toone
; Base64
encode twice the generated cookie from the 3rd step;- Send a
GET request
with 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-Flipping
process 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.