Intro
As a frequently player on cybergames and ctf’s this year wanted play on prequal of Cybercamp CTF 2018 organized by INCIBE. This allows me to take a snapshot of the maturity and quality of both platforms and challenges, apart from having a good time solving some problems (not always played as tunelko :))
Challenge
On this challenge they give us two files, a corrupted RSA private key and a secret.txt. First thing is replace base64 asterisks given by organizers by a simple slash to fill the encoding padding.
-----BEGIN RSA PRIVATE KEY----- MIIBOwIBAAJBAMSwf+/I42wFwNpDQiGuv0fb9w5Ria2JJAjzrYEYKp4HAKB8nXxm yGx6OWAhI+4PYFYT3pf95J/mg5buCvP19fMCAwEAAQJAKuxRnyR57PL8eSVAY1Vd TPNF4QwOPZ62DHYRISEC++UtRemqE1eBPkRgswiJ91+r9y8EnVw/SvL4GYQmeovS sQIhAOq8Heinxe4udriNOd35SgJV9e87YglCCIfCoAirR0qtAiEA1oIMcKaiRiUj 2S/Q4YFTNySdT+fH16huoSQrEapD9x8///////////////////////////////// 77////////////////////////////////////////////////////////////// //////////////////////////////////////////// -----END RSA PRIVATE KEY-----
We need to recover final part of the key (slash part) as much data as possible. RSA private key tipically follow an PKCS#1 scheme or format.
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
if we parse data we have with openssl we can extract n,e,d,p and q:
$ openssl asn1parse -in key.pem
0:d=0 hl=4 l= 315 cons: SEQUENCE
4:d=1 hl=2 l= 1 prim: INTEGER :00
7:d=1 hl=2 l= 65 prim: INTEGER :C4B07FEFC8E36C05C0DA434221AEBF47DBF70E5189AD892408F3AD81182A9E0700A07C9D7C66C86C7A39602123EE0F605613DE97FDE49FE68396EE0AF3F5F5F3
74:d=1 hl=2 l= 3 prim: INTEGER :010001
79:d=1 hl=2 l= 64 prim: INTEGER :2AEC519F2479ECF2FC79254063555D4CF345E10C0E3D9EB60C7611212102FBE52D45E9AA1357813E4460B30889F75FABF72F049D5C3F4AF2F81984267A8BD2B1
145:d=1 hl=2 l= 33 prim: INTEGER :EABC1DE8A7C5EE2E76B88D39DDF94A0255F5EF3B6209420887C2A008AB474AAD
180:d=1 hl=2 l= 33 prim: INTEGER :D6820C70A6A2462523D92FD0E1815337249D4FE7C7D7A86EA1242B11AA43F71F
Error in encoding
139985901871296:error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long:../crypto/asn1/asn1_lib.c:101:
So we have only to make rest operations with help of python:
#!/usr/bin/python
import pyasn1.codec.der.encoder
import pyasn1.type.univ
import base64
# present values on key.pem
e = 0x010001
n = 0xC4B07FEFC8E36C05C0DA434221AEBF47DBF70E5189AD892408F3AD81182A9E0700A07C9D7C66C86C7A39602123EE0F605613DE97FDE49FE68396EE0AF3F5F5F3
p = 106173580239682931389627142547722999257831171755485751420548914984291463023277
q = 97024725573258981352721169214486148772531836683230815123426383547032318244639
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
gcd, x, y = egcd(a, m)
if gcd != 1:
return None
else:
return x % m
# we need to recover this values on private key
dp = modinv(e, (p - 1))
dq = modinv(e, (q - 1))
qi = modinv(q, p)
phi = (p - 1) * (q - 1)
d = modinv(e, phi)
def generate_pem(n, e, d, p, q, dP, dQ, qInv):
template = '-----BEGIN RSA PRIVATE KEY-----\n{}-----END RSA PRIVATE KEY-----\n'
seq = pyasn1.type.univ.Sequence()
for x in [0, n, e, d, p, q, dP, dQ, qInv]:
seq.setComponentByPosition(len(seq), pyasn1.type.univ.Integer(x))
der = pyasn1.codec.der.encoder.encode(seq)
return template.format(base64.encodestring(der).decode('ascii'))
key = generate_pem(n, e, d, p, q, dp, dq, qi)
key
f = open("somevalid.key", "w")
f.write(key)
f.close()
Once we generate our valid private key we’ll be able to read the flag:
$ cat somevalid.key
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAMSwf+/I42wFwNpDQiGuv0fb9w5Ria2JJAjzrYEYKp4HAKB8nXxmyGx6OWAhI+4P
YFYT3pf95J/mg5buCvP19fMCAwEAAQJAKuxRnyR57PL8eSVAY1VdTPNF4QwOPZ62DHYRISEC++Ut
RemqE1eBPkRgswiJ91+r9y8EnVw/SvL4GYQmeovSsQIhAOq8Heinxe4udriNOd35SgJV9e87YglC
CIfCoAirR0qtAiEA1oIMcKaiRiUj2S/Q4YFTNySdT+fH16huoSQrEapD9x8CIQC2/WOLhY8FeO9Q
O7hK1RXe8EhC8VYhxXqE6zJ6z5tKGQIgZkLLQWz/EWelRmXYM5kenbwzzqMVj0b5rpJ6gcpk6ksC
IQDk7SB3+YXESMSY0iXCoJjwxOjoCfRPCbeCrka+0s2pyw==
-----END RSA PRIVATE KEY-----
$ cat secret.txt | openssl rsautl -decrypt -inkey somevalid.key
flag{gk83h280fwlo2}
