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.
Then we can use a site like https://www.epochconverter.com to get the exact number we need. Finally we use the indexes to print the flag.
1
2
for i in l:
print(rand_printable[c], end='')
Flag
brck{EZP3n9u1nZ}