CTF,

Cybercamp 2018 quals: «Unnecessary redundancy»

sshot-11

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}

No hay contenido relacionado