TJ CTF 2024
Account Leak [134 pts]
Uncrackable password? I thought this was a CTF; get me my friends minecraft password pls <3
nc tjc.tf 31601
Here’s the Python source:
#!/usr/local/bin/python3.10 -u
import time
from Crypto.Util.number import getPrime, getRandomInteger, getRandomNBitInteger
flag = open("flag.txt").read().strip()
p = getPrime(512)
q = getPrime(512)
sub = getRandomInteger(20)
# hehe u cant guess it since its random :P
my_password = getRandomNBitInteger(256)
n = p*q
c = pow(my_password, 65537, n)
dont_leak_this = (p-sub)*(q-sub)
def gamechat():
print("<Bobby> i have an uncrackable password maybe")
print(f"<Bobby> i'll give you the powerful numbers, {c} and {n}")
print("<Bobby> gl hacking into my account")
print("<Bobby> btw do you want to get my diamond stash")
resp = input("<You> ")
if (resp.strip() == "yea"):
print("<Bobby> i'll send coords")
print(f"<Bobby> {dont_leak_this}")
print("<Bobby> oop wasnt supposed to copypaste that")
print("<Bobby> you cant crack my account tho >:)")
tic = time.time()
resp = input("<You> ")
toc = time.time()
if (toc-tic >= 2.5):
print("<Bobby> you know I can reset my password faster than that lol")
elif (resp.strip() != str(my_password)):
print("<Bobby> lol nice try won't give password that easily")
else:
print("<Bobby> NANI?? Impossible?!?")
print("<Bobby> I might as wel give you the flag")
print(f"<Bobby> {flag}")
else:
print("<Bobby> bro what, who denies free diamonds?")
print("Bobby has left the game")
gamechat()
Seems like another RSA challenge. We’re provided a leak equivalent to (p-sub)(q-sub)
, where sub
is a random 20-bit integer. Well, we can actually do a bit of math to turn this leak into knowledge of phi(n), i.e. Euler’s totient, which will allow us to decrypt the password ciphertext and get the flag:
Now, in order to get sub
, we can just brute-force it, knowing that it is a factor of \(n - leak\)
from pwn import *
from sympy.ntheory import factorint
from Crypto.Util.number import *
r = remote('tjc.tf', 31601)
r.recvuntil(b', ')
res = r.recvline().decode("ascii").split(' ')
c = int(res[0])
n = int(res[-1])
r.sendlineafter(b'<You> ', b'yea')
r.recvline()
leak = int(r.recvline().decode('ascii')[:-1].split()[-1])
sub = -1
for i in range(1<<19, 1<<20): # 50% chance for it to be 20 bits long
if (n - leak) % i == 0:
print(i)
sub = i
break
assert sub.bit_length() == 20
p_plus_q = (n - leak)//sub + sub
phi = n - p_plus_q + 1
d = inverse(65537, phi)
pt = pow(c, d, n)
r.sendlineafter(b'<You> ', str(pt).encode())
r.interactive()
tjctf{h3y_wh3r3_d1d_my_d1am0nds_g0_th3y_w3r3_ju5t_h3r3}