Rating:

When connecting to the server, we get the following information:

```
$ nc challs.xmas.htsp.ro 1004
Provide a hex string X such that sha256(unhexlify(X))[-5:] = 88446

1c0a2cef6da36bff2543
Good, you can continue!
Hello, thanks for answering my call, this time we have to break into Krampus' server and recover a stolen flag.
We have to solve a hash collision problem to get into the server.
Sadly, we're on a hurry and you only have 2 actions you can make until we get detected.
Choose what you want to do:
1. hash a message
2. provide a collision
3. exit

```

We can either get the hash for a provided message or provide a collision. It is interesting to note that we have only two actions before the server closes the connection.
From the provided source code we learn that the hash is computed as follows:

The message is split into blocks of 16 bytes. The last block is padded to 16 bytes by adding zero bytes if shorter.
```
hash = b'\00'*16
message = pad(message)
for block in message:
hash = block ^ aes(hash ^ block)
```
The key for AES is chosen at random when connecting to the server.

Since the `hash` variable is initially chosen as zero, we know that the result of the first AES encryption is the ciphertext of the provided message. If we choose the first block to be all-zero, the result of the first encryption will also be the new value of the `hash` variable.

Our first operation is getting the hash of an all-zero 16 byte block.

```
1
Ok, give me a hex-encoded string to hash.

Give me a message.
00000000000000000000000000000000
Here is your hash: b'6cae7f1c9c2ef4604080f7bae883fa76'.

Choose what you want to do:
1. hash a message
2. provide a collision
3. exit

```

Our second operation is providing the collision. After learning the ciphertext of an all-zero block we can construct a second message that results in the same hash as the all-zero block. The colliding message is of the form `b'\x00'*16 + hash(b'\x00'*16) + b'\x00'*16`.

```
2
Now give me two different hex-encoded strings to check for a collision.

Give me a message.
00000000000000000000000000000000
Give me a message.
000000000000000000000000000000006cae7f1c9c2ef4604080f7bae883fa7600000000000000000000000000000000
```

This works since the first block sets the `hash` variable to the known hash of an all-zero block. The second block has the same value, so computing the xor results in an all-zero block being encrypted. Xoring the resulting ciphertext with the same value sets `hash` to zero. So now the hash algorithm has the same state like at the start. Since we have another all-zero block left for hashing, we get the same hash as the all-zero block.

After providing the collision, the server prints the flag:
```
Damn, that was a really clever approach, you should be proud of yourself.
Here's the flag: X-MAS{C0l1i5ion_4t7ack5_4r3_c0o1!_4ls0_ch3ck_0u7_NSUCRYPTO_fda233}
```