Post

Block Construction

Block construction - Crypto - 150 Points - 46 Solves

Challenge Description + files

“Sir, sir! This is a construction site.” You look up at what you thought was a building being constructed, but you realize it is a construction bot. “Sir please move aside. I had to have these blocks in order since last week, but some newbie construction bot shuffled them.” “I can move aside, “ you tell the bot, “but I might be able to help you out.”

Can you help the bot get the blocks in order?

Introduction

This challenge uses AES in ECB mode to encrypt every byte of the flag. We solve it by exploiting the weakness of the ECB mode, repeating plaintext generates repeating ciphertext.

Recon

In the block_construction.zip there are 2 files, block_construction.py and ciphertext. The file block_construction.py contains a script that encrypts the flag with AES in ECB mode and writes the encrypted flag in ciphertext.

For the ciphertext to be generated each character from the flag is padded with each character from rand_printable and then encrypted with AES in ECB mode with a random key (32 bytes).

1
2
3
4
with open('ciphertext_test.txt','w') as fout:
    for x in flag:
        for y in rand_printable:
            fout.write(encrypt(x + (y*31)).decode())

The list rand_printable is formed from printable characters that are shuffled with a time based seed.

1
2
3
4
# len(printable) = 100
random.seed(int(time()))
rand_printable = [x for x in printable]
random.shuffle(rand_printable)

Solution

The solution is divided in two main parts:

Finding the index of the flag characters from rand_printable

1
2
3
4
5
6
7
8
9
l = []
with open("ciphertext", 'r') as fin:
    text = fin.read()
    text = binascii.unhexlify(text)
    for i in range(0, len(text), 3200):
        for j in range(0, 3200, 32):
            if text[(i + j):(i + j + 16)] == text[(i + j + 16):(i + j + 32)]:
                l.append(j // 32)
                break

AES in ECB mode encrypts a 32 bytes text with a 32 bytes key by splitting the text in two blocks of 16 bytes and then encrypts them with the same key. This means that if we have a text such that text[0:16] == text[16:32] then ciphertext[0:16] == ciphertext[16:32]. We can use this to our advantage. We can find the index of the flag characters in rand_printable by checking where the flag characters are equal with the character from the padding.

Recreating the rand_printable list and getting the flag

To get the same shuffle we need to find the exact time the program generated the ciphertext. We can see this by looking when it was last modified.

image

Then we can use a site like https://www.epochconverter.com to get the exact number we need. Pasted image 20240227211629 Finally we use the indexes to print the flag.

1
2
for i in l:
    print(rand_printable[c], end='')

Flag

brck{EZP3n9u1nZ}