Lo-Hi Card Game

For the challenge, we need to gain enough money (self.dollars >= 130), we should obtain the flag. Observing the PRNG, we can see that the PRNG is a Linear Congruential Generator, with properly randomized parameters. Let’s first discuss how to break the LCG. Denote the multiplier mul as $M$, increment inc as $I$, modulo as $N$. We can easily retrieve $M, I$ after obtaining three numbers from the LCG, denoted by $A, B, C$....

January 20, 2023 · 6 min · qvinhprolol

Gotta Go Fast

The key is generated using current_time = int(time.time()), hence if we send two request quickly, the value of current_time is the same, leading to the same key. We can reuse this key for decryption of the flag. Another idea is to generate the space of all possible keys that can be generated on the server. However, it seems like there is some time sync issue (the time on my machine is different from the time on the server), hence we will need a bigger range of time, specifically range(current_time - 100, current_time + 101), where current_time is the time measured using int(time....

January 18, 2023 · 2 min · qvinhprolol

No Leaks

We will exploit the fact that the key is randomly generated, and the ciphertext, after the assertion, will not contain the same bytes as the flag. We can issue a lot of requests to the server to slowly eliminate the space of possible characters for the unknown portion of the flag (the ???? portion). The guess space for each unknown position is the characters in the range of 33 to 127, the printable characters....

January 18, 2023 · 2 min · qvinhprolol

RSA or HMAC

This covers the two parts of the challenge. The challenge is related to the CVE-2017-11424 key confusion vulnerability in pyJWT. This is somewhat hinted by the challenge’s description of a “patch” to enable the exploit. Looking at the commit, we see that one of the newly added invalid_strings is '-----BEGIN RSA PUBLIC KEY-----'. This implies that we can leverage the public key for some forging. Combined with this line from the source code:...

January 17, 2023 · 5 min · qvinhprolol

Mixed Up

I had the correct idea, but unfortunately could not come up with the correct implementation to this problem. We can notice that shuffle is a function that uses the value of each byte in mixed_and as an index to select which byte in mixed_xor will be outputted. Hence, with the same value for every byte in mixed_and, the shuffle output will only be a repeat of some byte len(FLAG) times....

January 15, 2023 · 3 min · qvinhprolol

MDFlag

This is a challenge about length extension attack on hashes like MD5 and SHA1 that uses the Merkle-Damgard construction. More on that can be found in this link, and a good Youtube video about this topic, if you can understand Vietnamese, is this series by CyberJutsu. The following is written under the assumption that you have some experience with the attack. In MD5 hash extension attack, it is often the case that we are allowed to extend the secret with some arbitrary data that we decide....

January 13, 2023 · 9 min · qvinhprolol

MD0

The code is vulnerable to hash length extension attack. The hash for a message with a new block appended can be computed from the hash of the old message, and xor with the result of encrypting the old hash with the key as the new block. Denote $H$ as the old hash, $H’$ as the new hash, the newly appended block as $B$, and encryption as $E$, we have the relation:...

January 11, 2023 · 2 min · qvinhprolol

No Difference

There are two possible solutions to this problem. One involves the method of differential cryptanalysis (normally done on the substitution box SBOX like these), and another brute-force, or more specifically birthday attack solution. I attempt this using the birthday attack solution. The idea is that the space of state is too small. Indeed, the shuffling of the first stage of the hash: 1 2 3 4 5 6 7 8 9 state = [16, 32, 48, 80, 80, 96, 112, 128] for i in range(0, len(data), 4): block = data[i:i+4] state[4] ^= block[0] state[5] ^= block[1] state[6] ^= block[2] state[7] ^= block[3] state = permute(state) state = substitute(state) Only state[4:] are modified from the block’s content....

January 10, 2023 · 5 min · qvinhprolol

Twin Keys

In the two keys that we have to “insert”, one has to start with the prefix of “CryptoHack Secure Safe”, and the other must not have this prefix. The two keys have to pass this check: 1 2 3 4 5 6 7 8 h1 = hashes[0] h2 = hashes[1] for i in range(2, 2**(random.randint(2, 10))): h1 = xor(self.magic1, xor(h2, xor(xor(h2, xor(h1, h2)), h2))) h2 = xor(xor(xor(h1, xor(xor(h2, h1), h1)), h1), self....

January 10, 2023 · 4 min · qvinhprolol

PriMeD5

Thanks to JosePisco for the very useful hint of “a property md5 has on collisions”. Completely shifted my approach. The server is signing the hash of the prime sent using RSA, and there is no information to figure out the private keys so we have to forge two numbers $n_1$ and $n_2$ such that $MD5(n_1) = MD5(n_2)$. Initially my approach is to use fastcoll to generate MD5 collisions with a given prefix, but this approach is just too unreliable, as the probability of finding a prime with some reasonably chosen prefix is too low - fastcoll always generate 1024-bit messages anyways....

January 9, 2023 · 4 min · qvinhprolol