<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.3">Jekyll</generator><link href="https://rootfs.eu/feed.xml" rel="self" type="application/atom+xml" /><link href="https://rootfs.eu/" rel="alternate" type="text/html" /><updated>2023-07-21T22:39:51+00:00</updated><id>https://rootfs.eu/feed.xml</id><title type="html">/ fs</title><subtitle>All paths lead to root</subtitle><entry><title type="html">Pwn2Win CTF 2019 - Cloud Admin</title><link href="https://rootfs.eu/pwn2win2019-cloud-admin/" rel="alternate" type="text/html" title="Pwn2Win CTF 2019 - Cloud Admin" /><published>2019-11-12T10:30:00+00:00</published><updated>2019-11-12T10:30:00+00:00</updated><id>https://rootfs.eu/pwn2win2019-cloud-admin</id><content type="html" xml:base="https://rootfs.eu/pwn2win2019-cloud-admin/">&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; Miscellaneous, &lt;strong&gt;Solves:&lt;/strong&gt; 7, &lt;strong&gt;Score:&lt;/strong&gt; 383&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I was able to capture a simple database from the Organization’s virtual machine. After gaining access as a cloud admin, I also managed to dump the VM memory. Maybe there is some important messages in this database…&lt;/p&gt;

  &lt;p&gt;Link: &lt;a href=&quot;https://cloud.ufscar.br:8080/v1/AUTH_c93b694078064b4f81afd2266a502511/static.pwn2win.party/cloud_admin_cbbeacb2025a5c979da7e9eddbe9119cf05fbd9d2b115f7ec8cc1810040ad82d.tar.gz&quot;&gt;https://cloud.ufscar.br:8080/v1/AUTH_c93b694078064b4f81afd2266a502511/static.pwn2win.party/cloud_admin_cbbeacb2025a5c979da7e9eddbe9119cf05fbd9d2b115f7ec8cc1810040ad82d.tar.gz&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Mirror: &lt;a href=&quot;https://static.pwn2win.party/cloud_admin_cbbeacb2025a5c979da7e9eddbe9119cf05fbd9d2b115f7ec8cc1810040ad82d.tar.gz&quot;&gt;https://static.pwn2win.party/cloud_admin_cbbeacb2025a5c979da7e9eddbe9119cf05fbd9d2b115f7ec8cc1810040ad82d.tar.gz&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;!--kg-card-end: markdown--&gt;
&lt;!--kg-card-begin: markdown--&gt;
&lt;h2 id=&quot;analysis&quot;&gt;Analysis&lt;/h2&gt;

&lt;p&gt;We’re given an SQLite database, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data.db&lt;/code&gt;, and a memory dump from a virtual machine, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memory.dump&lt;/code&gt;. Initially, we dumped the contents of the database to see what we’re dealing with:&lt;/p&gt;

&lt;h3 id=&quot;database&quot;&gt;Database&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sqlite3 data.db
SQLite version 3.22.0 2018-01-22 18:45:57
Enter &quot;.help&quot; for usage hints.
sqlite&amp;gt; .tables
MSGS
sqlite&amp;gt; .dump MSGS
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE MSGS(ID int, CONTENT text);
INSERT INTO MSGS VALUES(0,'7f80b3887fa22a29c02d302dbd72d9ee2df1ef86c915210e153375aa2684cab1004ede5787b4adb2bf');
INSERT INTO MSGS VALUES(0,'a83acee0c65881a61cf2d8c91624bb2d5d5d63ddbd26f834a03aa3c3e79407a1fdbf2d6557b9');
INSERT INTO MSGS VALUES(0,'3163da8582380813b8798571e2900aacd1602ac218d401e72cd784d1aa809eb39e108f601c04');
INSERT INTO MSGS VALUES(0,'c91f4bdd9b199ac7a8f1d1aa8a5d30668f62b0a6f28855f893af3bb3b78bb600c15564c5198b175aef535711f17895b2a7423cdaf617d4df23cd0f8840f6326188cff29c32fbb52bb2181fc742d98dc966bf28b2');
INSERT INTO MSGS VALUES(0,'d97a56b474d7bb2a530f5e4fee4b814050f08f89883867497ef4d922931a6a47af9edc8');
COMMIT;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There’s a table, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSGS&lt;/code&gt;, which contains some hex-encoded strings. The message &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c91f4bdd9b199ac7a8f1d1aa8a5d30668f62b0a6f28855f893af3bb3b78bb600c15564c5198b175aef535711f17895b2a7423cdaf617d4df23cd0f8840f6326188cff29c32fbb52bb2181fc742d98dc966bf28b2&lt;/code&gt; is particularly interesting because it is quite long compared to the rest. Just decoding them yields gibberish. Seeing that, and given the challenge description, we assumed one of these messages is the flag. It is possibly encrypted in some fashion and we’re supposed to figure out how to decrypt it by making use of the memory dump.&lt;/p&gt;

&lt;h3 id=&quot;memory-dump&quot;&gt;Memory dump&lt;/h3&gt;

&lt;p&gt;Initially, we did a bit of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strings&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt; on the memory dump to see what kind of information we can glean from it. We learned that:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;This is a memory dump of a 64-bit Ubuntu 16.04.5 VM (the specific version comes into play again later).&lt;/li&gt;
  &lt;li&gt;There’s something about a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secret_msg.py&lt;/code&gt; script, with some strings pointing to the usage of AES.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A teammate had extracted the script with a bit of ad-hoc analysis at this point:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import sqlite3
import requests
import base64
import os
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import (
    Cipher, algorithms, modes
id_count = 0
key = None
def create_db():
    conn = sqlite3.connect('data.db')
    cursor = conn.cursor()
    cursor.execute(&quot;CREATE TABLE MSGS(ID int, CONTENT text)&quot;)
    conn.commit()
    conn.close()

def enc(msg):
    iv = os.urandom(12)
    encryptor = Cipher(
        algorithms.AES(key),
        modes.GCM(iv),
        backend=default_backend()
    ).encryptor()
    enc = encryptor.update(msg) + encryptor.finalize()
    return (iv + encryptor.tag + enc).encode(&quot;hex&quot;)

def insert_new_message(msg):
    conn = sqlite3.connect('data.db')
    cursor = conn.cursor()
    cursor.execute(&quot;INSERT INTO MSGS VALUES(&quot; + str(id_count) + &quot;, '&quot; + enc(msg) + &quot;')&quot;)
    conn.commit()
    conn.close()

def test():
    global key
    key = base64.b64decode(requests.get('https://172.17.0.2:5000', verify=False).content)
    create_db()
    while(True):
        try:
            msg = requests.get('https://172.17.0.2:5000', verify=False).content
            insert_new_message(msg)
        except:
            break
test()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After going through the script, we noticed a few things:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Our assumption about the messages being encrypted was correct. It is AES in GCM mode and nothing looks immediately wrong with the crypto. Pwn2Win 2018 had a &lt;a href=&quot;https://fireshellsecurity.team/pwn2win-gcm/&quot;&gt;challenge that involved making use of a vulnerability of the AES-GCM implementation in the Python &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cryptography&lt;/code&gt; library&lt;/a&gt;. That specific vulnerability does not apply in this case, though, due to the nature of the challenge.&lt;/li&gt;
  &lt;li&gt;The key used to encrypt the messages as well as the messages themselves were retrieved over HTTPS from some service running at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.17.0.2:5000&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;The key is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt; object referenced by a global in module scope, which means that there’ll always be at least one reference to it and it won’t be collected by the garbage collector.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The most obvious path to solve the challenge is recovering the key from memory. If it is not, and assuming the key is randomly generated using a CSPRNG, this would become unsolvable.&lt;/p&gt;

&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;

&lt;p&gt;We used the &lt;a href=&quot;https://www.volatilityfoundation.org/&quot;&gt;volatility framework&lt;/a&gt; to analyze the memory dump. After some more grepping, we learned that the Linux kernel version of the snapshotted machine is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4.4.0-131-generic&lt;/code&gt;. We used &lt;a href=&quot;https://github.com/bannsec/volatility_profile_builder&quot;&gt;volatility profile builder&lt;/a&gt; to create an Ubuntu 16.04.5 (xenial-20191024) profile and loaded up the dump.&lt;/p&gt;

&lt;p&gt;Listing the processes that were running:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Volatility Foundation Volatility Framework 2.6
Pid Uid Gid Arguments                                                       
1 0 0 /sbin/init                                                      
2 0 0 [kthreadd]                                                      
3 0 0 [ksoftirqd/0]                                      
[...snip...]                                        
1149 1000 1000 -bash                                                           
7288 0 0 [kworker/u2:2]                                                  
7307 0 0 [kworker/u2:0]                                                  
7310 1000 1000 python secret_msg.py                                            
7314 0 0 [kworker/0:0]       
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And here’s the process we’re looking for, the Python 2 (identified the installed Python interpreter version during initial analysis) process with PID &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;7310&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since it is Python 2, we know that the key is going to be of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt; unlike Python 3 where it would have been &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes&lt;/code&gt; instead. We started digging through the &lt;a href=&quot;https://github.com/python/cpython/tree/2.7&quot;&gt;CPython 2.7&lt;/a&gt; source code to understand how Python strings are represented in memory.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/python/cpython/blob/2.7/Include/stringobject.h&quot;&gt;layout for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt; instances on a 64-bit architecture&lt;/a&gt; is as follows (in pseudocode):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PyStringObject {
   ulong reference_count;
   PyTypeObject * string_type;
   long string_length;
   long string_hash;
   int string_state;
   char string_value[string_length + 1]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyTypeObject&lt;/code&gt; refers to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyString_Type&lt;/code&gt; in this case, and has a &lt;a href=&quot;https://github.com/python/cpython/blob/2.7/Objects/stringobject.c&quot;&gt;layout that starts as&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PyString_Type {
   ulong reference_count;
   PyTypeObject * type;
   long string_object_length;
   char * name = &quot;str\x00&quot;;
   [...snip unnecessary attributes...]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our strategy was: find all the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt; instances in the process memory and filter them down to possible AES key candidates, then try all of them. In detail, the plan is to:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Identify all byte sequences that represent &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str\x00&lt;/code&gt;, that is the ASCII string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt; with a terminating null byte (i.e. a regular C string).&lt;/li&gt;
  &lt;li&gt;Look for all the locations in memory that reference the identified byte sequences’ addresses. One of them should be at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyString_Type + 0x18&lt;/code&gt; (as indicated by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyString_Type&lt;/code&gt; model), and ideally, there will be only one instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyString_Type&lt;/code&gt; in memory.&lt;/li&gt;
  &lt;li&gt;Look for all the locations that reference the address of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PyString_Type&lt;/code&gt;, these should be the second field of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt; instances, referencing the type of the instance. For each of the locations &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location_address&lt;/code&gt; that fit the criterion, we’ll have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location_address + 0x8&lt;/code&gt; be the address where the corresponding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt; instance resides.&lt;/li&gt;
  &lt;li&gt;Filter them down to ones that could be used as an AES key based on length.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Implementing this process with volatility was relatively easy since it provides a handy Python shell that we could use to analyze the process memory, allowing us to read data from the process using virtual addresses, as if we were actually the process itself.&lt;/p&gt;

&lt;p&gt;Here is the volatility shell session, implementing the above process, that was used to solve the challenge during the CTF, annotated wherever clarification is useful:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; cc(pid=7310)
Current context: process python, pid=7310 DTB=0x355b4000
&amp;gt;&amp;gt;&amp;gt; asp = proc().get_process_address_space()
&amp;gt;&amp;gt;&amp;gt; sm = proc().search_process_memory
&amp;gt;&amp;gt;&amp;gt; # A helper function to convert a list of integers into
&amp;gt;&amp;gt;&amp;gt; # little-endian byte string representations of them
&amp;gt;&amp;gt;&amp;gt; def conv(li):
... return list(map(lambda y: y[::-1], map(lambda x: hex(x)[2:-1].decode('hex') if len(hex(x)[2:-1]) % 2 == 0 else ('0' + hex(x)[2:-1]).decode('hex'), li)))
...
&amp;gt;&amp;gt;&amp;gt; # Helper function to right-pad a list of strings to the right with 0
&amp;gt;&amp;gt;&amp;gt; # bytes until they are plen long. Does not apply any transformations
&amp;gt;&amp;gt;&amp;gt; # to strings that are at least plen bytes long.
&amp;gt;&amp;gt;&amp;gt; def rpad(li, plen=8):
... return list(map(lambda x: x + ('\x00' * (plen - len(x))), li))
... 
&amp;gt;&amp;gt;&amp;gt; # Find all memory addresses that point to the sequence 'str\x00'
&amp;gt;&amp;gt;&amp;gt; str_insts = [x for x in sm(['str\x00'])]
&amp;gt;&amp;gt;&amp;gt; str_insts
[4246750L, 4247954L, 4256116L, [...snip...] 140734922346175L]
&amp;gt;&amp;gt;&amp;gt; ptr_str_insts = rpad(conv(str_insts))
&amp;gt;&amp;gt;&amp;gt; # Locate all the memory addresses that point to byte sequences
&amp;gt;&amp;gt;&amp;gt; # representing any of the previously identified memory addresses
&amp;gt;&amp;gt;&amp;gt; ref_str_insts = [x for x in sm(ptr_str_insts)]
&amp;gt;&amp;gt;&amp;gt; ref_str_insts
[9411704L]
&amp;gt;&amp;gt;&amp;gt; # Only one of them was found, which would ideally be the third field
&amp;gt;&amp;gt;&amp;gt; # in the PyString_Type object. Subtract 0x18 to get the address of
&amp;gt;&amp;gt;&amp;gt; # PyString_Type
&amp;gt;&amp;gt;&amp;gt; ref_str_insts = [9411704L - 0x18]
&amp;gt;&amp;gt;&amp;gt; ref_str_insts
[9411680L]
&amp;gt;&amp;gt;&amp;gt; # Find all the memory locations referencing PyString_Type.
&amp;gt;&amp;gt;&amp;gt; str_type_ptrs = [x for x in sm(rpad(conv(ref_str_insts)))]
&amp;gt;&amp;gt;&amp;gt; len(str_type_ptrs)
41867
&amp;gt;&amp;gt;&amp;gt; # Helper function to convert a byte sequence into an integer.
&amp;gt;&amp;gt;&amp;gt; # Assumes the byte sequence is a little-endian ordering.
&amp;gt;&amp;gt;&amp;gt; def s_to_ulong(s):
... return int(s[::-1].encode('hex'), 16)
... 
&amp;gt;&amp;gt;&amp;gt; # Helper function to read a Python `str` from memory, given its
&amp;gt;&amp;gt;&amp;gt; # address. If a string is longer than maxlen then it returns the 
&amp;gt;&amp;gt;&amp;gt; # empty string.
&amp;gt;&amp;gt;&amp;gt; def read_str(asp, off, maxlen=0x100):
... strlen = s_to_ulong(asp.read(off + 0x10, 8))
... if strlen &amp;gt; maxlen:
... return ''
... return asp.read(off + 0x24, strlen)
... 
&amp;gt;&amp;gt;&amp;gt; str_ptrs = list(map(lambda x: x - 0x8, str_type_ptrs))
&amp;gt;&amp;gt;&amp;gt; strs = list(map(lambda x: read_str(asp, x, maxlen=0x20), str_ptrs))
&amp;gt;&amp;gt;&amp;gt; candidate_keys = list(filter(lambda x: len(x) == 16 or len(x) == 32, strs))
&amp;gt;&amp;gt;&amp;gt; len(candidate_keys)
1377
&amp;gt;&amp;gt;&amp;gt; len16 = list(filter(lambda x: len(x) == 16, candidate_keys))
&amp;gt;&amp;gt;&amp;gt; len32 = list(filter(lambda x: len(x) == 32, candidate_keys))
&amp;gt;&amp;gt;&amp;gt; with open('candidate_keys_16', 'wb') as fs:
... map(fs.write, len16) and None
... 
&amp;gt;&amp;gt;&amp;gt; with open('candidate_keys_32', 'wb') as fs:
... map(fs.write, len32) and None
... 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Side-note:&lt;/strong&gt; In hindsight, we should have also extracted 192-bit long strings. We made a mistake there, but it’s very uncommon to see AES keys of that length. However, as luck would have it, the actual key was 128 bits long.&lt;/p&gt;

&lt;p&gt;After extracting the keys, we tried them all with another Python script:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import (
    Cipher, algorithms, modes
)
from cryptography.exceptions import InvalidTag


def dec(msg, key):
    msg = msg.decode('hex')
    iv = msg[:12]
    msg = msg[12:]
    tag = msg[:16]
    ct = msg[16:]
    decryptor = Cipher(
        algorithms.AES(key),
        modes.GCM(iv, tag),
        backend=default_backend()
    ).decryptor()
    return decryptor.update(ct) + decryptor.finalize()


msgs = [
    '7f80b3887fa22a29c02d302dbd72d9ee2df1ef86c915210e153375aa2684cab1004ede5787b4adb2bf',
    'a83acee0c65881a61cf2d8c91624bb2d5d5d63ddbd26f834a03aa3c3e79407a1fdbf2d6557b9',
    '3163da8582380813b8798571e2900aacd1602ac218d401e72cd784d1aa809eb39e108f601c04',
    'd97a56b474d7bb2a530f5e4fee4b814050f08f89883867497ef4d922931a6a847af9edc8',
    'c91f4bdd9b199ac7a8f1d1aa8a5d30668f62b0a6f28855f893af3bb3b78bb600c15564c5198b175aef535711f17895b2a7423cdaf617d4df23cd0f8840f6326188cff29c32fbb52bb2181fc742d98dc966bf28b2',
]


def try_keys():
    with open('candidate_keys_16', 'rb') as fs:
        data = fs.read()
    keys16 = [data[i:i+16] for i in range(0, len(data), 16)]

    with open('candidate_keys_32', 'rb') as fs:
        data = fs.read()
    keys32 = [data[i:i+32] for i in range(0, len(data), 32)]

    keys = keys16 + keys32
    print('Loaded {} keys'.format(len(keys)))

    for k in keys:
        try:
            decrypted = [dec(m, k) for m in msgs]
            if decrypted:
                print('Decrypted messages using key {}'.format(repr(k)))
                print(decrypted)
                break
        except InvalidTag as e:
            pass
        except Exception as e:
            print(e)


try_keys()

$ python solve.py 
Loaded 1377 keys
Decrypted messages using key '\x01\x01\x85\xc8/;\xce\xa3{\x1fL3Y`\xe7\xdb'
['9-999-999-999', 'Cleoswaldo', 'A flag \xc3\xa9:', 'shutdown', 'CTF-BR{d3v14_73r_cr1p706r4f4d0_4n735_d3_ch364r_n4_cl0ud}']
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;flag&quot;&gt;Flag&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CTF-BR{d3v14_73r_cr1p706r4f4d0_4n735_d3_ch364r_n4_cl0ud}&lt;/code&gt;&lt;/p&gt;

&lt;!--kg-card-end: markdown--&gt;</content><author><name>kmhn</name></author><category term="writeup" /><category term="ctf" /><summary type="html">Category: Miscellaneous, Solves: 7, Score: 383</summary></entry><entry><title type="html">CODE BLUE CTF 2017 - Common Modulus series</title><link href="https://rootfs.eu/codeblue2017-common-modulus/" rel="alternate" type="text/html" title="CODE BLUE CTF 2017 - Common Modulus series" /><published>2017-11-15T20:39:00+00:00</published><updated>2017-11-15T20:39:00+00:00</updated><id>https://rootfs.eu/codeblue2017-common-modulus</id><content type="html" xml:base="https://rootfs.eu/codeblue2017-common-modulus/">&lt;p&gt;There are 3 challenges in this series, all of which are based on the same problem with varying conditions. Therefore, we’ll go through them in increasing order of difficulty and build solutions incrementally.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;N.B. All files related to the problems for these challenges and their solutions are available &lt;a href=&quot;https://github.com/khalednassar/ctf_writeups/tree/master/codebluectf2017/common_modulus&quot;&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;common-modulus-1&quot;&gt;Common Modulus 1&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;We made RSA Encryption Scheme/Tester. Can you break it?
&lt;a href=&quot;https://github.com/khalednassar/ctf_writeups/raw/master/codebluectf2017/common_modulus/Common_Modulus_1.zip-37882dbd7dd05381bbf72a11fbbdb3f23def0e4981bc9ffcd399e4c138549fc8&quot;&gt;Common_Modulus_1.zip&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;common-modulus-2&quot;&gt;Common Modulus 2&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;The previous one is very easy. so is this also easy?
&lt;a href=&quot;https://github.com/khalednassar/ctf_writeups/raw/master/codebluectf2017/common_modulus/Common_Modulus_2.zip-24d74ea8d1b7bc154d30bb667f6f13ef24a9fe260a7741caab427421d1070c98&quot;&gt;Common_Modulus_2.zip&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;common-modulus-3&quot;&gt;Common Modulus 3&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;try harder!
&lt;a href=&quot;https://github.com/khalednassar/ctf_writeups/raw/master/codebluectf2017/common_modulus/Common_Modulus_3.zip-275005199fd0ecbec4183fd7e1b421f65c7bb982ffba65a12a4089e263899152&quot;&gt;Common_Modulus_3.zip&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The common setting is that we’re given two RSA-encrypted messages \((c_1, c_2)\) which are the encryptions of the flag \(m\) such that \(c_1\) is the encryption of \(m\) with the public key \((n, e_1)\) and \(c_2\) is the encryption of \(m\) with the public key \((n, e_2)\). In other words, we have two encryptions of the same message with public keys that share the same modulus. To be precise, what we have is&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;\(c_1 = m^{e_1} \mod n\)&lt;/li&gt;
  &lt;li&gt;\(c_2 = m^{e_2} \mod n\)&lt;/li&gt;
  &lt;li&gt;\(e_1, e_2\) are randomly generated primes in the first challenge, which are each multiplied by 3 and 17 for the second and third challenges respectively.&lt;/li&gt;
  &lt;li&gt;\(n\) which is the common modulus to both public keys, a large randomly generated &lt;a href=&quot;https://en.wikipedia.org/wiki/Semiprime&quot;&gt;semiprime&lt;/a&gt; of length 2048, 4096 and 8192 bits respectively for the first, second and third challenges.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In terms of operations that we can do, we can multiply both ciphertexts to get a third ciphertext \(c_m\). That is because textbook RSA is &lt;a href=&quot;https://en.wikipedia.org/wiki/Homomorphism&quot;&gt;homomorphic&lt;/a&gt; with regards to (integer) multiplication. This operation would yield&lt;/p&gt;

\[\begin{align}
&amp;amp; c_m &amp;amp; \mod n\\\\
&amp;amp; = c_1 \cdot c_2 &amp;amp; \mod n\\\\
&amp;amp; = m^{e_1} \cdot m^{e_2} &amp;amp; \mod n\\\\
&amp;amp; = m^{e_1 + e_2} &amp;amp; \mod n
\end{align}\]

&lt;p&gt;And if we were to raise \(c_1\) and \(c_2\) to the powers of \(x\) and \(y\), respectively, then multiply them together&lt;/p&gt;

\[\begin{align}
c_m = c_1^{x} \cdot c_2^{y} &amp;amp; = (m^{e_1})^{x} \cdot (m^{e_2})^{y} &amp;amp; \mod n\\\\
&amp;amp; = m^{e_1 \cdot x} \cdot m^{e_2 \cdot y} &amp;amp; \mod n\\\\
&amp;amp; = m^{x \cdot e_1} \cdot m^{y \cdot e_2} &amp;amp; \mod n\\\\
&amp;amp; = m^{x \cdot e_1 + y \cdot e_2} &amp;amp; \mod n
\end{align}\]

&lt;p&gt;At this point, we can take advantage of &lt;a href=&quot;https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity&quot;&gt;Bézout’s identity&lt;/a&gt;, which simply states&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;For \(a, b \in \mathbb{Z}^{+}\) and their greatest common divisor \(d\), there are \(x, y \in \mathbb{Z}\) such that
\(x \cdot a + y \cdot b = d\)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can calculate \(x\) and \(y\) efficiently using the &lt;a href=&quot;https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm&quot;&gt;Extended Euclidean Algorithm&lt;/a&gt;. If one of the coefficients happens to be negative, then we compute the modular inverse of the respective ciphertext \(\mod n\) first, and raise it to the power of the absolute value of the coefficient. After calculating \(c_m\), we have three different cases. One for each challenge&lt;/p&gt;

&lt;h3 id=&quot;common-modulus-1-1&quot;&gt;Common Modulus 1&lt;/h3&gt;
&lt;p&gt;This is the simplest variation, because \(e_1\) and \(e_2\) are relatively prime, meaning that their greatest common divisor is 1, so it yields&lt;/p&gt;

\[\begin{align}
c_m = c_1^{x} \cdot c_2^{y} &amp;amp; = m^{e_1 \cdot x} \cdot m^{e_2 \cdot y} &amp;amp; \mod n &amp;amp; \\\\
&amp;amp; = m^{e_1 \cdot x + e_2 \cdot y} &amp;amp; \mod n &amp;amp; \\\\
&amp;amp; = m^{1} &amp;amp; \mod n &amp;amp; \quad \text{By Bézout's identity} \\\\
&amp;amp; = m
\end{align}\]

&lt;p&gt;So we’ve successfully recovered the first message, and hence the the first flag: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CBCTF{6ac2afd2fc108894db8ab21d1e30d3f3}&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;common-modulus-2-1&quot;&gt;Common Modulus 2&lt;/h3&gt;
&lt;p&gt;For this variation, we don’t recover the message itself but instead we get \(m^3 \mod n\). However, we know that the flag is of the form&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CBCTF{ ... 32 characters representing a hex-encoded MD5 hash ... }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Meaning that the bit length of the flag is&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;32 characters of the hash, at 8-bits per character, 256 bits +&lt;/li&gt;
  &lt;li&gt;5 characters of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CBCTF&lt;/code&gt;, at 8-bits per character, 40 bits +&lt;/li&gt;
  &lt;li&gt;2 charactes for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;}&lt;/code&gt;, at 8-bits per character, 16 bits =&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;312 bits, and when multiplied by 3 (because this is the 3rd power), would be in the vicinity of 936 bits. This is a lot less than the bit length of \(n\), which is 4096 bits for the second challenge. What this means is that we can simply take the cubic root of \(m^3 \mod n\), yielding \(m\) and hence the flag: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CBCTF{d65718235c137a94264f16d3a51fefa1}&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;common-modulus-3-1&quot;&gt;Common Modulus 3&lt;/h3&gt;
&lt;p&gt;In this variation, the hardest of the three, not only is the greatest common divisor of \(e_1\) and \(e_2\) 17, but the flag is also right-padded with null bytes (bytes with the value 0) until it’s in the vicinity of ~8192 bits (a few bits less) before being encrypted. To start, we utilize the same method to get \(m_p^{17} \mod n\), where \(m_p\) is the padded flag. But we need to retrieve \(m\), not \(m_p^{17}\). How do we do that? Well, there are two things to keep in mind:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The modulus is quite large at 8192, meaning that the - unpadded - message must be at least 482 bits (8192 / 17 bits) so that the 17th power becomes sort of a problem. Therefore, knowing the length of the message is 312 bits because it follows the same format as the other challenges in this CTF, we can actually calculate the 17th root of \(m^{17} \mod n\) and successfully recover the flag IF there were no padding.&lt;/li&gt;
  &lt;li&gt;The padding is deterministic and linear. It is the equivalent of multiplying the flag with a very large power of 2, since the bitstring representation would be \(XXXXX…0000000000000…0\) where \(XXXXX\) is the binary representation of the coveted flag.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using these two facts stated above, we can &lt;em&gt;unpad&lt;/em&gt; the message by first calculating the &lt;strong&gt;padding coefficient&lt;/strong&gt;&lt;sup id=&quot;fnref:pad_coeff&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:pad_coeff&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; which is \(2^B \mod n\) where \(B = \) the number of bits needed to pad the message to be close to 8192 bits, which is \(8192 - 312 = ~7880\) bits. Afterwards, we get the modular inverse for the previously calculated padding coefficient, yielding \(2^{-B} \mod n\). We then calculate \(2^{-B \cdot 17} \mod n\) by raising the previous value to the power of 17. Now, if we multiply that with \(m_p^{17}\) what we get is&lt;/p&gt;

\[\begin{align}
&amp;amp; m_p^{17} \cdot 2^{-B \cdot 17} &amp;amp; \mod n\\\\
&amp;amp; = (m \cdot 2^{B})^{17} \cdot 2^{-B \cdot 17} &amp;amp; \mod n\\\\
&amp;amp; = (m^{17} \cdot 2^{B \cdot 17}) \cdot 2^{-B \cdot 17} &amp;amp; \mod n\\\\
&amp;amp; = m^{17} \cdot (2^{B \cdot 17} \cdot 2^{-B \cdot 17} &amp;amp; \mod n\\\\
&amp;amp; = m^{17} \cdot (2^{(B \cdot 17) + (-B \cdot 17)}) &amp;amp; \mod n\\\\
&amp;amp; = m^{17} \cdot 1 &amp;amp; \mod n
\end{align}\]

&lt;p&gt;So we’ve successfully calculated \(m^{17} \mod n\) and, as previously mentioned, we can also calculate the 17th root to recover \(m\) itself.&lt;/p&gt;

&lt;p&gt;But wait, we haven’t actually decided what \(B\) is! Well, in the worst case, we’re going to be a few bits off from the real value, so we can simply write a program that does all the steps described above, retrieves a candidate \(m\) and checks that it starts with the expected &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CBCTF&lt;/code&gt;. We can use a conservative starting value \(B = 7868\), and within only 4 attempts, we recover the flag: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CBCTF{b5c96e00cb90d11ec6eccdc58ef0272d}&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:pad_coeff&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;em&gt;Probably&lt;/em&gt; not a real term. It simply seemed apt. &lt;a href=&quot;#fnref:pad_coeff&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</content><author><name>kmhn</name></author><category term="writeup" /><category term="ctf" /><category term="codeblue2017" /><summary type="html">There are 3 challenges in this series, all of which are based on the same problem with varying conditions. Therefore, we’ll go through them in increasing order of difficulty and build solutions incrementally.</summary></entry><entry><title type="html">Building on blockchains</title><link href="https://rootfs.eu/building-on-blockchains/" rel="alternate" type="text/html" title="Building on blockchains" /><published>2017-01-31T23:00:07+00:00</published><updated>2017-01-31T23:00:07+00:00</updated><id>https://rootfs.eu/building-on-blockchains</id><content type="html" xml:base="https://rootfs.eu/building-on-blockchains/">&lt;p&gt;Last semester I participated in a research seminar on applications of blockchain technology at Aalto University. The aim of this seminar was to see which fields could benefit from the merits of blockchains, as well as gain some insight in how to design systems based on blockchain technologies. To facilitate this we teamed up in groups of two to work on selected topics, and I worked with Taneli (a colleague student at Aalto) to investigate whether it is feasible to create trackable supply chains using blockchain technologies.&lt;/p&gt;

&lt;p&gt;Throughout the project I came to realize that a lot of pillars on which the average blockchain project relies turn out to be quite shaky when you inspect them up close, especially in the scalability department. This has left me wondering how there can be so many blockchain powered projects out there with huge investments backing them, and whether people actually realize where the limitations lie with current-day blockchain tech.
Don’t get me wrong here, blockchains definitely hold a lot of potential, but adding some blockchain fairy dust to your project does not automatically dissolve all your problems and elevate you to some sort of Elysium. From what I’ve experienced so far, it is more likely to add as many problems as it solves and some of those are really challenging to overcome.&lt;/p&gt;

&lt;p&gt;In this post I will try to shed some light on problems we identified during our research. These problems are not really something that affect every distributed application or every transaction out there but rather something related to blockchain technologies in general. It’s certainly not required to take these things into account for every application, but should you want to create the first blockchain Google then some careful consideration is definitely recommended in these areas.&lt;/p&gt;

&lt;h2 id=&quot;consensus&quot;&gt;Consensus&lt;/h2&gt;
&lt;p&gt;Every blockchain system out there has implemented some distributed consensus protocol, in order for nodes to be able to agree on which block is the ‘true’ successor to the current end of the chain. Bitcoin uses a consensus model which relies on some proof-of-work. While this is currently regarded as the ‘safe pick’ for consensus protocols (it helped make Bitcoin big after all!), it also wastes a lot of resources in achieving consensus. There are some alternatives out there, such as proof-of-stake where nodes prove that they have an interest in creating correct blocks before they start mining them. To my knowledge there is currently no system in use where proof-of-stake is used without at least a second consensus model supporting it, mainly because there are some caveats with the proof-of-stake approach that nobody has solved in an elegant way yet.
In my opinion, the most interesting alternative to proof-of-work so far is the &lt;a href=&quot;https://www.stellar.org/papers/stellar-consensus-protocol.pdf&quot;&gt;Stellar&lt;/a&gt; federated byzantine agreement protocol or SCP (Stellar Consensus Protocol) for short. This protocol allows nodes to choose which other nodes they trust, which -along with a healthy dose of black magic- enables federated consensus. It is especially interesting in that it (maybe?) creates the possibility of having different slightly overlapping branches of blockchains that grow in parallel, where nodes decide which branch they’re following based on what other nodes they trust.
&lt;em&gt;Note: I’m not 100% sure at this moment whether this is actually possible, as I have not yet reached a full understanding of the inner workings of the SCP.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;scalability&quot;&gt;Scalability&lt;/h2&gt;
&lt;p&gt;I do not think it is feasible right now to create a scalable (to the size of say, Visa, Netflix, and so forth) system that relies upon blockchains for its core functionality. The first hurdle here is performance: if you want to create a system that can handle a large amount of transactions per second (tps), blockchains are not your best bet. Bitcoin itself is limited to 7 tps. While this is the result of a &lt;a href=&quot;https://en.bitcoin.it/wiki/Block_size_limit_controversy&quot;&gt;manually imposed limit&lt;/a&gt; on the Bitcoin protocol, it is not clear to anyone how changing this limit would affect Bitcoin as a whole. For example, one consequence is that blocks will take longer to propagate over the network, affecting the speed at which they are verified by nodes. 
Other blockchain systems such as Ethereum are not (to my understanding) affected by this problem to the same degree, but unfortunately there are other problems that hamper scalability. In Ethereum’s case, I think the biggest limiting factor is the size of the blockchain: Ethereum allows you to store data structures into the blockchain. Now imagine there being two gazillion contracts, each storing some data into the chain with every invocation. Soon enough some nodes will not be  able to store full copies of the chain, leading to other interesting problems (See  the &lt;a href=&quot;https://github.com/ethereum/wiki/wiki/White-Paper#scalability&quot;&gt;Ethereum white paper&lt;/a&gt;). Increasing the price for storing data into the chain might counter this, but at the same time it increases the cost needed to operate on the Ethereum chain, which is not exactly something that stimulates adoption. In my eyes that is more of a mitigation technique.
Every other blockchain based project I looked at has similar scalability issues.
One interesting mention is &lt;a href=&quot;https://www.bigchaindb.com/&quot;&gt;BigChainDB&lt;/a&gt; which aims to create a distributed database system where there is no central authority involved. BigchainDB builds upon an existing distributed database and then adds blocks and a consensus mechanism on top. The problem with this project (apart from the fact that all nodes actually participating in a DB need to have quite some resources at their disposal) is that for it to achieve its advertised sub-second performance, it assumes that all nodes are in the same data-center. That’s not really practical for a big open system like Ethereum, and in my eyes seems fit for only a limited number of applications. Nonetheless, it is an interesting project.
The problem of scalability is widely acknowledged as an important one, and many extremely smart people are working on solutions, but as of yet I do not think it has been solved to the degree necessary for large scale blockchain applications to be feasible.&lt;/p&gt;

&lt;h2 id=&quot;long-term-storage&quot;&gt;Long-term Storage&lt;/h2&gt;
&lt;p&gt;Long-term storage? Isn’t that related to scalability? Well, yes. But there are some extra things to take into account here. If the underlying blockchain system has some mechanism in place where nodes are not required to store full copies of the blockchain (so called ‘light nodes’), then this might mean that data stored in the blockchain is only served by a limited number of nodes, or in an extreme case not even at all (although that would mean not a single node on earth maintaining a full copy of the chain, quite far-fetched, I know)! When there are only a few nodes serving specific data that is stored in the chain, this opens up new possibilities for attacking the blockchain system by e.g. constantly harassing those nodes with some form of a DOS attack, or by having them hold this unique data hostage in some other way. I think there is an opportunity here to build a blockchain system on top of a content addressed network (e.g. &lt;a href=&quot;https://ipfs.io&quot;&gt;IPFS&lt;/a&gt;), which would reduce the likelihood of this situation ever happening by quite a bit, as well as possily increasing the performance since popular data is likely to be stored somewhere geographically close to your location. It could also possibly lead to a cost decrease for storing data in systems like Ethereum.&lt;/p&gt;

&lt;p&gt;There are still some topics missing on this list, and I might elaborate on those in a future post, but I think this is enough  blockchain skepticism for today. The point I’ve been trying to get across with this post is that I don’t see blockchain-based applications becoming widespread before these issues are solved to a satisfactory degree, and that there is still a good ways to go before this field can be considered mature.&lt;/p&gt;</content><author><name>mono</name></author><category term="blockchain" /><category term="thoughts" /><summary type="html">Last semester I participated in a research seminar on applications of blockchain technology at Aalto University. The aim of this seminar was to see which fields could benefit from the merits of blockchains, as well as gain some insight in how to design systems based on blockchain technologies. To facilitate this we teamed up in groups of two to work on selected topics, and I worked with Taneli (a colleague student at Aalto) to investigate whether it is feasible to create trackable supply chains using blockchain technologies.</summary></entry><entry><title type="html">Lessons learned from a failed hackathon</title><link href="https://rootfs.eu/lessons-learned-from-a-failed-hackathon/" rel="alternate" type="text/html" title="Lessons learned from a failed hackathon" /><published>2016-12-01T11:56:33+00:00</published><updated>2016-12-01T11:56:33+00:00</updated><id>https://rootfs.eu/lessons-learned-from-a-failed-hackathon</id><content type="html" xml:base="https://rootfs.eu/lessons-learned-from-a-failed-hackathon/">&lt;p&gt;Last weekend I attended &lt;a href=&quot;https://hackjunction.com&quot;&gt;Junction&lt;/a&gt; together with &lt;a href=&quot;https://rootfs.eu/author/kmhn/&quot;&gt;Khaled&lt;/a&gt;. It was tons of fun and I had a great time, but we ended up with absolutely nothing to show for it. Except for a neat shirt of course. 
Normally we’re constantly bouncing the silliest ideas off each other, so how come we produced &lt;em&gt;nada&lt;/em&gt; for this particular hackathon? Below are the reasons I managed to come up with.&lt;/p&gt;

&lt;p style=&quot;text-align:center&quot;&gt;&lt;img src=&quot;/content/images/2016/11/muki_pan_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:center&quot;&gt;&lt;em&gt;Most productive moment of the weekend: A picture of my dog on a coffee cup with e-ink display&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;1-winning-criteria-are-not-project-requirements&quot;&gt;1. Winning criteria are not project requirements&lt;/h2&gt;
&lt;p&gt;Although we initially had some ideas on what we wanted to create before the event started, we disregarded all of those just before it started as we felt that none were very interesting from a marketability perspective, which is what most of the companies hosting the various tracks were after. This was our first mistake. We completely boxed ourselves in by having the idea that our projects would have to be somehow &lt;em&gt;relevant&lt;/em&gt; to the track’s host company. Who cares about &lt;em&gt;their&lt;/em&gt; incentives? We’re here to have fun with their technology, not to solve their problems.
 Next time we won’t treat the criteria as if they’re the &lt;em&gt;M&lt;/em&gt; in &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/MoSCoW_method&quot;&gt;MoSCoW&lt;/a&gt;&lt;/em&gt;. 
They’re more like &lt;em&gt;should haves&lt;/em&gt; for sure :)&lt;/p&gt;

&lt;h2 id=&quot;2-just-pick-a-damn-track&quot;&gt;2. Just pick a damn track&lt;/h2&gt;
&lt;p&gt;While hackathons I attended in the past all had one (maybe two) tracks, Junction had more tracks than I could count on my fingers. Of course this is neat, but at the same time it caused us to jump from track to track with our ideas, never arriving to the point where we actually started doing something. Usually, when we’re completely out of ideas for a track, there is no option but to do our own thing (ignoring the challenge altogether). This usually leads to fun results. 
At Junction however, every time we found that we couldn’t come up with something fun for the track we were currently looking at, we decided to go for a different track. This happened 10 times or something. Not productive!
 Next time I see this happening, I’m just going to pick a track and stick with it, possibly incorporating other tracks into the project as we go.&lt;/p&gt;

&lt;h2 id=&quot;3-a-poc-is-all-you-need&quot;&gt;3. A PoC is all you need&lt;/h2&gt;
&lt;p&gt;Yeah. This is so obvious it shouldn’t even be listed here right? Well, it turns out we were actually focussing on creating working projects because.. I don’t know honestly. 
Maybe because we are used to jumping into the design of systems that are actually functional right away. And, at previous hackathons we did create functional pieces of soft/hardware. We managed to forget about only needing a PoC, and that having the underlying program logic work flawlessly is merely a bonus.&lt;/p&gt;

&lt;p&gt;So, there you have it. There are probably a whole bunch of other reasons I didn’t manage to come up with, but at least I’ll be keeping these in mind for Junction 2017.
&lt;em&gt;Viva la reflection!&lt;/em&gt;&lt;/p&gt;</content><author><name>mono</name></author><category term="hackathon" /><category term="junction" /><summary type="html">Last weekend I attended Junction together with Khaled. It was tons of fun and I had a great time, but we ended up with absolutely nothing to show for it. Except for a neat shirt of course. Normally we’re constantly bouncing the silliest ideas off each other, so how come we produced nada for this particular hackathon? Below are the reasons I managed to come up with.</summary></entry><entry><title type="html">ALICTF 2016 - showmethemoney</title><link href="https://rootfs.eu/alictf-2016-showmethemoney-2/" rel="alternate" type="text/html" title="ALICTF 2016 - showmethemoney" /><published>2016-06-07T11:07:05+00:00</published><updated>2016-06-07T11:07:05+00:00</updated><id>https://rootfs.eu/alictf-2016-showmethemoney-2</id><content type="html" xml:base="https://rootfs.eu/alictf-2016-showmethemoney-2/">&lt;p&gt;Unfortunately I didn’t have much time to play this CTF, but this challenge caught my eyes and I decided to look at it at the last few hours of the tournament. I didn’t manage to do it in time for the CTF due to the lack of time and some bone-headed mistake, but I went on with it anyways the day after.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; All the files related to this challenge can be found &lt;a href=&quot;https://github.com/khalednassar/ctf_writeups/tree/master/alictf2016/showmethemoney&quot;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;reconnaissance-and-failures&quot;&gt;Reconnaissance (and failures)&lt;/h2&gt;
&lt;p&gt;So we were given &lt;a href=&quot;https://github.com/khalednassar/ctf_writeups/blob/master/alictf2016/showmethemoney/showmethemoney_481bc5a72f7872a27e38a464ae97e935.zip&quot;&gt;showmethemoney.zip&lt;/a&gt; with the description:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;test:showmethemoney&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not very helpful, but we check out the contents and we find 3 files&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flag.txt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readme.txt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;showmethemoney.exe&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readme.txt&lt;/code&gt; simply stated&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;Show me the money to decrypt it. &lt;br /&gt;
ID: 09ce12e1-b775-4bda-af37-8abd886478ee &lt;br /&gt;
Filename: flag.txt&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not very informative yet, but seems highly likely that we’re looking at some hypothetical ransomware situation. We need to dig deeper.&lt;/p&gt;

&lt;p&gt;A quick look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;showmethemoney.exe&lt;/code&gt; reveals that it is a .NET executable. Neat. So I fired up .NET Reflector to check it out. The application is relatively simple, just a couple of classes.&lt;/p&gt;

&lt;p style=&quot;text-align:center&quot;&gt;&lt;img src=&quot;/content/images/2016/06/appinternals.png&quot; alt=&quot;appinternals&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AesCryptoHelper&lt;/code&gt; is a rather peculiar wrapper class around .NET’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AESCryptoServiceProvider&lt;/code&gt;, and it seems like a red herring because it’s never referenced in the code that actually gets run. Let’s dig a little deeper then.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/content/images/2016/06/programcs.png&quot; alt=&quot;programcs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are some interesting things going on here, but for a quick rundown of how things happen starting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;An &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID&lt;/code&gt; is generated using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Guid.NewGuid()&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt; is generated using some combination of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Random&lt;/code&gt; and another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Guid&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RijndaelManaged&lt;/code&gt; (AES in this case) is used to encrypt the contents of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flag.txt&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt; and overwrite it with the base64 encoding of the ciphertext. Note that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ECB&lt;/code&gt; mode is used and the key size is 256 bits. I considered this more evidence that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AesCryptoHelper&lt;/code&gt; class is a red herring since it uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CFB&lt;/code&gt; mode, but I could still be mistaken at this point.&lt;/li&gt;
  &lt;li&gt;Both the generated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt; are sent to a process listening on port 9999 on some server. The format of the message is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi&amp;lt;ID&amp;gt;\0&amp;lt;key&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With this in mind, I started looking at how could I possibly replicate the state of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Random&lt;/code&gt; PRNG to hopefully manage to recover the key. I frantically searched for any bugs or information leaks from GUIDs only to learn that this specific GUID implementation is a UUID version 4, as indicated by the character &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4&lt;/code&gt; at the beginning of the third part in the given ID &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;09ce12e1-b775-4bda-af37-8abd886478ee&lt;/code&gt;. Those do not leak information (allegedly) like previous versions of UUID and are well, for all purposes of this challenge, a dead end. And this would be the reason why I couldn’t finish this challenge during the CTF as I went on looking down this - incorrect - path wasting a good hour and a half before calling it quits for the day.&lt;/p&gt;

&lt;p&gt;Fast forward a day later, I decided to list the information that I currently posses:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;How the data was encrypted.&lt;/li&gt;
  &lt;li&gt;Which server the data was sent to.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After listing the 2nd item, I already knew what I missed. So I fired up nmap and decided to take a look at this server, which luckily was and is still running at the time of writing of this post. There were 3 open ports: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;80 (http)&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;22 (ssh)&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9999&lt;/code&gt;.
We know that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9999&lt;/code&gt; is the port that the ransomware sends the keys to, but why is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;80&lt;/code&gt; open?&lt;/p&gt;

&lt;p style=&quot;text-align:center&quot;&gt;&lt;img src=&quot;/content/images/2016/06/greetings.png&quot; alt=&quot;greetings&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Oh look, what is this? &lt;a href=&quot;https://github.com/khalednassar/ctf_writeups/blob/master/alictf2016/showmethemoney/vvss&quot;&gt;vvss&lt;/a&gt;?
It turns out to be an ELF. IDA is fired up and after some quick messing around, we learn that this application uses 2 sqlite databases, namely &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keys.db&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keysbak.db&lt;/code&gt;, the latter seemingly a backup of the former. It also accepts input of the forms:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi&amp;lt;string1&amp;gt;\0&amp;lt;string2&amp;gt;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pz&amp;lt;string1&amp;gt;\0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;py\0&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(1)&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(2)&lt;/code&gt;, it forms a query that it executes on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keys.db&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(1)&lt;/code&gt; adds a new row to the table &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keys&lt;/code&gt; with columns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qid=string1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plain=string2&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;len=length(plain)&lt;/code&gt;. This is clearly the routine used to store keys and their respective IDs that the ransomware sends. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(2)&lt;/code&gt; reads the row with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qid=string1&lt;/code&gt; and deletes it from the table afterwards. It’s very likely that neither of these are of any help given what they do.&lt;/p&gt;

&lt;p&gt;However, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(3)&lt;/code&gt; runs a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;select * from keys;&lt;/code&gt; query on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keysbak.db&lt;/code&gt;. Yep, there it is.&lt;/p&gt;

&lt;h2 id=&quot;attack-vector-very-very-secure-system&quot;&gt;Attack vector (Very Very Secure System)&lt;/h2&gt;
&lt;p&gt;So now that we know what we need to do, it’s very easy to write a &lt;a href=&quot;https://github.com/khalednassar/ctf_writeups/blob/master/alictf2016/showmethemoney/attack.py&quot;&gt;python script&lt;/a&gt; that will send our query to the process. This is the output from the script:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;python&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Sent&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Received&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Received&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;87&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PLAIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;58897&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d583d888978b62469889d584472&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;QID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;09&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ce12e1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b775&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bda&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;af37&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abd886478ee&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;LEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The returned &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QID&lt;/code&gt; matches the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID&lt;/code&gt; in the given readme! Hence, our key is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;58897d583d888978b62469889d584472&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It’s just as simple then to write &lt;a href=&quot;https://github.com/khalednassar/ctf_writeups/blob/master/alictf2016/showmethemoney/decrypt.py&quot;&gt;another script&lt;/a&gt; to decrypt the contents of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flag.txt&lt;/code&gt;, and indeed we get the flag we’re looking for: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alictf{Black_sh33p_w411}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Moral of this writeup: do your reconnaissance well before going down rabbit holes.&lt;/p&gt;</content><author><name>kmhn</name></author><category term="writeup" /><category term="ctf" /><category term="alictf2016" /><summary type="html">Unfortunately I didn’t have much time to play this CTF, but this challenge caught my eyes and I decided to look at it at the last few hours of the tournament. I didn’t manage to do it in time for the CTF due to the lack of time and some bone-headed mistake, but I went on with it anyways the day after.</summary></entry></feed>