Noncense (800)

  • Challenge description: Dear RTN,

As you might know, I am the CEO of False Fruits Ltd, and we are one of the main producers of smoothies in the country.

Recently, I received a message from our IT department that our security system has problems. Two of our employees did not follow the protocol to the letter, which resulted in the formula of our latest smoothie getting leaked to the public.

As one of our regulars, it is my duty to inform you about any possible security breaches in our systems. We are still investigating this incident, but since you are an expert in the field, any help is appreciated.

Attached are some of the documents that resurfaced which you might find interesting.

Best regards, Dr. E. Zecutive CEO of False Fruits Ltd

P.S: The IT department said something about SHA 256 and public keys. Personally I have a hard time making heads and tails out of this nonsense.


noncense.zip contains the following files:

  • document01.pdf through document05.pdf
  • document01.sig through document05.sig
  • berry.pub, vgtables.pub
  • get_flag.sh
  • message.txt

message.txt contains a copy of the challenge description, so we can safely skip that.

get_flag.sh contains the following shellscript:

#!/bin/sh
scp -i key_file.pem vgtables@smoothie.rtn-team.cc:/home/vgtables/secret_document.pdf flag.pdf

vgtables.pub contains the following public key (and berry.pub contains a similar one):

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0UCtYSD1mAZ6bhWceNOXgF3MmKye
P/d6ZGsZfL5RZdYYuruVqVgxLZdvT3gZPVKGWvQlJAUyUI7oDfnTc07RIw==
-----END PUBLIC KEY-----

The .sig files contained some binary data.

So judging from the files, it seems that the PDF documents are signed through these public keys, and we need to generate key_file.pem so we can connect to the remote server over SSH to get the flag.

I started of by looking into the public keys. Using this site, I decoded the public key of vgtables into the following structure:

Algo ECDSA
Format X.509
 ASN1 Dump
EC Public Key [06:03:30:8a:a9:1a:d3:4e:0a:60:69:a0:c5:1c:7e:f0:14:ac:ac:9d]
            X: d140ad6120f598067a6e159c78d397805dcc98ac9e3ff77a646b197cbe5165d6
            Y: 18babb95a958312d976f4f78193d52865af425240532508ee80df9d3734ed123

It looks like ECDSA is used for this public key. According to Wikipedia it is possible to recover the public key if a nonce is re-used. And guess what, the title of this challenge hints towards nonces being important. If you want to see an informative and entertaining explanation of this vulnerability, this talk by fail0verflow for 27c3 on hacking the PS3. It's only ~5 minutes, and shows a legendary moment in console hacking history, so I definitely recommend watching it.

To abuse a nonce reuse vulnerability, we need to first find a reused nonce. We can list a hexdump of all signatures with the shellscript for i in *.sig; do print "$i:"; hexdump "$i"; done:

document01.sig:
0000000 4630 2102 fa00 9646 c7cd 25c5 d4a5 c381
0000010 87e1 1485 99b2 1765 b0dd d374 91b3 7ac2
0000020 0eb5 ff57 029e 0021 50ae a65f 4382 51e2
0000030 2a76 561c 24b3 2df3 085b 1c08 a1e2 f48e
0000040 328e 04b7 2ecb a088
0000048
document02.sig:
0000000 4530 2102 aa00 20f6 8a08 5609 58bd 51e9
0000010 9257 a802 c5ac 3a2b 4ffa 3fd7 30fd c68b
0000020 fdef fc1e 025c 2220 bf41 669f da35 71e7
0000030 07ae 54ca c15f 4380 2666 d3f6 d031 7393
0000040 b68f 159b 9784 0086
0000047
document03.sig:
0000000 4430 2002 4f68 5b82 9c58 dfcd ac23 8684
0000010 55c5 2142 43ba 8ef9 5516 8086 a368 17ed
0000020 ae02 400d 2002 5543 2b0d 28d3 6f0d 07d0
0000030 336f 77f2 1eb1 d6b6 9112 751e ff94 6a6d
0000040 1ae1 dbb7 7d4d
0000046
document04.sig:
0000000 4630 2102 aa00 20f6 8a08 5609 58bd 51e9
0000010 9257 a802 c5ac 3a2b 4ffa 3fd7 30fd c68b
0000020 fdef fc1e 025c 0021 68c7 1933 78b5 2130
0000030 87b6 8e96 4adb ca41 cf82 9b80 4735 5f90
0000040 c3a3 1800 df22 cea1
0000048
document05.sig:
0000000 4630 2102 d400 2a1a f54d 0649 2dec 6a5f
0000010 d1bb 476b 8ec9 46c7 0af9 9ba7 d59a fefc
0000020 1312 3186 02b6 0021 8bf6 6dfb 7a7b 742f
0000030 47bd dbec 4c96 f3fc 2390 eb8a 6409 f702
0000040 f3ff 8fe1 e9ec 4522
0000048

From looking at the PDF files, we know that documents 1, 3 and 5 are signed by "berry", and 2 and 4 by "vgtables". Looking at the signatures, we can notice that the first 36 bytes of document 2 and 4's signature are the exact same. From that I deduced that they most likely used the same nonce, so these were the signatures to try.

Elliptic-curve crypto is something I don't (and don't want to) understand, so I'll just use this tool by bytemare on GitHub. I checked out commit 68ea2aa3a8871ec1214cfcb0e7fb76590e34f404 and applied the following changes:

diff --git a/ecdsa-nonce_reuse-crack.py b/ecdsa-nonce_reuse-crack.py
index 6596f62..d4fff74 100755
--- a/ecdsa-nonce_reuse-crack.py
+++ b/ecdsa-nonce_reuse-crack.py
@@ -42,31 +42,21 @@ def rs_from_der(der_encoded_signature):
     :return: r, s
     """

-    # Look if library is available
-    try:
-        __import__("ecdsa.der")
-    except ImportError:
-        array = binascii.hexlify(base64.b64decode(der_encoded_signature))
-
-        # r
-        r_length = 2 * int(array[6:8], 16)
-        r = array[8:8 + r_length]
-
-        # s
-        s_offset = 8 + r_length
-        s = array[s_offset + 4:]
-
-        # Cast them to integers
-        # r = long(r, 16)
-        # s = long(s, 16)
-        r = int(r, 16)
-        s = int(s, 16)
+    array = binascii.hexlify(der_encoded_signature)

-    else:
-        rs, _ = der.remove_sequence(der.unpem(der_encoded_signature))
-        r, tail = der.remove_integer(rs)
-        # s, point_str_bitstring = der.remove_integer(tail)
-        s, _ = der.remove_integer(tail)
+    # r
+    r_length = 2 * int(array[6:8], 16)
+    r = array[8:8 + r_length]
+
+    # s
+    s_offset = 8 + r_length
+    s = array[s_offset + 4:]
+
+    # Cast them to integers
+    # r = long(r, 16)
+    # s = long(s, 16)
+    r = int(r, 16)
+    s = int(s, 16)

     if verbosity >= 2:
         print("r : " + str(r))
@@ -306,7 +296,7 @@ def get_file_content(_file):
     :param _file:
     :return:
     """
-    with open(_file, 'r') as file:
+    with open(_file, 'rb') as file:
         data = file.read()

     return data
@@ -334,9 +324,9 @@ def call_from_files(public_key_path, message1_path, message2_path, signature1_pa

     # Launch exploit to try to get private key
     private_key = get_private_key(public_verification_key.curve,
-                                  msg1.encode('utf-8'),
+                                  msg1,
                                   sig1,
-                                  msg2.encode('utf-8'),
+                                  msg2,
                                   sig2,
                                   get_hash_function(hash_alg))

Once we've made these changes, we can run the script with the following command:

python ecdsa-keyrec/ecdsa-nonce_reuse-crack.py -files \
    --pubkey vgtables.pub \
    --message1 document02.pdf --signature1 document02.sig \
    --message2 document04.pdf --signature2 document04.sig \
    --hashalg sha256 --output key_file.pem

And we're done! After making sure the correct file permissions are applied with chmod 700 key_file.pem, we can run the get_flag.sh shellscript and retrieve the PDF. Open it and we can the flag RTN{h0W_mUcH_m0r3_n0nS3ns3_d0_Y0u_w4Nt}.