# Insomni'hack teaser 2020 Writeup

I played Insomni'hack teaser 2020 in shibad0gs. There're only 1 misc, 1 rev, 1 forensics, 3 crypto and 4 web. We solved 4 tasks in the first 4 hours and that's it lol.

As the web tasks are too guessy, I just solved the misc, forensics and the easiest web.

# [misc] welcome

We're given a PoW script, which also sends the user data to server and overwrite bashrc while calculating. I just removed the malicious line and run it, sent the result to the server and got the flag.

# [web] LowDeep

It's a ping service online. As it has obvious OS command injection, I run ls -lha and found ./print_flag, which seems an ELF binary but not executable. I dropped it through browser (since it's in /var/www/html) and found the flag using string command.

# [forensics] getdents

Description: 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?
File: memory.vmem

This is the only fun challenge. We're given a memory dump of an Ubuntu machine.

At first I dumped the file list.

$vol.py -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_enumerate_files Looking over the list, I found some curious files. 0xffff8a9dc38422e8 2363716 /home/julien/Downloads 0x0 ------------------------- /home/julien/Downloads/.hidden 0xffff8a9dd42755e8 2359303 /home/julien/Downloads/rkit.ko 0xffff8a9d948151a8 2367790 /home/julien/Downloads/meterpreter Let's dump and analyse rkit.ko. $ vol.py -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_find_file -i 0xffff8a9dd42755e8 -O rkit.ko

This function is suspicious because it's alternating getdents syscall to something new.

Let's check sub_80005EE and sub_8000266. sub_80005EE is pretty incomprehensive.

However, it seems a base64 encoder since it's using a table abcd...789+/ inside the function. The return value of this function is the kmalloced pointer. So, we can guess something like this is happening.

ep = base64(s, strlen(s), &epl);

Let's check sub_8000266 now.

This is another encoder. I implemented this encoder in Python.

pk = "wC4jSbGOktXTIfdsHFuKoU7nZVvLq0eWl1mBQr9P5JEpMyN832AY6chRigDaxz"
sk = ""
for i in range(62):
sk += chr(ord(pk[i]) ^ key)


At first glance the xor key is variable but actually constant.

Where is ep used? There's another suspicious function sub_80005F9.

This is also an encoder which uses sk as the key. The code looks like this:

for i in range(len(encoded_flag)):
encoded_flag[i] ^= sk[j % 62]


Okay, now we have every piece. Next thing we need to do is find the encoded flag.

Let's dump the memory around this kernel module using volshell. Before that we have to find the address where rkit.ko is loaded.

$vol.py -f memory.vmem --profile=LinuxUbuntu_4_15_0-72-generic_profilex64 linux_check_modules Volatility Foundation Volatility Framework 2.6.1 Module Address Core Address Init Address Module Name ------------------ ------------------ ------------------ ------------------------ 0xffffffffc0943080 0xffffffffc0941000 0x0 rkit You see the address of the syscall table is fixed. Also, sk, epl and ep are followed by syscall_table. In volshell you can find those data here: >>> db(0xffffffffc09433e0, 128) 0xffffffffc09433e0 e5 d1 a6 f8 c1 f0 d5 dd f9 e6 ca c6 db f4 f6 e1 ................ 0xffffffffc09433f0 da d4 e7 d9 fd c7 a5 fc c8 c4 e4 de e3 a2 f7 c5 ................ 0xffffffffc0943400 fe a3 ff d0 c3 e0 ab c2 a7 d8 d7 e2 df eb dc aa ................ 0xffffffffc0943410 a1 a0 d3 cb a4 f1 fa c0 fb f5 d6 f3 ea e8 00 00 ................ 0xffffffffc0943420 16 00 00 00 00 00 00 00 a0 12 fc a1 9d 8a ff ff ................ 0xffffffffc0943430 40 02 60 ab ff ff ff ff 00 00 00 00 00 00 00 00 @.............. 0xffffffffc0943440 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0xffffffffc0943450 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ Let's dump the pointer to the encoded flag. >>> db(0xffff8a9da1fc12a0, 128) 0xffff8a9da1fc12a0 ac 9f f5 83 93 c0 e5 a9 b2 d7 be 80 eb 86 a4 8e ................ 0xffff8a9da1fc12b0 ea bf 8e bc 8e ba 00 00 60 da af aa ff ff ff ff ............... 0xffff8a9da1fc12c0 7a 73 84 f8 09 cc dd c4 d0 9b aa aa ff ff ff ff zs.............. 0xffff8a9da1fc12d0 b0 9b aa aa ff ff ff ff b0 4e b0 aa ff ff ff ff .........N...... 0xffff8a9da1fc12e0 c0 f0 68 c0 51 d7 ff ff 80 f0 68 c0 51 d7 ff ff ..h.Q.....h.Q... 0xffff8a9da1fc12f0 00 f1 68 c0 51 d7 ff ff 00 00 00 00 00 00 00 00 ..h.Q........... 0xffff8a9da1fc1300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0xffff8a9da1fc1310 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ Cool. As we have sk and ep, we can easily recover the original flag. import base64 encrypted = "\xac\x9f\xf5\x83\x93\xc0\xe5\xa9\xb2\xd7\xbe\x80\xeb\x86\xa4\x8e\xea\xbf\x8e\xbc\x8e\xba" sk = b'\xe5\xd1\xa6\xf8\xc1\xf0\xd5\xdd\xf9\xe6\xca\xc6\xdb\xf4\xf6\xe1\xda\xd4\xe7\xd9\xfd\xc7' flag = "" for i in range(len(encrypted)): flag += chr(ord(encrypted[i]) ^ ord(sk[i % 62])) print(flag)  $ python solve.py
INS{R00tK1tF0rRo0kies}