SHA2017 CTF - WannaFly

Event Points Solves Categories Task ID
SHA2017 CTF 100 187 Forensic 4418

Challenge Description

My daughter Kimberly her computer got hacked. Now she lost all her favorite images. Can you please help me recover those images?

wannafly.tgz 7509faed92d67a242068de6605659ca1

Overview

The provided archive file contains an image file of about 100MB. We use 7z to extract the image file: 7z x kimberly.img. We get a quick overview of the extracted files with the ls -laR command. The pictures directory contains 17 PNG images of ponies, which are encrypted by the “WannaFly” ransomware, as the embedded disclaimer tells us:

PNG encrypted by the WannaFly ransomware

We quickly check whether the PNG files have any unusual business going on by using the exiftool and zsteg utilities. Indeed, each PNG file seems to have additional base64 encoded data appended to the normal image data:

$ zsteg Pictures/78d14f37ae413511b119776c2294c414.png 
[?] 812169 bytes of extra data after image end (IEND), offset = 0x37a3d

Looks like the data of the original image was encrypted and appended to the watermarked version of it. Now we just need the key and the correct encryption algorithm to recover the images! We look a little further and notice 2 interesting files in the home directory: ... and .bash_history. Let’s check out the bash history first:

$ cat .bash_history 
unset HISTFIL
ls -la
pwd
chmod +x ...
./... Hb8jnSKzaNQr5f7p
ls -Rla

So, somebody tried to not leave any traces but failed, classic ransomware author! The unset HISTFILE command turns off the automatic saving of the bash history for that session, however the attacker misspelled the command so that the bash history still got saved. Apparently the ... script was made executable and called with the parameter Hb8jnSKzaNQr5f7p. This could very well be our key as the script was probably used to encrypt the image files and needed a key to do so. All we have to do now is to understand how the script encrypted the images and revert the process.

Decrypt All The Images!

We analyze the Python script and figure out the steps that are performed to encrypt the images:

We make use of the existing code and modify it in the following way such that it performs the decryption for us:

#!/usr/bin/env python

import random, string, sys, os
from time import time
from Crypto.Cipher import AES
import base64

def get_iv(img):
    img_seed= os.path.getmtime(img)
    iv = ""
    random.seed(int(img_seed))
    for i in range(0,16):
        iv += random.choice(string.letters + string.digits)
    return iv

def decrypt(m, p, i):
    aes = AES.new(p, AES.MODE_CFB, i)
    return aes.decrypt(base64.b64decode(m))

def find_images():
    i = []
    for r, d, f in os.walk("."):
        for g in f:
            if g.endswith(".png"):
                i.append((os.path.join(r, g)))
    return i

def decrypt_images():
    for i in find_images():
        decrypt_image(i)

def decrypt_image(img):
    data = open(img, 'r').readlines()[-1]
    decrypted_img = decrypt(data, sys.argv[1], get_iv(img))
    dec_img= img.replace("Pictures", "Decrypted")
    open(dec_img, 'w').write(decrypted_img)

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print "Usage: %s <pass>" % sys.argv[0]
    else:
        decrypt_images()

Now, all that we have to do is call the script with the passphrase we found in the bash history:

$ python decrypt.py Hb8jnSKzaNQr5f7p

We are able to decrypt all but one image. However, while flipping through the decrypted images we notice that one of them already contains the flag:

Decrypted pony image containing the flag

The flag is: flag{ed70550afe72e2a8fed444c5850d6f9b}