ebCTF 2013: FOR100
After a recent attack, we found this encrypted file. Luckily, we made a
memory dump, can you decrypt the file?
Archive password: lcoXse3oa3Uicioc
http://ebctf.nl/files/883f6fdf1a87b7651b7216e1354a7e1f/flag
http://194.171.96.106/ebctf/memory.7z
We took this exercise as an opportunity to learn to use volatility, so this writeup will be a little overcomplicated, we could have just done it with strings/grep, but it was a great way to learn more about how to search and exploit memory dump.
To begin with, we have a memory dump of a VirtualBox VM :
$ file memory.dump
memory.dump: ELF 64-bit LSB core file x86-64, version 1 (SYSV)
$ readelf -n memory.dump
Notes at offset 0x000002a8 with length 0x00000480:
Owner Data size Description
VBCORE 0x00000018 Unknown note type: (0x00000b00)
VBCPU 0x00000440 Unknown note type: (0x00000b01)
A little examination of the raw data indicates that it should be a linux, as we see the grub code in memory, and some indication of a kernel version :
BOOT_IMAGE=/boot/vmlinuz-3.5.0-23-generic root=UUID=d45d9170-0f93-4ff4-b5a5-be89760c0d77 ro
A little more search indicates that it is an Ubuntu 12.04 x86_64
image.
In order to use volatility on linux dumps, we must build or find a profile of the kernel. Instructions for building a profile for a kernel can be found here.
With this profile in place we can now start to tinker with our dump. Let’s start with the process list :
$ vol.py --profile=LinuxUbuntu1204x64 -f memory.dump linux_pslist
Volatile Systems Volatility Framework 2.3_beta
Offset Name Pid Uid Gid DTB Start Time
------------------ -------------------- --------------- --------------- ------ ------------------ ----------
0xffff88000f9b0000 init 1 0 0 0x000000000aff1000 2013-07-21 19:19:32 UTC+0000
0xffff88000f9b1700 kthreadd 2 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000f9b2e00 ksoftirqd/0 3 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fa48000 migration/0 6 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fa49700 watchdog/0 7 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fa4ae00 cpuset 8 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fa4c500 khelper 9 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fa4dc00 kdevtmpfs 10 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fa68000 netns 11 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fa69700 sync_supers 12 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fa6ae00 bdi-default 13 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fa6c500 kintegrityd 14 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fa6dc00 kblockd 15 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fb00000 ata_sff 16 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fb01700 khubd 17 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000fb02e00 md 18 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000db90000 khungtaskd 21 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000db91700 kswapd0 22 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000db92e00 ksmd 23 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000db94500 fsnotify_mark 24 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000db95c00 ecryptfs-kthrea 25 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000d5f0000 crypto 26 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000d7a5c00 kthrotld 35 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000d7a2e00 scsi_eh_0 36 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000d7a1700 kworker/u:2 37 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000d7a0000 scsi_eh_1 38 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000d5f5c00 scsi_eh_2 39 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000d5f4500 kworker/u:3 40 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000d5f1700 binder 42 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000f011700 deferwq 62 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000f012e00 charger_manager 63 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000f014500 devfreq_wq 64 0 0 ------------------ 2013-07-21 19:19:32 UTC+0000
0xffff88000ee35c00 jbd2/sda1-8 201 0 0 ------------------ 2013-07-21 19:19:33 UTC+0000
0xffff88000ee30000 ext4-dio-unwrit 202 0 0 ------------------ 2013-07-21 19:19:33 UTC+0000
0xffff88000ec7dc00 kworker/0:3 220 0 0 ------------------ 2013-07-21 19:19:35 UTC+0000
0xffff88000ec78000 upstart-udev-br 288 0 0 0x000000000ada3000 2013-07-21 19:19:37 UTC+0000
0xffff88000f2ddc00 udevd 332 0 0 0x000000000ef46000 2013-07-21 19:19:37 UTC+0000
0xffff88000c291700 udevd 496 0 0 0x000000000c2a6000 2013-07-21 19:19:37 UTC+0000
0xffff88000c292e00 udevd 497 0 0 0x000000000c2c1000 2013-07-21 19:19:37 UTC+0000
0xffff88000c838000 kpsmoused 546 0 0 ------------------ 2013-07-21 19:19:37 UTC+0000
0xffff88000c4c9700 upstart-socket- 638 0 0 0x000000000d939000 2013-07-21 19:19:38 UTC+0000
0xffff88000ee31700 dhclient3 706 0 0 0x000000000f0fb000 2013-07-21 19:19:38 UTC+0000
0xffff88000c4cc500 rsyslogd 720 101 103 0x000000000c600000 2013-07-21 19:19:38 UTC+0000
0xffff88000c83ae00 sshd 729 0 0 0x000000000bbce000 2013-07-21 19:19:38 UTC+0000
0xffff88000c4cdc00 dbus-daemon 759 102 105 0x000000000c538000 2013-07-21 19:19:38 UTC+0000
0xffff88000d1aae00 getty 822 0 0 0x000000000c641000 2013-07-21 19:19:38 UTC+0000
0xffff88000c62c500 getty 827 0 0 0x000000000d98c000 2013-07-21 19:19:38 UTC+0000
0xffff88000c839700 login 831 0 1000 0x000000000f28d000 2013-07-21 19:19:38 UTC+0000
0xffff88000c83dc00 getty 832 0 0 0x000000000d9c1000 2013-07-21 19:19:38 UTC+0000
0xffff88000c4cae00 getty 834 0 0 0x000000000c684000 2013-07-21 19:19:38 UTC+0000
0xffff88000d0a4500 acpid 837 0 0 0x000000000c315000 2013-07-21 19:19:39 UTC+0000
0xffff88000c83c500 cron 839 0 0 0x000000000d9da000 2013-07-21 19:19:39 UTC+0000
0xffff88000d1a9700 atd 840 0 0 0x000000000c327000 2013-07-21 19:19:39 UTC+0000
0xffff88000da11700 login 896 0 1000 0x000000000ae44000 2013-07-21 19:19:39 UTC+0000
0xffff88000c514500 whoopsie 901 103 106 0x000000000dae3000 2013-07-21 19:19:39 UTC+0000
0xffff88000bb15c00 bash 1064 1000 1000 0x000000000c6f0000 2013-07-21 19:19:46 UTC+0000
0xffff88000af90000 kworker/0:0 1313 0 0 ------------------ 2013-07-21 19:24:35 UTC+0000
0xffff88000af94500 kworker/0:2 1314 0 0 ------------------ 2013-07-21 19:29:36 UTC+0000
0xffff88000af91700 kworker/0:1 1315 0 0 ------------------ 2013-07-21 19:34:37 UTC+0000
0xffff88000af95c00 kworker/0:4 1316 0 0 ------------------ 2013-07-21 19:35:46 UTC+0000
0xffff88000af92e00 python2 1317 1000 1000 0x000000000c6fb000 2013-07-21 19:36:09 UTC+0000
0xffff88000d0a5c00 bash 1454 1000 1000 0x000000000d8c8000 2013-07-21 19:36:23 UTC+0000
0xffff88000f9b4500 flush-8:0 1552 0 0 ------------------ 2013-07-21 19:36:28 UTC+0000
As we can see here, we have a python2 instance launched (pid 1317). Let’s examine the bash history, in order to see exactly what and how it has been launched. It is a quite long process, but with it we should be able to see exactly what was launched.
$ vol.py --profile=LinuxUbuntu1204x64 -f memory.dump linux_bash
Volatile Systems Volatility Framework 2.3_beta
Pid Name Command Time Command
-------- -------------------- ------------------------------ -------
1064 bash 2013-07-21 19:19:47 UTC+0000 ps aux | grep ssh
1064 bash 2013-07-21 19:19:47 UTC+0000 sudo poweroff
1064 bash 2013-07-21 19:19:47 UTC+0000 ip addr
1064 bash 2013-07-21 19:20:53 UTC+0000 ls
1064 bash 2013-07-21 19:21:05 UTC+0000 python2 ctf.py
1064 bash 2013-07-21 19:21:29 UTC+0000 python2 ctf.py ' i hide my '
1454 bash 2013-07-21 19:36:23 UTC+0000 ps aux | grep ssh
1454 bash 2013-07-21 19:36:23 UTC+0000 sudo poweroff
1454 bash 2013-07-21 19:36:23 UTC+0000 ip addr
1454 bash 2013-07-21 19:36:29 UTC+0000 ps aux | grep python
1454 bash 2013-07-21 19:37:04 UTC+0000 kill -s SIGUSR1 1317
Ok, so we have a python2 script ctf.py
launched and after that, killed by a SIGUSR1
signal.
If the code should still be in memory, but sadly, not in python memory, as was
compiled before and the second launched should only load the pyc
file.
But if we search in memory, we can simply grep for SIGUSR1
there should not
be a lot of instance of it. And with that we get :
import sys
import time
import random
import signal
from Crypto.Cipher import AES
key1 = "is this where"
key2 = sys.argv[1]
key3 = raw_input("Password: ")
iv = 'a very random iv'
secret = './flag'
mode = AES.MODE_CBC
def encrypt(signum, frame):
key = key1 + key2 + key3
enc = AES.new(key, mode, iv)
inp = raw_input("Enter secret: ")
diff = len(inp) % 16
if diff != 0:
inp += ' ' * (16 - diff)
with open(secret, 'wb') as outfile:
outfile.write(enc.encrypt(inp))
del key, enc
def decrypt(signum, frame):
key = key1 + key2 + key3
enc = AES.new(key, mode, iv)
with open(secret, 'rb') as infile:
print(enc.decrypt(infile.read(48)))
del key, enc
signal.signal(signal.SIGUSR1, encrypt)
signal.signal(signal.SIGUSR2, decrypt)
while True:
time.sleep(1)
Now we have the code. There is a decrypt function that should give us the flag.
we have found key2
in the bash history, it was ' i hide my '
. What we still
miss is the key3
string. So let’s look at the python process memory.
$ vol.py --profile=LinuxUbuntu1204x64 -f memory.dump linux_proc_maps -p 131
Volatile Systems Volatility Framework 2.3_beta
Pid Start End Flags Pgoff Major Minor Inode File Path
-------- ------------------ ------------------ ------ ------------------ ------ ------ ---------- --------------------------------------------------------------------------------
$ vol.py --profile=LinuxUbuntu1204x64 -f memory.dump linux_proc_maps -p 1317
Volatile Systems Volatility Framework 2.3_beta
Pid Start End Flags Pgoff Major Minor Inode File Path
-------- ------------------ ------------------ ------ ------------------ ------ ------ ---------- --------------------------------------------------------------------------------
1317 0x0000000000400000 0x0000000000671000 r-x 0x0 8 1 1273 /usr/bin/python2.7
1317 0x0000000000870000 0x0000000000871000 r-- 0x270000 8 1 1273 /usr/bin/python2.7
1317 0x0000000000871000 0x00000000008da000 rw- 0x271000 8 1 1273 /usr/bin/python2.7
1317 0x00000000008da000 0x00000000008ec000 rw- 0x0 0 0 0
1317 0x0000000002109000 0x0000000002200000 rw- 0x0 0 0 0 [heap]
1317 0x00007f7e9a000000 0x00007f7e9a001000 rw- 0x0 0 0 0
1317 0x00007f7e9a001000 0x00007f7e9a009000 r-x 0x0 8 1 146852 /usr/lib/python2.7/dist-packages/Crypto/Cipher/AES.so
1317 0x00007f7e9a009000 0x00007f7e9a208000 --- 0x8000 8 1 146852 /usr/lib/python2.7/dist-packages/Crypto/Cipher/AES.so
1317 0x00007f7e9a208000 0x00007f7e9a209000 r-- 0x7000 8 1 146852 /usr/lib/python2.7/dist-packages/Crypto/Cipher/AES.so
1317 0x00007f7e9a209000 0x00007f7e9a20a000 rw- 0x8000 8 1 146852 /usr/lib/python2.7/dist-packages/Crypto/Cipher/AES.so
1317 0x00007f7e9a20a000 0x00007f7e9a4d3000 r-- 0x0 8 1 8358 /usr/lib/locale/locale-archive
1317 0x00007f7e9a4d3000 0x00007f7e9a4e8000 r-x 0x0 8 1 713 /lib/x86_64-linux-gnu/libgcc_s.so.1
1317 0x00007f7e9a4e8000 0x00007f7e9a6e7000 --- 0x15000 8 1 713 /lib/x86_64-linux-gnu/libgcc_s.so.1
1317 0x00007f7e9a6e7000 0x00007f7e9a6e8000 r-- 0x14000 8 1 713 /lib/x86_64-linux-gnu/libgcc_s.so.1
1317 0x00007f7e9a6e8000 0x00007f7e9a6e9000 rw- 0x15000 8 1 713 /lib/x86_64-linux-gnu/libgcc_s.so.1
1317 0x00007f7e9a6e9000 0x00007f7e9a89e000 r-x 0x0 8 1 968 /lib/x86_64-linux-gnu/libc-2.15.so
1317 0x00007f7e9a89e000 0x00007f7e9aa9d000 --- 0x1b5000 8 1 968 /lib/x86_64-linux-gnu/libc-2.15.so
1317 0x00007f7e9aa9d000 0x00007f7e9aaa1000 r-- 0x1b4000 8 1 968 /lib/x86_64-linux-gnu/libc-2.15.so
1317 0x00007f7e9aaa1000 0x00007f7e9aaa3000 rw- 0x1b8000 8 1 968 /lib/x86_64-linux-gnu/libc-2.15.so
1317 0x00007f7e9aaa3000 0x00007f7e9aaa8000 rw- 0x0 0 0 0
1317 0x00007f7e9aaa8000 0x00007f7e9aba3000 r-x 0x0 8 1 978 /lib/x86_64-linux-gnu/libm-2.15.so
1317 0x00007f7e9aba3000 0x00007f7e9ada2000 --- 0xfb000 8 1 978 /lib/x86_64-linux-gnu/libm-2.15.so
1317 0x00007f7e9ada2000 0x00007f7e9ada3000 r-- 0xfa000 8 1 978 /lib/x86_64-linux-gnu/libm-2.15.so
1317 0x00007f7e9ada3000 0x00007f7e9ada4000 rw- 0xfb000 8 1 978 /lib/x86_64-linux-gnu/libm-2.15.so
1317 0x00007f7e9ada4000 0x00007f7e9adba000 r-x 0x0 8 1 4874 /lib/x86_64-linux-gnu/libz.so.1.2.3.4
1317 0x00007f7e9adba000 0x00007f7e9afb9000 --- 0x16000 8 1 4874 /lib/x86_64-linux-gnu/libz.so.1.2.3.4
1317 0x00007f7e9afb9000 0x00007f7e9afba000 r-- 0x15000 8 1 4874 /lib/x86_64-linux-gnu/libz.so.1.2.3.4
1317 0x00007f7e9afba000 0x00007f7e9afbb000 rw- 0x16000 8 1 4874 /lib/x86_64-linux-gnu/libz.so.1.2.3.4
1317 0x00007f7e9afbb000 0x00007f7e9b15a000 r-x 0x0 8 1 1604 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
1317 0x00007f7e9b15a000 0x00007f7e9b359000 --- 0x19f000 8 1 1604 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
1317 0x00007f7e9b359000 0x00007f7e9b374000 r-- 0x19e000 8 1 1604 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
1317 0x00007f7e9b374000 0x00007f7e9b37f000 rw- 0x1b9000 8 1 1604 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
1317 0x00007f7e9b37f000 0x00007f7e9b383000 rw- 0x0 0 0 0
1317 0x00007f7e9b383000 0x00007f7e9b3d5000 r-x 0x0 8 1 1603 /lib/x86_64-linux-gnu/libssl.so.1.0.0
1317 0x00007f7e9b3d5000 0x00007f7e9b5d5000 --- 0x52000 8 1 1603 /lib/x86_64-linux-gnu/libssl.so.1.0.0
1317 0x00007f7e9b5d5000 0x00007f7e9b5d8000 r-- 0x52000 8 1 1603 /lib/x86_64-linux-gnu/libssl.so.1.0.0
1317 0x00007f7e9b5d8000 0x00007f7e9b5de000 rw- 0x55000 8 1 1603 /lib/x86_64-linux-gnu/libssl.so.1.0.0
1317 0x00007f7e9b5de000 0x00007f7e9b5df000 rw- 0x0 0 0 0
1317 0x00007f7e9b5df000 0x00007f7e9b5e1000 r-x 0x0 8 1 986 /lib/x86_64-linux-gnu/libutil-2.15.so
1317 0x00007f7e9b5e1000 0x00007f7e9b7e0000 --- 0x2000 8 1 986 /lib/x86_64-linux-gnu/libutil-2.15.so
1317 0x00007f7e9b7e0000 0x00007f7e9b7e1000 r-- 0x1000 8 1 986 /lib/x86_64-linux-gnu/libutil-2.15.so
1317 0x00007f7e9b7e1000 0x00007f7e9b7e2000 rw- 0x2000 8 1 986 /lib/x86_64-linux-gnu/libutil-2.15.so
1317 0x00007f7e9b7e2000 0x00007f7e9b7e4000 r-x 0x0 8 1 967 /lib/x86_64-linux-gnu/libdl-2.15.so
1317 0x00007f7e9b7e4000 0x00007f7e9b9e4000 --- 0x2000 8 1 967 /lib/x86_64-linux-gnu/libdl-2.15.so
1317 0x00007f7e9b9e4000 0x00007f7e9b9e5000 r-- 0x2000 8 1 967 /lib/x86_64-linux-gnu/libdl-2.15.so
1317 0x00007f7e9b9e5000 0x00007f7e9b9e6000 rw- 0x3000 8 1 967 /lib/x86_64-linux-gnu/libdl-2.15.so
1317 0x00007f7e9b9e6000 0x00007f7e9b9fe000 r-x 0x0 8 1 972 /lib/x86_64-linux-gnu/libpthread-2.15.so
1317 0x00007f7e9b9fe000 0x00007f7e9bbfd000 --- 0x18000 8 1 972 /lib/x86_64-linux-gnu/libpthread-2.15.so
1317 0x00007f7e9bbfd000 0x00007f7e9bbfe000 r-- 0x17000 8 1 972 /lib/x86_64-linux-gnu/libpthread-2.15.so
1317 0x00007f7e9bbfe000 0x00007f7e9bbff000 rw- 0x18000 8 1 972 /lib/x86_64-linux-gnu/libpthread-2.15.so
1317 0x00007f7e9bbff000 0x00007f7e9bc03000 rw- 0x0 0 0 0
1317 0x00007f7e9bc03000 0x00007f7e9bc25000 r-x 0x0 8 1 985 /lib/x86_64-linux-gnu/ld-2.15.so
1317 0x00007f7e9bca2000 0x00007f7e9bd96000 rw- 0x0 0 0 0
1317 0x00007f7e9bd97000 0x00007f7e9be1f000 rw- 0x0 0 0 0
1317 0x00007f7e9be23000 0x00007f7e9be25000 rw- 0x0 0 0 0
1317 0x00007f7e9be25000 0x00007f7e9be26000 r-- 0x22000 8 1 985 /lib/x86_64-linux-gnu/ld-2.15.so
1317 0x00007f7e9be26000 0x00007f7e9be28000 rw- 0x23000 8 1 985 /lib/x86_64-linux-gnu/ld-2.15.so
1317 0x00007fff39317000 0x00007fff39339000 rw- 0x0 0 0 0 [stack]
1317 0x00007fff393ff000 0x00007fff39400000 r-x 0x0 0 0 0
The python2 heap are on high addresses, and we should have some of the strings in it. So let’s dump all the address space and search in it.
$ vol.py --profile=LinuxUbuntu1204x64 -f memory.dump linux_dump_map -p 1317 -D output/
$ grep -r 'i hide my' output/
Binary file output/task.1317.0x7f7e9bca2000.vma matches
Binary file output/task.1317.0x7fff39317000.vma matches
$ strings output/task.1317.0x7f7e9bca2000.vma | grep 'i hide my'
i hide my
is this where i hide my secrets?
$ strings output/task.1317.0x7fff39317000.vma | grep 'i hide my'
i hide my
As we can see that it should be 'secrets?'
. So we have the final modified
python script :
import sys
import time
import random
import signal
from Crypto.Cipher import AES
key1 = "is this where"
key2 = ' i hide my '
key3 = 'secrets?'
iv = 'a very random iv'
secret = './flag'
mode = AES.MODE_CBC
def encrypt(signum, frame):
key = key1 + key2 + key3
enc = AES.new(key, mode, iv)
inp = raw_input("Enter secret: ")
diff = len(inp) % 16
if diff != 0:
inp += ' ' * (16 - diff)
with open(secret, 'wb') as outfile:
outfile.write(enc.encrypt(inp))
del key, enc
def decrypt(signum, frame):
key = key1 + key2 + key3
enc = AES.new(key, mode, iv)
with open(secret, 'rb') as infile:
print(enc.decrypt(infile.read(48)))
del key, enc
print(decrypt(0, 0))
and the flag is :
$ python2 ctf.py
ebctf{55169c1c241aa20412da94b3fcbf8506}
This challenge was interesting, thank you Eindbazen and NFI for these Forensics Challenges. We did not had the time to finish any other, but we will do them later. We hope to see more forensics challenges like that in future CTFs.