Day 12 - Leveling Up with picoCTF's Medium Crypto Challenges
After warming up with the easy challenges, today I felt ready to raise the difficulty. I dove into the "Medium" category for cryptography on picoCTF. These problems required a bit more thought and combined multiple concepts, which was a great way to test my understanding.
Here’s a breakdown of the challenges I tackled!
1. credstuff
This challenge simulated a real-world scenario: a credential leak from a black market website. I was given two files, usernames.txt and passwords.txt, and my goal was to find the password for the user "cultiris". The description noted that the Nth user in the username file corresponds to the Nth password.
My Solution:
This was a two-step process involving some command-line magic and a familiar cipher.
- Find the Password: First, I needed to find which line the user
cultiriswas on. Thegrepcommand was perfect for this. It told me the user was on line 378.
Then, I used thejosh@DESKTOP-E7VKRGO:~/credstuff/leak/leak$ grep -n cultiris usernames.txt 378:cultirissedcommand to print only the 378th line from thepasswords.txtfile, which gave me the encrypted password.josh@DESKTOP-E7VKRGO:~/credstuff/leak/leak$ sed -n '378p' passwords.txt cvpbPGS{P7e1s_54I35_71Z3} - Decrypt the Password: The password
cvpbPGS{...}had the classic format of a ROT13 cipher. I used my ROT13 script from a previous challenge to decrypt it.
Flag: picoCTF{C7r1F_54V35_71M3}
2. basic-mod1
This challenge was a fun exercise in modular arithmetic and character mapping. I was given a list of numbers and a specific decryption scheme.
The Task:
For each number in the message, I had to calculate the value modulo 37. Then, I needed to map the result to a specific character set: 0-25 for uppercase letters (A-Z), 26-35 for digits (0-9), and 36 for an underscore.
My Solution:
I wrote a Python script to automate this process. It loops through the numbers, applies the mod 37 operation, and uses if/elif/else statements to map the result to the correct character before joining them all into the final flag.
# The decryption function for basic-mod1
def decrypt(ct):
arr=[]
angka_int=[int(a) for a in ct.split()]
for i in angka_int:
fi=i%37
if 0<=fi<=25:
arr.append(chr(fi+65))
elif 26<=fi<=35:
arr.append(str(fi-26))
else:
arr.append('_')
return "picoCTF{" + ''.join(arr) + "}"
Flag: picoCTF{ROUND_N_ROUND_79C18FB3}
3. basic-mod2
This challenge built directly on the previous one, adding another mathematical step: the modular inverse.
The Task:
This time, I had to take each number modulo 41 and then find the modular inverse of that result. The final value was then mapped to a character set (1-26 for A-Z, 27-36 for 0-9, and 37 for an underscore).
My Solution:
My Python script for this was similar, but included a crucial new step. For each number, after applying mod 41, I used Python's powerful pow(number, -1, 41) function to efficiently calculate the modular multiplicative inverse.
# The core logic for basic-mod2
def decrypt(ct):
arr=[]
angka_int=[int(a) for a in ct.split()]
for i in angka_int:
fi = i%41
try:
# Calculate the modular inverse
inv=pow(fi, -1, 41)
if 1<=inv<=26:
arr.append(chr(ord('A')+inv-1))
elif 27<=inv<=36:
arr.append(str(inv-27))
else:
arr.append('_')
except ValueError:
# Handle cases where inverse doesn't exist
arr.append('?')
continue
return "picoCTF{" + ''.join(arr) + "}"
Flag: picoCTF{1NV3R53LY_H4RD_8A05D939}
4. Mind your Ps and Qs
This was an interesting RSA challenge. The security of RSA depends on the difficulty of factoring the modulus N. The challenge's name hinted that something was special about the prime factors p and q.
The Vulnerability:
It turns out that N was a number whose factors were already known and stored in public databases. I used an online database (factordb.com) via a Python library to instantly find p and q.
My Solution:
Once I had p and q, breaking the rest of the RSA encryption was straightforward. My script automated the following steps:
- Factor N: Use the
factordb-pylibrary to fetchpandqfrom factordb.com. - Calculate φ and d: Compute
phi = (p-1)*(q-1)and then the private keyd = pow(e, -1, phi). - Decrypt: Compute the plaintext by calculating
pow(c, d, n)and converting the resulting integer to a readable string.
This challenge was a great lesson in how real-world tools and databases can be used to break implementations that might seem theoretically secure.
Flag: picoCTF{SmAll_N_g00d_45369387}
5. Mini RSA
My final challenge for the day was another RSA problem, this time focusing on a small public exponent (e).
The Vulnerability:
When e is small (like e=3), if the plaintext message M is also small, M**e might be smaller than the modulus N. In this case, an attacker can simply calculate the integer e-th root of the ciphertext to recover M. This challenge was slightly trickier because padding ensured M**e was just barely larger than N. This means M**e = k*N + C for some small integer k. The attack is to try small values of k (0, 1, 2, ...) and check if (k*N + C) is a perfect e-th root.
My Solution:
I wrote a script that iterated through values of k, calculated candidate = k*N + c, and used the gmpy2.iroot() function to check if the result was a perfect root. On iteration k = 3533, it found the plaintext!
# Core logic of the Mini RSA attack
# (Assuming c, n, e are already defined)
import gmpy2
for i in range(10000):
candidate = i * n + c
is_true_root, m = gmpy2.iroot(candidate, e)
if is_true_root:
print(f"Found i = {i}")
# ... code to convert m to string and print flag ...
break
This was a classic example of an attack on a "textbook" RSA implementation with a small e.
Flag: picoCTF{e_is_n0t_en0ugh_t0_br34k_RSA_638ce719}
It was really satisfying to see the crypto concepts I've been reading about come together in practical scripts to break these challenges. What a fantastic day of learning at picoCTF!
#IDNBootCampCyber
Komentar
Posting Komentar