Tags: volatility rootkit 

Rating: 4.6

# getdents
by kevin
115 solves

Oh shit! Data have been stolen from my computer... I looked for malicious activity but found nothing suspicious. Could ya give me a hand and find the malware and how it's hiding?

[Memory image](https://storage.googleapis.com/insomnihack/media/memory_a97a5b9a792b61131eb6193e09c69616df875bb43539359af0e421b1b0798ba7.zip)

## Analysis
You are presented with a `memory.vmem` and a `Ubuntu_4.15.0-72-generic_profile.zip` file.
A .vmem file is a memory dump of VMWare Workstation. I heard the tool of choice is [volatility](https://www.volatilityfoundation.org/) and the "profile" archive was a good hint that we're supposed to use it too.

I've never used volatility before, so this might get a little bit verbose if you're familiar.

### Poking with `binwalk`
A team member first got a really small ELF executable file out of the memory dump, which did some syscalls to connect to a local IP `192.168.180.131:1337`, read 126 bytes of shellcode from the socket and execute it? They used `binwalk` to find all ELF files, filter out all shared objects, so there were only a few executables left, and carved them out closely using `dd`.

So we're after some network payload hopefully still in memory somewhere?

### Recon
Install volatility first. It's thankfully packaged in most linux distributions.
```bash
$ sudo apt install volatility
```

Then I had to figure out how to use that profile, since volatility only came with windows profiles in my case. `--plugins=.` in the folder with the profile.zip did the trick.
```bash
$ volatility --plugins=. --info
Volatility Foundation Volatility Framework 2.6

Profiles
--------
LinuxUbuntu_4_15_0-72-generic_profilex64 - A Profile for Linux Ubuntu_4.15.0-72-generic_profile x64
VistaSP0x64 - A Profile for Windows Vista SP0 x64
VistaSP0x86 - A Profile for Windows Vista SP0 x86
...
```

Following a [nice tutorial](https://medium.com/@zemelusa/first-steps-to-volatile-memory-analysis-dcbd4d2d56a1), I tried to get some output, just to realize that most of the used commands are Windows-only and you need to use the `linux_` prefixed plugins.

```bash
$ volatility --plugins=. -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 pslist
Volatility Foundation Volatility Framework 2.6
ERROR : volatility.debug : This command does not support the profile LinuxUbuntu_4_15_0-72-generic_profilex64
$ volatility --plugins=. -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_pslist
Volatility Foundation Volatility Framework 2.6
Offset Name Pid PPid Uid Gid DTB Start Time
------------------ -------------------- --------------- --------------- --------------- ------ ------------------ ----------
...
0xffff8a9db6dc0000 bash 1733 1724 1000 1000 0x0000000014662000 2020-01-16 14:00:57 UTC+0000
0xffff8a9dcf5ec5c0 sudo 1750 1733 0 0 0x000000005388a000 2020-01-16 14:01:22 UTC+0000
0xffff8a9dcf5edd00 meterpreter 1751 1750 0 0 0x0000000014540000 2020-01-16 14:01:22 UTC+0000
...
0xffff8a9dc3c40000 sh 2964 1751 0 0 0x0000000076aec000 2020-01-16 14:02:57 UTC+0000
```

I've stripped down the output of the process list to the processes that looked most interesting and possibly contain user input.

I tried a few random `linux_*` plugins to see if there is anything suspicious. volatility has a pretty good `--help` system for every command, so it was easy to use. `linux_lsmod` to list all loaded kernel modules didn't show anything unusual. `linux_ifconfig` showed that the IP we found earlier is actually the local IP of the machine:

```bash
$ volatility --plugins=. -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_ifconfig
Volatility Foundation Volatility Framework 2.6
Interface IP Address MAC Address Promiscous Mode
---------------- -------------------- ------------------ ---------------
lo 127.0.0.1 00:00:00:00:00:00 False
ens33 192.168.180.132 92:3d:f2:bb:2d:48 False
lo 127.0.0.1 00:00:00:00:00:00 False
```

The bash history looked interesting too:
```bash
$ volatility --plugins=. -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_bash
Volatility Foundation Volatility Framework 2.6
Pid Name Command Time Command
-------- -------------------- ------------------------------ -------
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo apt upgrade
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo apt upgrade
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo apt update
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo apt update
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo reboot
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo reboot
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo apt upgrade
1733 bash 2020-01-16 14:00:36 UTC+0000 rub
1733 bash 2020-01-16 14:00:36 UTC+0000 uname -a
1733 bash 2020-01-16 14:00:36 UTC+0000 AWAVH??
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo apt update
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo apt autoclean
1733 bash 2020-01-16 14:00:36 UTC+0000 uname -a
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo apt upgrade
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo reboot
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo apt upgrade
1733 bash 2020-01-16 14:00:36 UTC+0000 sudo reboot
1733 bash 2020-01-16 14:00:41 UTC+0000 chmod +x meterpreter
1733 bash 2020-01-16 14:00:42 UTC+0000 sudo ./meterpreter
```

So all that happened was starting [meterpreter](https://www.metasploit.com/) as root. I tried to get a history of that other `sh` process using the same `linux_bash` plugin, but it looks like it really only supports `bash` processes. Go figure.

Lets dump the memory of those processes and see if there's anything:
```bash
$ volatility --plugins=. -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_procdump -D ./procdumps -p 1733,1751,2964
$ strings procdumps/sh.2964.0x55f26b1a8000
...
insmod /home/julien/Downloads/rkit.ko hide=rJ/1g5PA5amy176A64akjuq/jryOug== hide_pid=1751
...
```

Now that's interesting. `rkit.ko` sounds like some rootkit kernel module. The `meterpreter` process has pid 1751, checking that binary from the dump turns out to be the same one we found using `binwalk` in the beginning. So the rootkit probably replaced the meterpreter binary in memory with that code?

Lets see if we can dump the rootkit.
```bash
$ volatility --plugins=. -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_enumerate_files
Inode Address Inode Number Path
------------------ ------------------------- ----
...
0xffff8a9dc38422e8 2363716 /home/home/home/julien/Downloads
0x0 ------------------------- /home/home/home/julien/Downloads/.hidden
0xffff8a9dd42755e8 2359303 /home/home/home/julien/Downloads/rkit.ko
0xffff8a9d948151a8 2367790 /home/home/home/julien/Downloads/meterpreter
...
0xffff8a9db536da40 890 /sys/module
0xffff8a9df5ac0be0 45233 /sys/module/rkit
0xffff8a9df5ac5ca0 45235 /sys/module/rkit/uevent
...

$ volatility --plugins=. -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_find_file --inode=0xffff8a9dd42755e8 --outfile=./files/rkit.ko
```

### Analysing the rootkit
Opening the kernel module in the reverse engineering framework of choice reveals only a few functions.
The basic outline of the functionality is as follows:

- base64 decode the `hide` parameter and save a pointer to it in the global `ep` variable.
- get some data from the network interface `ens33` and setup a key like `sk[i] = pk[i] ^ networkthing[i]`, while `pk` is a hardcoded string in the binary.
- replace the `getdents` syscall handler with a custom function. That's probably where the challenge got its name from :)
- the custom handler decrypts the global `ep` variable using `sk`, does something with the syscall arguments I guess, then encrypts `ep` again like `ep[i] ^= sk[i % len(sk)]`.

The key `sk` is only created once when the module is loaded and stays the same over the time of the program. We know the value of the `hide` parameter from the dump of the `sh` process above: `rJ/1g5PA5amy176A64akjuq/jryOug==`. So if we could dump the copy of the kernel module in memory we should be able to get that key `sk`!

The `linux_lsmod` plugin couldn't find the rootkit kernel module, lets try another one.

```bash
$ volatility --plugins=. -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_check_modules
Volatility Foundation Volatility Framework 2.6
Module Address Core Address Init Address Module Name
------------------ ------------------ ------------------ ------------------------
0xffffffffc0943080 0xffffffffc0941000 0x0 rkit
```

There you are. Dump it.
```bash
$ volatility --plugins=. -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_moddump --base=0xffffffffc0943080 --dump-dir=./moddump
```

The command took half an hour on my laptop, but eventually spit out a `rkit.0xffffffffc0943080.lkm` file. This was the same kernel module, just with actual values (and absolute addresses) in the `.bss` section. From there we could extract the secret key `sk` and get the flag using xor, like the binary did.

```python
import base64
param = base64.b64decode('rJ/1g5PA5amy176A64akjuq/jryOug==')
key = bytes.fromhex('E5 D1 A6 F8 C1 F0 D5 DD F9 E6 CA C6 DB F4 F6 E1 DA D4 E7 D9 FD C7 A5 FC C8 C4 E4 DE E3 A2 F7 C5 FE A3 FF D0 C3 E0 AB C2 A7 D8 D7 E2 DF EB DC AA A1 A0 D3 CB A4 F1 FA C0 FB F5 D6 F3 EA E8 00 00')
print(bytes(param[i] ^ key[i%len(key)] for i in range(len(param))))
# b'INS{R00tK1tF0rRo0kies}'
```

expend20Jan. 21, 2020, 9:25 a.m.

Hi, thanks for the write up. Is there any command in volatility to dump kernel memory? Or memory from usermode process address space.