My team ‘Pwnlyfans’ recently participated in the ASCIS CTF 2024, and we managed to secure 3rd place and 2nd prize. This is a write-up for the crypto challenges we solved.
Xory:
|
|
We can see that it a easy stream cipher with the key length of 5 bytes. The flag format is ‘ASCIS{…}’. So from cipher we can get the key and decrypt the flag.
|
|
LoveLinhALot:
|
|
We encounter a custom hash function, when searching through the code I noticed that in the login fuction only check for the hash return from the secure_hash function is in the pwd_hashes list. So if we can craft a message that under the token for that ‘admin’ still in the list, we can login as admin and get the flag.
The step to solve this challenge is:
- Register a user ‘Malosdaf’ with a random password
- Using breach function to get the token of that admin and ‘Malosdaf’
- Recalculate the hash for ‘Malosdaf’.
- Digging deeper, we can see that the hash function is calulate by the following formula: $$ y_{u_1} = g^{x_1} \times g^{tokenuser1 * block_1} \times g^{tokenuser2 * block_2} \times … \times g^{tokenusern* block_n} \mod p_1$$
So we can reduce the collision problem from multiplicatve group to the additive group by:
Assume the hash of ‘Malosdaf’ is $y_{u_1} = g^{target}$. The collision we must satisfy is: $$ tokenuser[0] * b_1[0] + tokenuser[1] * b_1[1] + … + tokenuser[BLOCKSIZE-1] * b_1[BLOCKSIZE-1] $$ $$ = target \mod phi(q_1) \rightarrow \mod p_1 $$
Which the BLOCKSIZE is 129, The time complexity for naitive bruteforce is $O(2^{129})$ which is infeasible. So we will construct a matrix of size $BLOCKSIZE \times BLOCKSIZE$ and using LLL and CVP to solve the problem.
- Quicknote: This was my first thought when I saw the challenge, but I noticed that the login and resigter function isn’t checking for full 128 null bytes 🐧🐧 🤣. So we just create a random account which password is 128 null bytes and login again using admin with this password and get the flag.
|
|
LoveLinhALot - Revenge:
|
|
This time author have fixed the previous bug, so we can’t use the same trick to get the flag. Back the the previous idea, we will contruct matrix to solve for the collision.
$$ \begin{pmatrix} 1 & 0 & 0 & \ldots & 0 & tokenuser[0] \ 0 & 1 & 0 & \ldots & 0 & tokenuser[1] \ & & & \vdots & & & \ 0 & 1 & 0 & \ldots & 1 & tokenuser[128] \ 0 & 0 & 0 & \ldots & 0 & p_1 \ \end{pmatrix} $$
And the target will vector will be:
$$ (tb[0],tb[1],tb[2], \ldots, tb[128], target) $$
while $t$ is the scaling factor. We can solve this problem using LLL and CVP. The rest of the code is struct construct the password and send it to the server.
- Note: The base is token + g1 so when construct the message we need to calculate for the difference between the target and the hash of the password.
|
|
This solution is quite slow because LLL on matrix size 129x129 but still far better than $O(2^{129})$. We can further improve by using flatter.
|
|
Which usually reduce the time. This is the comparison between the two code:
|
|