Problem Description

Deep on the web, I discovered a secret key validation. It appeared to be from the future, and it only had one sentence: “Risk speed for security”. Something seems fishy, you should try to break the key and find the secret inside!

future_fun

The binary

Welp, this binary was movfuscated:

08048794 <check_element>:
 8048794:	a1 88 d2 3f 08       	mov    eax,ds:0x83fd288
 8048799:	ba 94 87 04 88       	mov    edx,0x88048794
 804879e:	a3 10 d1 1f 08       	mov    ds:0x81fd110,eax
 80487a3:	89 15 14 d1 1f 08    	mov    DWORD PTR ds:0x81fd114,edx
 80487a9:	b8 00 00 00 00       	mov    eax,0x0
 80487ae:	b9 00 00 00 00       	mov    ecx,0x0
 80487b3:	ba 00 00 00 00       	mov    edx,0x0
 80487b8:	a0 10 d1 1f 08       	mov    al,ds:0x81fd110
 80487bd:	8b 0c 85 20 77 05 08 	mov    ecx,DWORD PTR [eax*4+0x8057720]
 80487c4:	8a 15 14 d1 1f 08    	mov    dl,BYTE PTR ds:0x81fd114
 80487ca:	8a 14 11             	mov    dl,BYTE PTR [ecx+edx*1]
 80487cd:	89 15 00 d1 1f 08    	mov    DWORD PTR ds:0x81fd100,edx
 80487d3:	a0 11 d1 1f 08       	mov    al,ds:0x81fd111
 80487d8:	8b 0c 85 20 77 05 08 	mov    ecx,DWORD PTR [eax*4+0x8057720]
 80487df:	8a 15 15 d1 1f 08    	mov    dl,BYTE PTR ds:0x81fd115
 80487e5:	8a 14 11             	mov    dl,BYTE PTR [ecx+edx*1]
 80487e8:	89 15 04 d1 1f 08    	mov    DWORD PTR ds:0x81fd104,edx
 80487ee:	a0 12 d1 1f 08       	mov    al,ds:0x81fd112
 80487f3:	8b 0c 85 20 77 05 08 	mov    ecx,DWORD PTR [eax*4+0x8057720]
 80487fa:	8a 15 16 d1 1f 08    	mov    dl,BYTE PTR ds:0x81fd116

Initially we tried using demovfuscator but all this really did was turn a few movs into leas but nothing too useful.

Instead, we used demovfuscator’s -g option to generate the control flow graph of the program which looked like this:

movfuscator control flow graph

Since the program was exiting on a wrong input, I decided to experiment by adding a breakpoint at the first branch and take a look around in gdb. This breakpoint was being hit thousands of times so I used ignore <bp> 1000000 to quickly check how many times which resulted in a really interesting output:

flag{  
[Inferior 1 (process 24054) exited with code 01]
pwndbg> i breakpoints
Num     Type           Disp Enb Address    What
2       breakpoint     keep y   0x0805262f <main+8901>
    breakpoint already hit 6018 times

fla__
[Inferior 1 (process 24082) exited with code 01]
pwndbg> i breakpoint
Num     Type           Disp Enb Address    What
3       breakpoint     keep y   0x0805262f <main+8901>
    breakpoint already hit 4012 times

Notice that when correct input is provided, the breakpoint is hit more often. Now that we have an indicator to know that one character of input is correct, we can go ahead and exploit this to recover the flag.

(Note: handle SIGSEGV nostop noprint pass and handle SIGILL nostop noprint pass are required to debug in gdb since movfuscator uses signal handlers on SIGSEGV and SIGILL for function calls and loops)

Exploiting the side channel

We whipped up a quick gdb script to automate the process of monitoring the breakpoints:

import gdb
import string

valid_chars = string.printable

gdb.execute("file future_fun")
gdb.execute("handle SIGSEGV nostop noprint pass")
gdb.execute("handle SIGILL nostop noprint pass")

class MyBreakpoint(gdb.Breakpoint):
    def stop(self):
        return False

bp = MyBreakpoint("*0x805262f")
bp.ignore_count = 90000000

flag = ""
while not flag.endswith("}"):
    for char in valid_chars:
        bp.hit_count = 0

        newflag = flag + char

        with open("flagfile", "w") as f:
            f.write(newflag + "%")
            f.write('\n')

        exec_command = 'r < flagfile > /dev/null'
        gdb.write("Trying: " + newflag + "\n")
        gdb.execute(exec_command)

        if bp.hit_count > (len(newflag) + 1) * 1000:
            gdb.write("[!] Found character: " + newflag + "\n")
            flag = newflag
            break
        else:
            gdb.write("Hits: {}\n".format(bp.hit_count))
            pass

This script tries each printable character and if we hit the breakpoint a thousand times more than the last, we know it was correct.

After running for a few minutes, the flag was recovered successfully.

Recovery in progress

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?

traffic.png

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))
hex(int(client_secret))
# 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)
hex(int(premaster_secret))
# 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

A lesson on data structures, networking protocols, data sanitization and disclosure

Around 2 years ago, I was enthusiastically working on Spigot and Bukkit along with a couple of fairly popular plugins. During my poking around within the networking internals of Minecraft, I came across a fairly substantial problem that allowed anyone to send certain malformed packets and crash a server by running it out of memory.

Following the defacto standard procedure, I responsibly and privately disclosed the problem to Mojang on 10th July, 2013. That’s nearly 2 years ago. I asked for updates in one month intervals over the course of 3 months and was ignored or given highly unsatisfactory responses. I kept my hopes up that the problem would be patched and checked the source code on new releases whenever I could.

The version of the game when the vulnerability was reported was 1.6.2, the game is now on version 1.8.3. That’s right, 2 major versions and dozens of minor versions and a critical vulnerability that allows you to crash any server, and starve the actual machines of CPU and memory was allowed to exist.

The technical details

The minecraft protocol enables the exchange of information about what an inventory slot contains. This allows you to, for example, get the items in your hotbar when you log in. Items in minecraft also contain a feature that allows them to store arbitary metadata (used for enhancements, books etc). This metadata is stored in a format known as NBT. The NBT format is essentially like JSON but in binary form. This allows it to store complex data structures with nesting and the like.

For example, the NBT metadata (known as a tag) for a book might look something like this

tag: {
    author: "ammar2",
    title: "Kitteh",
    pages: ["Kitties are cute", "I like kitties"]
}

The vulnerability stems from the fact that the client is allowed to send the server information about certain slots. This, coupled with the NBT format’s nesting allows us to craft a packet that is incredibly complex for the server to deserialize but trivial for us to generate.

In my case, I chose to create lists within lists, down to five levels. This is a json representation of what it looks like.

rekt: {
    list: [
        list: [
            list: [
                list: [
                    list: [
                        list: [
                        ]
                        list: [
                        ]
                        list: [
                        ]
                        list: [
                        ]
                        ...
                    ]
                    ...
                ]
                ...
            ]
            ...
        ]
        ...
    ]
    ...
}

The root of the object, rekt, contains 300 lists. Each list has a list with 10 sublists, and each of those sublists has 10 of their own, up until 5 levels of recursion. That’s a total of 10^5 * 300 = 30,000,000 lists. And this isn’t even the theoretical maximum for this attack. Just the nbt data for this payload is 26.6 megabytes. But luckily minecraft implements a way to compress large packets, lucky us! zlib shrinks down our evil data to a mere 39 kilobytes.

Note: in previous versions of minecraft, there was no protocol wide compression for big packets. Previously, NBT was sent compressed with gzip and prefixed with a signed short of its length, which reduced our maximum payload size to 2^15 - 1. Now that the length is a varint capable of storing integers up to 2^28, our potential for attack has increased significantly. (for the more technically minded people, we fill the list up with TAG_ENDs, which aren’t accounted for by the accumulator Mojang attempted to implement to fix this)

When the server will decompress our data, it’ll have 27 megs in a buffer somewhere in memory, but that isn’t the bit that’ll kill it. When it attempts to parse it into NBT, it’ll create java representations of the objects meaning suddenly, the sever is having to create several million java objects including ArrayLists. This runs the server out of memory and causes tremendous cpu load.

This vulnerability exists on almost all previous and current minecraft versions as of 1.8.3, the packets used as attack vectors are the 0x08: Block Placement Packet and 0x10: Creative Inventory Action.

The fix for this vulnerability isn’t exactly that hard, the client should never really send a data structure as complex as NBT of arbitrary size and if it must, some form of recursion and size limits should be implemented. These were the fixes that I recommended to Mojang 2 years ago.

Proof of concept

A proof of concept of this exploit can be seen here on my Github repo. The code to generate the posioned nbt can be seen in start.py. The code has been tested under python 2.7, once you have connected to a server simply enter exploit in the command line and the packet will be sent to the server.

Disclosure

I thought a lot before writing this post, on the one hand I don’t want to expose thousands of servers to a major vulnerability, yet on the other hand Mojang has failed to act upon it. Mojang is no longer a small indie company making a little indie game, their software is used by thousands of servers, hundreds of thousands of people play on servers running their software at any given time. They have a responsibility to fix and properly work out problems like this. In addition, it should be noted that giving condescending responses to white hats who are responsibly disclosing vulnerabilities and trying to improve a product they enjoy is a sure fire way to get developers dis-interested the next time they come across a bug like this.

Timeline

  1. 28th July, 2013: First contact with mojang employee about the issue, vulnerability disclosed and proof of concept provided.

  2. 19th August, 2013: Second time asking about fix, response given that its being worked on.

  3. 24th September, 2013: Third contact with employee, told that the problem has been delegated.

  4. 25th October, 2013: Fourth time I attempted to contact employee, ignored.

  5. 27th October, 2013: Another attempt to contact, ignored again. (at this point, I patiently waited for a fix)

In retrospect, yes, I should have given them a final warning sometime recently before this but I just expected to be shot down again

Update: With the release of this full disclosure I have actually made contact with mojang and they are working to fix the issue. Apparently the initial fix they tried failed which indicates a lack of proper testing.

Update 2: The exact problem that caused this bug to go unpatched has been identified. Mojang attempted to implement a fix for this problem, however they did not test their fix against the proof of concept I provided, which still crashed the server perfectly fine. This, in combination with ignoring me when I asked for status updates twice led me to believe that Mojang had attempted no fix. In retrospect, a final warning before this full disclosure more recently was propbably in order. A combination of mis-communication and lack of testing led to this situation today, hopefully it can be a good learning experience.

Update 3: This problem has been patched as of minecraft version 1.8.4

https://mojang.com/2015/04/minecraft-1-8-4-security-release/

I’m happy to see that multiple other security issues have also been fixed. Once again, I feel better communication would have easily alleviated this problem. Keeping me in the loop and not ignoring me, in addition to proper testing would have easily led to this exploit being fixed long ago.

Edit: In regards to the statements that I never filed a report on their bug tracker, I’d just like to point out that nobody pointed me towards the tracker when I reported the issue, I wasn’t asked to make a ticket or told that I could follow the progress of the report on x-ticket.

Custom API being used by a javascript web page, android and php graphing program. Apologies for the slight out of sync-ness, the web page polls temperature faster causing the one on the phone and page to be different.

I was always really interested in making new projects for my arduino, the first of which was an LED music visualizer. The problem here was that arduinos aren't really popular in Pakistan, I had to get my current duemillenove shipped in from China thus getting an internet shield would be very difficult. One fine day I started thinking and said to myself, hey I nave a dedicated home server why not just hook up the arduino to that and write a program on the server to read that data through serial and use it somehow. Initially it was designed just to be able to read the current temperature, graphing was added in later. Here is how it works: The first part of the process is an arduino which has a  DS18B20 Temperature Sensor attatched to it. Using serial communication, it sends out temperature readings to my dedicated home server. The next part is a python script running in an infinite loop, it reads the values from the serial port and then proceeds to put them in a MySQL table, this occurs once every 2 minutes.
import MySQLdb
import time
import serial
import sys
 
conn = MySQLdb.connect (host = "localhost",
 user = "derp",
 passwd = "murp",
 db = "tempdata")

while True:
 timestamp = int(time.time())
 ser = serial.Serial('/dev/ttyUSB0');
 ser.open
 linebeep = ser.readline()
 line = ser.readline()
 cursor = conn.cursor()
 cursor.execute("""INSERT INTO Data(Temperature, Time)
 VALUES(%s, %s)""", (line, timestamp,))
 ser.close
 print timestamp
 print line
 time.sleep(120)
The final stage is a php script using jpgraph to plot the data from the mysql table.
<?php
require_once ('jpgraph/src/jpgraph.php');
require_once ('jpgraph/src/jpgraph_line.php');
 
$link = mysql_connect('localhost', 'derp', 'hurp');
if (!$link) {
    die('Could not connect: ' . mysql_error());
}
mysql_select_db("tempdata", $link);
$query = mysql_query("SELECT Temperature from Data");
$i = 0;
while($row = mysql_fetch_array($query)){
    $holder = (float) $row[0];
    $temparray[$i] = $holder;
    $i++;
}
 
$query2 = mysql_query("SELECT Time from Data");
$p = 0;
 
//This part of the script is used to get the dates at the bottom
while($row = mysql_fetch_array($query2)){
    $rowint = (int) $row[0];
    $kitteh = date("G:i",$rowint);
    if($kitteh == "0:01" || $kitteh == "0:02" || $kitteh == "0:00" || $kitteh == "0:03"){
        $datesarray[$p]= date("j M", $rowint);
    }
    else{
        $datesarray[$p] = "";
    }
    $p++;
}
$graph = new Graph(1300,700);
$graph->SetScale("textlin");
 
$theme_class=new UniversalTheme;
 
$graph->SetTheme($theme_class);
$graph->title->Set('Temperature');
$graph->SetBox(false);
$graph->img->SetAntiAliasing();
 
$graph->yaxis->HideZeroLabel();
$graph->yaxis->HideLine(false);
$graph->yaxis->HideTicks(false,false);
 
$graph->xgrid->Show();
$graph->xgrid->SetLineStyle("solid");
$graph->xaxis->SetTickLabels($datesarray);
$graph->xgrid->SetColor('#E3E3E3');
 
// Create the first line
$p1 = new LinePlot($temparray);
//$p1 = new LinePlot($newx);
$graph->Add($p1);
$p1->SetColor("#6495ED");
$p1->SetLegend('Temperature');
 
$graph->legend->SetFrameWeight(1);
 
// Output line
$graph->Stroke();
 
?>