Skip to content

Instantly share code, notes, and snippets.

@spake
Created September 27, 2015 14:53
Show Gist options
  • Save spake/77dbedfaaaa20def00e3 to your computer and use it in GitHub Desktop.
Save spake/77dbedfaaaa20def00e3 to your computer and use it in GitHub Desktop.
Trend Micro CTF 2015: Crypto 100

We get two pieces of information; what looks like an RSA public key:

-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhALYtzp8lgWNXI9trGI8S8EacvuDLxdrL
NsNuDJa26nv8AgMBAAE=
-----END PUBLIC KEY-----

and what appears to be an encrypted message:

kPmDFLk5b/torG53sThWwEeNm0AIpEQek0rVG3vCttc=

The description mentions that:

  • we’ll want to decrypt the message with the missing private key
  • there is a missing 1 bit
  • we might want to do prime factorisation.

So let’s take a closer look at the public key using Python:

from Crypto.PublicKey import RSA

pubkey = RSA.importKey(open('PublicKey.pem').read())
print 'n =', pubkey.n

which gives us the key's modulus as

n = 82401872610398250859431855480217685317486932934710222647212042489320711027708

This looks to be 256-bit (easily factorable), but it doesn't look right; the modulus should be the product of two 128-bit primes, yet it's even?!

So what about that missing 1 bit... well there are two ways we could throw in a 1 bit (in a useful way that makes the modulus no longer even, that is). We could append a 1 to the end of the modulus:

(n << 1) | 1 = 164803745220796501718863710960435370634973865869420445294424084978641422055417

Unfortunately WolframAlpha tells us this is prime, so not a great modulus! We could also try replacing the least-significant bit with 1:

n | 1 =
82401872610398250859431855480217685317486932934710222647212042489320711027709

WolframAlpha doesn't tell us anything about its factors, so they probably aren't too small (and thus hopefully non-trivial); we'll have to use something a bit more heavy-duty to factor it though, like msieve.

./msieve 82401872610398250859431855480217685317486932934710222647212042489320711027709

This takes a couple of minutes to factor, but we eventually get (from msieve.log) that our modified modulus has factors

p = 279125332373073513017147096164124452877
q = 295214597363242917440342570226980714417

which looks promising! Let's try making a private key out of these and decrypting the message:

from Crypto.PublicKey import RSA
import gmpy

msg = "kPmDFLk5b/torG53sThWwEeNm0AIpEQek0rVG3vCttc="

# factors of the modified modulus, from msieve
p = 279125332373073513017147096164124452877L
q = 295214597363242917440342570226980714417L
n = p*q

e = 65537L # standard e, was also in the public key we were given

# calculate d based on the factors; thank you gmpy
d = long(gmpy.invert(e, (p-1)*(q-1)))

privkey = RSA.construct((n,e,d,p,q))
print repr(privkey.decrypt(msg.decode('base64')))

which gives us

'\x02\xd8T\xf1v\xea\xa0y!\x00TMCTF{$@!zbo4+qt9=5}\n'

and hence we have our flag

TMCTF{$@!zbo4+qt9=5}

Yay!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment