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
cultiris
was on. Thegrep
command 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:cultiris
sed
command to print only the 378th line from thepasswords.txt
file, 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-py
library to fetchp
andq
from 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