Pearl Ctf 2024 Writeup by Fai I have participanted in Pearl Ctf 2024 with Students Taking Flags Society and we achieved 8th/601. The below writeup is the chals I solved **OSINT** - Noob Hacker This is the Osint series-2, after series-1, from the youtube comments we got the github page of shenoyharry. we can found a repo named PGP, which is an encryption system used for both sending encrypted emails and encrypting sensitive files. After base64 decoding the given file we found his email. pearl{shenoyharry@proton.me} - Bomb Trace Still in shenoyharry's github page, we can find a whatsapp chat screenshot from 'cool', after accessing the url inside the screenshot we found a image, which an AI generated art museum ticket and a geometric location attached in it. Googling it show us the result of virginia. pearl{virginiamuseumoffinearts} - lost letter Since the organization is from india, I immediately search all the states and city which start with T and J, after few attempts I got the flag. pearl{jagtial_telangana} **Crypto** - Baby's Message Out ``` #!/usr/bin/env python3 from Crypto.Util.number import getPrime, isPrime, bytes_to_long from flag import FLAG from math import log import sys n = pow(10, 5) sys.setrecursionlimit(n) def nextPrime(p): if isPrime(p): return p else: return nextPrime(p + 61) p = getPrime(256) q = nextPrime(nextPrime(17*p + 1) + 3) r = nextPrime(29*p*q) s = nextPrime(q*r + p) t = nextPrime(r*s*q) n = p*q*r*s*t e = 65537 m = bytes_to_long(FLAG.encode()) c = pow(m, e, n) print(f"c: {c}") print(f"n: {n}") ``` This chals is about multi-prime RSA. from the source code we can see that all primes and some relations and can all be written as p. since p is a large prime, for every next/fore prime it makes a big change towards n. And the difference between p^n^ and p^n-1^ is small. Hence, we could try to write q,r,s,t as a*p^b, where a and b is a constant. after calculation, we got n = 17^8^ * 29^4^ * p^13^. so p = (n/(17^8^ * 29^4^))^(1/13)^. ``` def nextPrime(p): if isPrime(p): return p else: return nextPrime(p + 61) def primegen(p): q = nextPrime(nextPrime(17*p + 1) + 3) r = nextPrime(29*p*q) s = nextPrime(q*r + p) t = nextPrime(r*s*q) return q*r*s*t*p def find_p(papprox, n): while True: print(papprox) try: n_approx = primegen(papprox) except: continue papprox = gmpy2.iroot(n//(pow(17, 8)*pow(29, 4)), 13)[0] p = find_p(papprox, n) q = nextPrime(nextPrime(17*p + 1) + 3) r = nextPrime(29*p*q) s = nextPrime(q*r + p) t = nextPrime(r*s*q) phi = (p-1)*(q-1)*(r-1)*(s-1)*(t-1) d = inverse(e, phi) pt = long_to_bytes(pow(c, d, n)) print(pt) ``` - 3 spies ``` #!/usr/bin/env python3 from Crypto.Util.number import getPrime, bytes_to_long with open('flag.txt', 'rb') as f: flag = f.read() n1 = getPrime(512)*getPrime(512) n2 = getPrime(512)*getPrime(512) n3 = getPrime(512)*getPrime(512) e=3 m = bytes_to_long(flag) c1 = pow(m,e,n1) c2 = pow(m,e,n2) c3 = pow(m,e,n3) with open('encrypted-messages.txt', 'w') as f: f.write(f'n1: {n1}\n') f.write(f'e: {e}\n') f.write(f'c1: {c1}\n\n') f.write(f'n2: {n2}\n') f.write(f'e: {e}\n') f.write(f'c2: {c2}\n\n') f.write(f'n3: {n3}\n') f.write(f'e: {e}\n') f.write(f'c3: {c3}\n') ``` since the e is small and used to generate three different cipher, it is under broadcast attack. ``` n = [n1, n2, n3] c = [c1, c2, c3] d = c1*c2*c3 m = gmpy2.iroot(d, e)[0] ``` - Rick Roll lost the source of this chals, basically just vigenre cipher + ROT13. **Misc** - Excel Mayhem treat the excel as zip and unzip it, we can found the flag in sharedstrings.xml - TooRandom The chals is bugged and can get the flag right away. - i^2 = -1 We solved this chals in the competition time actually but none of us spotted that, we found it out after competition end :( ``` car1_complex = car1.astype(np.int16) imwrite("unknown.png", car1_complex[..., 0].astype(np.float64) / 4) ``` By doing this we can saw the flag in the shadow of car. **Web** - rabbithole By access to robots.txt we can see it disallowed /w0rk_h4rd, after accessing to it is show us a bold text about **s3cr3t1v3_m3th0d**. So if we raise a request as `s3cr3t1v3_m3th0d /w0rk_h4rd` we can get the flag. **Reversing** - input-validator ``` def reverse(): var3 = [1102, 1067, 1032, 1562, 1612, 1257, 1562, 1067, 1012, 902, 882, 1397, 1472, 1312, 1442, 1582, 1067, 1263, 1363, 1413, 1379, 1311, 1187, 1285, 1217, 1313, 1297, 1431, 1137, 1273, 1161, 1339, 1267, 1427] str2 = "oF/M5BK_U<rqxCf8zWCPC(RK,/B'v3uARD" for i in range(34): var3[i] -= 1337 var2 = [] for i in range(34): var2.append(0) for i in range(17): var2[1+2*i] = var3[i]//5 var2[2*i] = var3[i+17]//2 for i in range(34): var2[i] += ord(str2[33-i]) print(var2) str1 = '' for i in range(34): str1 += chr(bytes_to_long(xor(var2[i], ord(str2[i])))) print(str1) var1 = "" var2 = "oF/M5BK_U<rqxCf8zWCPC(RK,/B'v3uARD" var3 = "pearl{aaaaaaaaaaaaaaaaaaaaaaaaaaa}" reverse() ```