Post

TCP1P-CTF 2023 - One Pad Time

Description

Category: Cryptography

Author: Wrth

At the wrong place at the wrong time

Attachments:

Solution

1. Overview

The flag has been encrypted with AES-CBC and we have the ciphertext xored with the key and the IV.

1
2
3
4
5
pt = open("flag.txt", "rb").read()
ct = pad(cipher.encrypt(pt), 16)
ct = xor(ct, key)
print(f"{iv = }")
print(f"{ct = }")

The goal is to decrypt the ciphertext but we are missing the key.

2. Padding

We can see that the ciphertext is the encryption of the flag with padding:

1
ct = pad(cipher.encrypt(pt), 16)

However AES is a block cipher with a block size of 128 bits (16 bytes).

It means that it can only encrypt data that length is a multiple of 16 bytes.

If the length is not a multiple of 16 bytes, we use padding to fill the missing bytes.

In this challenge, we didn’t have to pad the plaintext which means that the length of the plaintext is a multiple of 16 bytes.

So the pad function in our case is only adding 16 times \x10 (PKCS padding method - IBM) to the ciphertext.

Knowing that we can recover the key and decrypt the ciphertext:

1
2
3
4
5
6
7
8
9
10
11
12
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

iv = b'\xf5\x8e\x85ye\xc8j(%\xc4K\xc1g#\x86\x1a'
ct = b'h\x08\xafmDV\xaa\xcd\xea\xe9C\xdd7/\x1fF\xe2?\xcb\xb0\x1d F\xcc\xe5\xa6\x9dTJ\\\xd1\x90\xac\xe0\x1c\x891}\x83*\x86\xee\xc4~\xa0\x18\xa8\x06\xea"{|\x0b\x92[\x9a[\x91\xc8\x19\xb7FK\x01\xb5\xf98\x80\x9bR)2\x84`\xb3E\t\xd5\xe5\xf0[\x83\xc6\x19\x82\r\x7f\xfaGF\xdb\xcb\xab\xd5~\x95\t\xdd\xb5E>F\xdd\xa9\xa6\x82\x86\xee"\x99\xd9\xcc\xaf\xce\xf0\'\xb3\xf4~\xcf\xdb\xc8\xbd3\x01\xd0,}]\xd5V\xd3?\xb0\xe7\xb4[4\x8a\xa2[\xa1TV\xd16\x1f\xbd"\xc8\xa2\\K\x16I%\xdaL\xc6\xfb\xb7f.\x98\xc3\xf4J\x1b\xe9TT\x83-\x98BO\xb4\x00~\xb5w\xcf7m\xa1\xea\xa9\xf6\xa6\xee\x00Y\xdfE\x9c7\xe3\xa3\xa2\x1f=.\x85\x08l\xacN\xfb2\x89\x8bB\x7f\x94\x91p\x10ep\x9b\x06oz\x87&U]J\x019\x12W\xce<\xc8\xa8\xb4v\xaf,\xb1n\x8b\xf5\xfe\xf8\r\xa7:r\xe8\xe0fvKN\\\xea\xe0\xa1\xe3\x99\xcc\xfd\x1a\x99Q\x90\xdf}\xae\xad'

key = xor(ct[-16:], b"\x10"*16)

cipher = AES.new(key, AES.MODE_CBC, iv)
print(cipher.decrypt(xor(ct, key)))

# b'TCP1P{why_did_the_chicken_cross_the_road?To_ponder_the_meaning_of_life_on_the_other_side_only_to_realize_that_the_road_itself_was_an_arbitrary_construct_with_no_inherent_purpose_and_that_true_enlightenment_could_only_be_found_within_its_own_existence_1234}\xbau\xb9\x0cV\xc4R\x95O\r\x85\x18\tH#F'

and get the flag: TCP1P{why_did_the_chicken_cross_the_road?To_ponder_the_meaning_of_life_on_the_other_side_only_to_realize_that_the_road_itself_was_an_arbitrary_construct_with_no_inherent_purpose_and_that_true_enlightenment_could_only_be_found_within_its_own_existence_1234}

This post is licensed under CC BY 4.0 by the author.