crypto

Challenges

Scr4mbl3d

I like to confuse people. (Or I'm the one confused?)

A custom block cipher tries to “look hard” by mixing SHA-256 and odd arithmetic. Under the hood it’s a Feistel network over ZP\mathbb{Z}_P​ (mod a 256-bit prime). No secret key. Everything (P, F, constants, schedule) is fixed and known. A Feistel network without a key is just a reversible permutation you can run backward and recover the plaintext.

Where is the Flag? The flag is encrypted using a custom block cipher and stored as the ciphertext. The original flag was converted to bytes (1), then to an integer (2), encrypted with a randomized number of rounds (26-53) (3), and output as hex (4).

How do we get it? 🚩

  1. Create decrypt functions that undo each encryption step —

  2. Since rounds are random (26-53), try all possibilities (smoll enough,hehe)

  3. Look for results that decode to readable text starting with "snakectf{"

circle-info

Script

  • snakeCTF{Ev3ry7hing_1s_34s13r_w1th_F3is7el_bb5dcc5e0a39ff0b}

Unf33dMe

Easy structure but the choice of parameters make it as strong as a Babylonian defense.

TL;DR: The “Unf33dMe” hash is a simple per-word permutation where each 2-byte chunk of the flag is independently run through three cube-and-add steps with public constants, then the only cross-mixing is a final pairwise swap-and-add that couples words two at a time.

Because there’s no secret key and each word is only 16 bits, we can rebuild the public round constants (from SHAKE256("SNAKECTF")), and for each swapped pair directly brute-force one word, compute the other from the equation, and check it—repeat for the 12 pairs, join candidates, PKCS#7-unpad and keep the printable ASCII that looks like a flag.

Doing this yields the flag: snakeCTF{p0lys_4r3_m4g1c_:)_16f95932140b4fbe}.

Where is the flag? The archive’s out.txt has two Python lists:

  1. digest — 24 field elements (mod p=65537)

  2. IV — 24 field elements used as the per-word “key”.

Those two lists are all you need to reconstruct (the flag) thanks to how the hash is built.

circle-info

Script

Free Start

It looks like it is impossible!

ncat --ssl freestart.challs.snakectf.org 1337

tldr;

circle-check

Our job is to

Repeatedly craft valid collisions that match the server’s hash output.

How? The server reveals, for each round:

  • the random message message = [m0, m1, m2, m3, m4]

  • the random initial capacity initial_capacity = c0

  • the resulting hash h = S.hash(message, c0)

We must reply with (a different message, at least 2 blocks) + (our initial capacity) that hashes to the same h, and that doesn’t contain any 2-element subsequence from the server’s message. Do that 100 times

The vulnerability?

Result is: Given any target hash h, we can choose the final y, invert the permutation once to obtain the input that must go into the last permutation call, and then use a 2-block message to hit that input exactly while obeying the server’s constraints.

  • snakeCTF{resultant_computation_can_help_a_lot_if_some_roots_are_easy_to_find_ac91ebf18ccc01d5}

Triple-Flavor

Why settle for just one mode of operation when you can have 3?

ncat --ssl triple-flavor.challs.snakectf.org 1337

tbd-will write later (this is cool sh)

Last updated