Tags: openssl rsa 

Rating: 0

**Description**

> Trinity needs help, find the key in time and discover the Matrix.

**Files provided**

- `allthekeys.tar.gz`

**Solution**

After extracting the archive, we see that it includes a bunch of files with random 4-character filenames. Looking around with a hexeditor and grep, we can categorise the files into folders as follows:

- `cert/` - 1 SSL certificate file
- `binary/` - 66 binary files
- `ec/` - 65 private EC keys
- `empty/` - 28 empty files
- `rsa/` - 4 private RSA keys

Since the number of private keys and binary files was (more or less) the same, my first attempt was to decrypt the binary files with the private keys we have. I tested at first with the RSA keys, e.g.:

for binary in binary/*; do
for key in rsa/*; do
openssl rsautl -in "$binary" -inkey "$key" -decrypt
done
done

But all of these failed. My working theory was that there would be a 1-to-1 correspondence between the keys and the binary files, so seeing as none of the RSA keys worked on any of the binary files, I tried something else.

Looking more closely at the certificate file, it includes some human-readable data, as well as an encoded certificate representation within `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----`. What happens if we make OpenSSL parse this encoded representation? Maybe the encoded data is actually different.

$ openssl x509 -in cert/6c8e -text -noout

The output is pretty much the same, but our original file has some extra data:

Response Single Extensions:
CT Certificate SCTs:
SCT validation status: valid
Signed Certificate Timestamp:
Version : v1 (0x0)
Log : Morpheus Tesfytiruces CT log
Log ID : SE:CF:68:74:74:70:73:3a:2f:2f:6d:69:6b:65:79:2e:
63:74:66:2e:72:6f:63:6b:73:00:00:00:00:00:00:00
Timestamp : Jun 1 08:05:26.276 1999 GMT
Extensions: none
Signature : ecdsa-with-SHA256
13:37:13:37:13:37:13:37:13:37:13:37:13:37:13:37:
13:37:13:37:13:37:13:37:13:37:13:37:13:37:13:37:
13:37:13:37:13:37:13:37:13:37:13:37:13:37:13:37:
13:37:13:37:13:37:13:37:13:37:13:37:13:37:13:37:
13:37:13:37:13:37:13

Interesting. The signature is obviously fake, but looking closely at the log ID, it doesn't look like binary data. And indeed, if we convert `68:74:70:...:6F:63:6B` to ASCII, we get:

https://mikey.ctf.rocks

If we actually try to access the website, it doesn't really work. The server is saying `400 No required SSL certificate was sent`. We need to send a certificate TO the server? Apparently there is a thing called client certificates, where the server requests that the client sends a certificate. Very useful information, and we can now guess that the certificate we have is not the server certificate, but a client certificate we need to provide. But naturally, there is only a public key in the certificate:

Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:65:18:ab:8d:b3:c5:d4:65:f1:65:f0:85:08:1c:
56:63:18:47:ad:38:b3:3e:b7:36:57:bd:e4:15:eb:
f8:81:4d:c0:ed:43:32:9b:52:82:47:8c:97:e1:5f:
96:a5:1b:e0:63:75:1b:6d:fb:42:40:a1:65:08:93:
83:94:80:7b:eb
ASN1 OID: prime256v1

To make this work we need the private key. Luckily we have dozens of them. Let's extract the public keys from all of our RSA keys:

for key in rsa/*; do
openssl rsa -in "$key" -text -noout
done

Nope, how about the EC keys?

for key in ec/*; do
openssl ec -in "$key" -text -noout
done

No luck! So what about the binary files? Now that we have a server to access, we will probably find the flag on the server, not in the files. If we look at all the binary files in a hexeditor, we can notice something – every single one of them starts with an ASCII `0`. [Sounds familiar](https://www.cryptosys.net/pki/rsakeyformats.html).

> Binary DER-encoded format. This is sometimes called ASN.1 BER-encoded (there is a subtle difference between BER- and DER-encodings: DER is just a stricter subset of BER). The most compact form. If you try to view the file with a text editor it is full of "funny" characters. The first character in the file is almost always a '0' character (0x30).

So let's extract the public keys from these as well:

for key in binary/*; do
openssl ec -in "$key" -inform DER -text -noout
done

One of them in particular is useful:

$ openssl ec -in binary/ddcb -inform DER -text -noout
read EC key
Private-Key: (256 bit)
priv:
13:75:f1:f0:66:84:74:e5:5e:f4:03:2b:e3:92:38:
39:47:8d:10:e4:10:c4:2d:0d:a3:36:7b:21:e4:a7:
25:53
pub:
04:65:18:ab:8d:b3:c5:d4:65:f1:65:f0:85:08:1c:
56:63:18:47:ad:38:b3:3e:b7:36:57:bd:e4:15:eb:
f8:81:4d:c0:ed:43:32:9b:52:82:47:8c:97:e1:5f:
96:a5:1b:e0:63:75:1b:6d:fb:42:40:a1:65:08:93:
83:94:80:7b:eb
ASN1 OID: prime256v1
NIST CURVE: P-256

The `pub` section matches what we have in our client certificate. I tried for a bit to make `curl` work with the certificate + the private key (converted to PEM format), but no luck, the server kept responding with the same error. So:

openssl s_client -key binary/ddcb -cert cert/6c8e -connect mikey.ctf.rocks:443

And indeed, we are flooded with HTML. After opening this, we see a nice ASCII art image, and the flag hiding among the text!

![](https://raw.githubusercontent.com/Aurel300/empirectf/master/writeups/2018-05-31-SecurityFest/screens/allthekeys.png)

`sctf{th3_M4tr1x_1s_4_5y5t3m_N30}`