In this post we will describe the Linux volshell and yarascan plugins. In previous releases of Volatility, these plugins only supported Windows samples, but starting with 2.3 you can interactively explore your Linux memory dumps (from a Python shell) or scan process and kernel memory with Yara signatures. The plugins also work against Android memory dumps.
Linux Volshell
To get the process started, simply run the "linux_volshell" plugin with no arguments.
# python vol.py --profile=LinuxMandriva2011x64 -f ~/mandriva.lime linux_volshell
Volatile Systems Volatility Framework 2.3_beta
Current context: process systemd, pid=1 DTB=0x106a3000
Welcome to volshell! Current memory image is:
file:///root/mandriva.lime
To get help, type 'hh()'
>>>
This drops you into a Python shell. At this point you have full access to the Volatility namespace as well as all of Python. If you type hh() you are given a help menu which displays the volshell-specific plugins:
>>> hh()
Use self.addrspace for Kernel/Virtual AS
Use self.addrspace.base for Physical AS
Use self.proc to get the current _EPROCESS object
and self.proc.get_process_address_space() for the current process AS
and self.proc.get_load_modules() for the current process DLLs
cc(offset=None, pid=None, name=None) : Change current shell context.
db(address, length=128, space=None) : Print bytes as canonical hexdump.
dd(address, length=128, space=None) : Print dwords at address.
dis(address, length=128, space=None, mode=None) : Disassemble code at a given address.
dq(address, length=128, space=None) : Print qwords at address.
dt(objct, address=None, space=None) : Describe an object or show type info.
hh(cmd=None) : Get help on a command.
list_entry(head, objname, offset=-1, fieldname=None, forward=True) : Traverse a _LIST_ENTRY.
modules() : Print a module listing.
ps() : Print a process listing.
sc() : Show the current context.
For help on a specific command, type 'hh(<command>)'
When you first enter volshell you are in the context of PID 1 which is generally init or "systemd", the process which spawns all other processes. At this point, self.proc is instanitated to the task struct for this process:
>>> self.proc
[task_struct task_struct] @ 0xFFFF8800159B8000
>>> self.proc.pid
[int]: 1
>>> str(self.proc.comm)
'systemd'
if we want to change to another process, we must use the cc() command:
>>> cc(pid=7326)
Current context: process insmod, pid=7326 DTB=0x176a4000
>>> self.proc.pid, str(self.proc.comm)
( [int]: 7326, 'insmod')
If we want to read from the address space of a process, we can use the db, dd, and dq commands:
>>> db(self.proc.comm.obj_offset)
0xffff880001cac848 69 6e 73 6d 6f 64 00 00 00 00 00 00 00 00 00 00 insmod..........
0xffff880001cac858 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0xffff880001cac868 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0xffff880001cac878 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0xffff880001cac888 00 40 2f 11 00 88 ff ff 38 38 2f 11 00 88 ff ff .@/.....88/.....
0xffff880001cac898 e8 a5 ab c1 ff 7f 00 00 00 00 00 00 00 00 00 00 ................
0xffff880001cac8a8 00 57 f6 ba 5a 7f 00 00 00 00 00 00 00 00 00 00 .W..Z...........
0xffff880001cac8b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
>>> dd(self.proc.comm.obj_offset)
ffff880001cac848 6d736e69 0000646f 00000000 00000000
ffff880001cac858 00000000 00000000 00000000 00000000
ffff880001cac868 00000000 00000000 00000000 00000000
ffff880001cac878 00000000 00000000 00000000 00000000
ffff880001cac888 112f4000 ffff8800 112f3838 ffff8800
ffff880001cac898 c1aba5e8 00007fff 00000000 00000000
ffff880001cac8a8 baf65700 00007f5a 00000000 00000000
ffff880001cac8b8 00000000 00000000 00000000 00000000
>>> dq(self.proc.comm.obj_offset)
0xffff880001cac848 0x646f6d736e69
0xffff880001cac850 0x0
0xffff880001cac858 0x0
0xffff880001cac860 0x0
0xffff880001cac868 0x0
0xffff880001cac870 0x0
0xffff880001cac878 0x0
0xffff880001cac880 0x0
0xffff880001cac888 0xffff8800112f4000
0xffff880001cac890 0xffff8800112f3838
0xffff880001cac898 0x7fffc1aba5e8
0xffff880001cac8a0 0x0
0xffff880001cac8a8 0x7f5abaf65700
0xffff880001cac8b0 0x0
0xffff880001cac8b8 0x0
0xffff880001cac8c0 0x0
We can also use the read() function of the address space to read arbitrary addresses and lengths. In this example we are reading the command line arguments to the insmod process:
>>> dq(self.proc.mm.arg_start, length=8)
0x7fffc1abb055 0x6c00646f6d736e69
>>> self.proc.get_process_address_space().read(0x7fffc1abb055, 79)
'insmod\x00lime-2.6.38.7-desktop-1mnb2.ko\x00path=/home/mhl/mandriva.lime format=lime\x00'
Volatility also provides conveniences functions, such as ps() and modules():
>>> ps()
Name PID Offset
systemd 1 0xffff8800159b8000
kthreadd 2 0xffff8800159b96b0
ksoftirqd/0 3 0xffff8800159bad60
kworker/u:0 5 0xffff8800159bdac0
migration/0 6 0xffff8800159e8000
cpuset 7 0xffff8800159e96b0
khelper 8 0xffff8800159ead60
netns 9 0xffff8800159ec410
[snip]
>>> modules()
lime 8734
fuse 71414
af_packet 21188
joydev 10468
rfcomm 67790
nfs 310764
lockd 79366
fscache 61155
nfs_acl 2725
auth_rpcgss 43775
sunrpc 224700
sco 17185
[snip]
For users wishing to explore data structures and potentially write their own plugins, the dt() command is very helpful. It can display data structures based on the current profile and also list the values of a particular instance.
>>> ps()
<snip>
insmod 7326 0xffff880001cac410
>>> dt("mm_struct")
'mm_struct' (864 bytes)
0x0 : mmap ['pointer', ['vm_area_struct']]
0x8 : mm_rb ['rb_root']
<snip>
0x120 : arg_start ['unsigned long']
0x128 : arg_end ['unsigned long']
0x130 : env_start ['unsigned long']
0x138 : env_end ['unsigned long'] >>> ts = obj.Object("task_struct", offset = 0xffff880001cac410, vm = self.addrspace)
>>> dt("mm_struct", ts.mm)
[CType mm_struct] @ 0xFFFF880010763B80
0x0 : mmap 18446612132338969288
0x8 : mm_rb 18446612132590402440
<snip>
0x120 : arg_start 140736442642517
0x128 : arg_end 140736442642596
0x130 : env_start 140736442642596
0x138 : env_end 140736442646507
Linux Yarascan
The yarascan plugin allows for searching of physical memory, the kernel AS, or the AS of any process for everything from simple strings to complex yara rules.
If we search for insmod inside of its parent bash process, we find many copies of the invocation used to capture the memory dump and whose command line arguments we previously looked at in volshell:
# python vol.py --profile=LinuxMandriva2011x64 -f ~/mandriva.lime linux_yarascan -Y insmod -p 7284
Volatile Systems Volatility Framework 2.3_beta
Task: bash pid 7284 rule r1 addr 0x10eded0
0x010eded0 69 6e 73 6d 6f 64 20 6c 69 6d 65 2d 32 2e 36 2e insmod.lime-2.6.
0x010edee0 33 38 2e 37 2d 64 65 73 6b 74 6f 70 2d 31 6d 6e 38.7-desktop-1mn
0x010edef0 62 32 2e 6b 6f 20 22 70 61 74 68 3d 2f 68 6f 6d b2.ko."path=/hom
0x010edf00 65 2f 6d 68 6c 2f 6d 61 6e 64 72 69 76 61 2e 6c e/mhl/mandriva.l
Additionally, if we search the firefox process for "http://", we find many references to LiME, which was the tool downloaded to capture memory:
# python vol.py --profile=LinuxMandriva2011x64 -f ~/mandriva.lime linux_yarascan -p 6977 -Y "http://"
Task: firefox-bin pid 6977 rule r1 addr 0x7f1824b72bfc
0x7f1824b72bfc 68 74 74 70 3a 2f 2f 6c 69 6d 65 2d 66 6f 72 65 http://lime-fore
0x7f1824b72c0c 6e 73 69 63 73 2e 67 6f 6f 67 6c 65 63 6f 64 65 nsics.googlecode
0x7f1824b72c1c 2e 63 6f 6d 2f 66 69 6c 65 73 2f 6c 69 6d 65 2d .com/files/lime-
0x7f1824b72c2c 66 6f 72 65 6e 73 69 63 73 2d 31 2e 31 2d 72 31 forensics-1.1-r1
Conclusion
Hopefully you have enjoyed and learned from this post and can use it to enhance your own Linux investigations. In tomorrow's blog post we will learn about scanning for bash history in memory and how to recover such records along with their timestamps. If you have any questions or comments please leave a reply below or you can find us on Twitter - @volatility.
No comments:
Post a Comment