1337UP LIVE CTF 2023
Really Secure Apparently [100 pts]
Challenge Description:
Apparently this encryption is “really secure” and I don’t need to worry about sharing the ciphertext, or even these values..
n = 689061037339483636851744871564868379980061151991904073814057216873412583484720768694905841053416938972235588548525570270575285633894975913717130070544407480547826227398039831409929129742007101671851757453656032161443946817685708282221883187089692065998793742064551244403369599965441075497085384181772038720949
e = 98161001623245946455371459972270637048947096740867123960987426843075734419854169415217693040603943985614577854750928453684840929755254248201161248375350238628917413291201125030514500977409961838501076015838508082749034318410808298025858181711613372870289482890074072555265382600388541381732534018133370862587
The values given and the problem name itself (whose acronym is cleverly RSA) implies that the encryption algorithm used is RSA. Except… that’s a really large e value isn’t it?
Usually, it’s more common to see e as 65537 or some other small number.
If you’re familiar with common RSA attacks, you might recognize this as Wiener’s attack. Because e and d are modular inverses for a modulus of phi(n), i.e. Euler’s Totient Function, when e is really large, d is usually pretty small! Therefore, it is possible to essentially figure out d with educated brute force.
Simply using the owiener python module will allow you to easily decrypt the ciphertext and get the flag!
INTIGRITI{0r_n07_50_53cur3_m4yb3}
Here is the implementation:
def long_to_bytes(n):
l = []
x = 0
off = 0
while x != n:
b = (n >> off) & 0xFF
l.append( b )
x = x | (b << off)
off += 8
l.reverse()
return bytes(l)
def bytes_to_long(s):
n = s[0]
for b in (x for x in s[1:]):
n = (n << 8) | b
return n
import owiener
n = 689061037339483636851744871564868379980061151991904073814057216873412583484720768694905841053416938972235588548525570270575285633894975913717130070544407480547826227398039831409929129742007101671851757453656032161443946817685708282221883187089692065998793742064551244403369599965441075497085384181772038720949
e = 98161001623245946455371459972270637048947096740867123960987426843075734419854169415217693040603943985614577854750928453684840929755254248201161248375350238628917413291201125030514500977409961838501076015838508082749034318410808298025858181711613372870289482890074072555265382600388541381732534018133370862587
d = owiener.attack(e, n)
f = open('crypto/reallysecureapparently/ciphertext', 'rb').read()
f = bytes_to_long(f)
m = pow(f, d, n)
print(long_to_bytes(m))