SwampCTF 2019 Brainwallet (Crypto) Writeup

Reading time ~2 minutes

Problem Description

Ever since their hella successful ICO, the crypto experts at VapeCoinIO have put developers first with their simple, intuitive, and, most importantly, secure API. Once you’ve created your account and set up your wallet, you can access it programmatically using your VapeID by sending a GET request to /api/login?key=<HASH> where <HASH> is your VapeID. Your wallet is transferred to you over TLS, so don’t worry—it’s really, really secure. In fact, it’s so secure that the founder and CEO of VapeCoinIO uses the API for his personal Brainwallet.

One of your contacts is a site-reliability engineer at VapeCoinIO. He has obtained a PCAP of a TLS session with a client originating from an IP he suspects to be used by CEO’s personal laptop. Perhaps he accessed his wallet! Can you find a way to recover its contents?


Inspecting the packet capture

As the problem description says, the first thing we notice in the PCAP is that the data is transferred exclusively over a TLS connection. Thus the first thing we need to look for is something amiss in the TLS exchange such as the use of a weak cipher.

We can see in the PCAP that the TLS connection is using: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256

DHE stands for “Diffie-Hellman ephemeral” which is where the RSA key is used to sign the server’s Diffie-Hellman public number to provide authenticity and every TLS session uses a new set of public numbers.

Looking at the Diffie-Hellman numbers in wireshark, we notice something very interesting:

Wireshark Disection TLS Exchange

Those numbers look absolutely tiny! Diffie-Hellman’s security is based on the difficulty of the Discrete Logarithm problem. Ordinarily the p (prime) for DH is a 2048 bit number, here it’s an abysmal 32 bits making it trivial to compute discrete logarithms on. SageMath has several algorithms built in to compute discrete logs so we wrote up a quick script to recover the client’s secret number.

p = 0xf661398b
g = 0x02
client_public = 0x42b2769b
server_public = 0x916ddb94

k = GF(p)
client_secret = discrete_log_lambda(k(client_public), k(g), (1,2**32))
# 0x5ec3d070

The client secret is then enough to compute the shared secret. This is known as the pre-master secret in TLS terms which is all wireshark needs to decrypt TLS traffic.

premaster_secret = pow(server_public, client_secret, p)
# 0xf5ca9f85

Decrypting with Wireshark

In order to let Wireshark utilize this, it needs a file mapping TLS sessions to the master or pre-master secrets. So we made a file called keylogfile.txt containing:

PMS_CLIENT_RANDOM 358970edf3544c1181cecf3369cd4c0e69be2c3605662ba1288b251161eba51e f5ca9f85

PMS stands for Pre-Master Secret and the giant number in the middle is the client random, sent as part of the Client Hello packet which is what wireshark uses to map the PMS to the right TLS session.

(Note: wireshark displays the timestamp and random bytes seperately if you expand the Random portion in the TLS packet, the client random is the timestamp and random bytes together.)

We set up Wireshark’s TLS protocol settings to use the log file:

Wireshark TLS Preferences

and boom, follow the TLS stream in Wireshark for the flag:

Wireshark TLS Stream

SwampCTF 2019 Future Fun (Reverse) Writeup

# Problem Description>Deep on the web, I discovered a secret key validation. It appeared to be from the future, and it only had one sente...… Continue reading

Minecraft Vulnerability Advisory

Published on April 16, 2015

Arduino Powered Room Temperature Graphs

Published on December 18, 2011