Let’s put ourselves into the shoes of an attacker, where we’ve already gained access to the system by exploiting an existing vulnerability or by using a social engineering attack to lure the victim into visiting our web page. Social engineering is the easiest way to get the keys to the castle, but an attacker can just as well exploit a vulnerability in an arbitrary application like OpenOffice, Pidgin, Chrome, Firefox, etc. At this point, we’re already in the system, and the details of how we’ve gained access to the system are not important. Let’s also suppose that we’ve been able to escalate privileges by exploiting a well known vulnerability in the Linux kernel to gain administrative privileges. After we’ve done so, nothing is stopping us from changing the system however we want: we can install a backdoor into the system and the victim wouldn’t even know it. If we don’t want to change the files on the filesystem or leave anything else for the forensics examiner, we have to be very stealth when exploiting the system.

Dumping memory

There are various tools that we can use to dump memory under the Linux operating system, some of which are presented below. At the very basic level, we can divide the tools between those that dump a memory of just one process or the whole system.

Tools for Dumping Memory of a Single Process: the Process Dumper [1] program can be used to dump memory of single processes. It dumps memory of a running process where all data and code sections are dumped. The memory dump is outputted to stdout, so we need to use the program together with other tools like netcat, tar, etc.

http://www.trapkit.de/research/forensic/pd/pd_v1.1_lnx.bz2 # bunzip2 pd_v1.1_lnx.bz2 # ./pd_v1.1_lnx

Tools for Dumping Memory of a Whole System: LiME (Linux Memory Extractor) [2]: can be used to dump memory of a whole Linux system. To install LiME, we have to execute the following commands:

svn checkout http://lime-forensics.googlecode.com/svn/trunk/ lime # cd lime/src/ # make

When LiME is being compiled, a kernel .ko module is created, which needs to be inserted into the kernel by using insmod command. The memory dump can be saved to the filesystem or sent over the network. When inserting a module into the kernel, we can pass a number of parameters to insmod command, which are presented below:

path: a filename on local filesystem where the memory dump will be written or a tcp:. format: LiME can output the memory dump in various formats, like raw, padded and lime. A raw format concatenates all system RAM into an image. A padded format pads non-system RAM with zeros and starts from physical address 0x0. A lime format appends an special header to each memory range to describe the address space information – also the Volatility program supports parsing this format, which is also the reason we’ll use it in this article. dio: when this parameter is set to 1 (the default), the Direct IO will be used, while the value of 0 disables it.

Now that we’ve described all three parameters that can be passed to lime.ko kernel module, we can issue the command as root to obtain the system’s memory. The command presented below will acquire whole system’s memory and save it into the /tmp/memdump.lime file by using lime format. Note that the process can take a while if you have large amount of physical memory available in the system; also note that there should be enough disk space to save the entire contents of physical memory to disk. [plain] # insmod lime.ko “path=/tmp/memdump.lime format=lime” [/plain] In Qemu we can dump memory of a running virtual machine by using the pmemsave command as follows. Note that the windows7.dump memory dump will be stored to the current directory if relative path is used. If we want to save the memory dump to an arbitrary location, we can enclose the whole path of the memory image in double quotation marks. [plain] (qemu) pmemsave 0 0x3FFFFFFF windows7.dump [/plain] Note that as long as the memory dumping is in progress, the virtual machine will be paused and we won’t be able to interact with it. In the command above, the start address is 0x0 to start dumping memory at the beginning and its size is 0x3FFFFFFF, which will dump 1GB of memory. If we go to system settings, we can see that the system has only 1GB of memory available, so we shouldn’t dump 4GB if it only has 1GB of memory.

Creating a profile in source distributions

Once the memory has been dumped, we have to analyze it in order to obtain useful information. Prior to doing that with Volatility, we have to create a profile, which contains kernel data structures and debug symbols that Volatility uses to locate critical information inside the memory dump [3]. It’s imperative that the profile is created on the same machine as we would like to analyze, since kernel data structure and debug symbols are specific to Linux distribution and kernel used. If we’re running a binary Linux distribution, it’s likely that some user has already created a profile and shared it with the rest of the world – in such cases we can use his profile to do our analysis. But if we’re running a source Linux distribution, we need to create the profile for ourselves. Each Linux profile depends upon three important factors:

Linux distribution Kernel version

CPU architecture

To build a profile, we must first download volatility source code from here and install it normally with make / make install. After successful installation, we need to enter the tools/linux/ directory in the Volatility source directory and issue a make command to create the required kernel’s data structures. By doing that, the Makefile will instruct the make command to compile module.c against the currently used Linux kernel, which we want to analyze. By doing that, a special file module.dwarf will be created.

The next step is getting the kernel symbols of the current kernel, which can be found in /boot/ directory for most binary Linux distributions. In source code distributions, the System.map can be found in the /usr/src/linux/ directory.

When creating a profile, we have to archive the module.dwarf as well as System.map into a .zip file and move the .zip file under plugins/overlays/linux/ directory. [plain] # cd volatility-2.3.1/volatility/plugins/overlays/linux/ # cp ../../../../tools/linux/module.dwarf . # cp /usr/src/linux/System.map . # zip Gentoo.zip System.map module.dwarf [/plain] To see whether the profile has been successfully created, we need to execute the vol.py command with the –info parameter and check if the Gentoo profile is presented in the output. In the output below, we can see that we’ve successfully added the Gentoo profile to Volatility. [plain] # ./vol.py –info | grep Linux Volatility Foundation Volatility Framework 2.3.1 LinuxGentoox64 – A Profile for Linux Gentoo x64 linux_banner – Prints the Linux banner information linux_yarascan – A shell in the Linux memory image [/plain] After that we can run Volatility normally with the following command, which will print all the supported commands that we can use when analyzing the memory dump of the Linux system. [plain] # ./vol.py -f memdump.lime –profile=LinuxGentoox64 -h Supported Plugin Commands: linux_arp Print the ARP table linux_banner Prints the Linux banner information linux_bash Recover bash history from bash process memory linux_check_afinfo Verifies the operation function pointers of network protocols linux_check_creds Checks if any processes are sharing credential structures linux_check_fop Check file operation structures for rootkit modifications linux_check_idt Checks if the IDT has been altered linux_check_modules Compares module list to sysfs info, if available linux_check_syscall Checks if the system call table has been altered linux_check_tty Checks tty devices for hooks linux_cpuinfo Prints info about each active processor linux_dentry_cache Gather files from the dentry cache linux_dmesg Gather dmesg buffer linux_dump_map Writes selected memory mappings to disk linux_find_file Recovers tmpfs filesystems from memory linux_ifconfig Gathers active interfaces linux_iomem Provides output similar to /proc/iomem linux_keyboard_notifier Parses the keyboard notifier call chain linux_lsmod Gather loaded kernel modules linux_lsof Lists open files linux_memmap Dumps the memory map for linux tasks linux_moddump Extract loaded kernel modules linux_mount Gather mounted fs/devices linux_mount_cache Gather mounted fs/devices from kmem_cache linux_netstat Lists open sockets linux_pidhashtable Enumerates processes through the PID hash table linux_pkt_queues Writes per-process packet queues out to disk linux_proc_maps Gathers process maps for linux linux_psaux Gathers processes along with full command line and start time linux_pslist Gather active tasks by walking the task_struct->task list linux_pslist_cache Gather tasks from the kmem_cache linux_pstree Shows the parent/child relationship between processes linux_psxview Find hidden processes with various process listings linux_route_cache Recovers the routing cache from memory linux_sk_buff_cache Recovers packets from the sk_buff kmem_cache linux_slabinfo Mimics /proc/slabinfo on a running machine linux_tmpfs Recovers tmpfs filesystems from memory linux_vma_cache Gather VMAs from the vm_area_struct cache linux_volshell Shell in the memory image linux_yarascan A shell in the Linux memory image mbrparser Scans for and parses potential Master Boot Records (MBRs) patcher Patches memory based on page scans [/plain] Since I was running a newer version of the Gentoo kernel than was officially supported, I wasn’t able to analyze the memory of Gentoo Linux. The supported Linux kernel versions are 2.6.11 – 3.5.x. If you have a kernel which falls in the range above, then Volatility is most probable to work just fine.

Analyzing memory

In this part of the article, we’ll analyze the memory dump of a Qemu Windows 7 system. To dump all available profiles we can use with the acquired image, we can use the –info parameter, which will display all available profiles as well as a lot of other information. [plain] # ./vol.py –info Volatility Foundation Volatility Framework 2.3.1 Profiles ——– LinuxGentoox64 – A Profile for Linux Gentoo x64 VistaSP0x64 – A Profile for Windows Vista SP0 x64 VistaSP0x86 – A Profile for Windows Vista SP0 x86 VistaSP1x64 – A Profile for Windows Vista SP1 x64 VistaSP1x86 – A Profile for Windows Vista SP1 x86 VistaSP2x64 – A Profile for Windows Vista SP2 x64 VistaSP2x86 – A Profile for Windows Vista SP2 x86 Win2003SP0x86 – A Profile for Windows 2003 SP0 x86 Win2003SP1x64 – A Profile for Windows 2003 SP1 x64 Win2003SP1x86 – A Profile for Windows 2003 SP1 x86 Win2003SP2x64 – A Profile for Windows 2003 SP2 x64 Win2003SP2x86 – A Profile for Windows 2003 SP2 x86 Win2008R2SP0x64 – A Profile for Windows 2008 R2 SP0 x64 Win2008R2SP1x64 – A Profile for Windows 2008 R2 SP1 x64 Win2008SP1x64 – A Profile for Windows 2008 SP1 x64 Win2008SP1x86 – A Profile for Windows 2008 SP1 x86 Win2008SP2x64 – A Profile for Windows 2008 SP2 x64 Win2008SP2x86 – A Profile for Windows 2008 SP2 x86 Win7SP0x64 – A Profile for Windows 7 SP0 x64 Win7SP0x86 – A Profile for Windows 7 SP0 x86 Win7SP1x64 – A Profile for Windows 7 SP1 x64 Win7SP1x86 – A Profile for Windows 7 SP1 x86 WinXPSP1x64 – A Profile for Windows XP SP1 x64 WinXPSP2x64 – A Profile for Windows XP SP2 x64 WinXPSP2x86 – A Profile for Windows XP SP2 x86 WinXPSP3x86 – A Profile for Windows XP SP3 x86 [/plain] Since we’re running Windows 7 SP1, we should use the Win7SP1x86 as the profile. To print all supported commands we can use with the memory dump, we can pass the -h as a parameter after we’ve already specified the memory image dump and profile. [plain] ./vol.py -f windows7.dump –profile=Win7SP1x86 Supported Plugin Commands: apihooks Detect API hooks in process and kernel memory atoms Print session and window station atom tables atomscan Pool scanner for _RTL_ATOM_TABLE bioskbd Reads the keyboard buffer from Real Mode memory callbacks Print system-wide notification routines clipboard Extract the contents of the windows clipboard cmdscan Extract command history by scanning for _COMMAND_HISTORY consoles Extract command history by scanning for _CONSOLE_INFORMATION crashinfo Dump crash-dump information deskscan Poolscaner for tagDESKTOP (desktops) devicetree Show device tree dlldump Dump DLLs from a process address space dlllist Print list of loaded dlls for each process driverirp Driver IRP hook detection driverscan Scan for driver objects _DRIVER_OBJECT dumpcerts Dump RSA private and public SSL keys dumpfiles Extract memory mapped and cached files envars Display process environment variables eventhooks Print details on windows event hooks filescan Scan Physical memory for _FILE_OBJECT pool allocations gahti Dump the USER handle type information gditimers Print installed GDI timers and callbacks gdt Display Global Descriptor Table getservicesids Get the names of services in the Registry and return Calculated SID getsids Print the SIDs owning each process handles Print list of open handles for each process hashdump Dumps passwords hashes (LM/NTLM) from memory hibinfo Dump hibernation file information hivedump Prints out a hive hivelist Print list of registry hives. hivescan Scan Physical memory for _CMHIVE objects (registry hives) hpakextract Extract physical memory from an HPAK file hpakinfo Info on an HPAK file idt Display Interrupt Descriptor Table iehistory Reconstruct Internet Explorer cache / history imagecopy Copies a physical address space out as a raw DD image imageinfo Identify information for the image impscan Scan for calls to imported functions kdbgscan Search for and dump potential KDBG values kpcrscan Search for and dump potential KPCR values ldrmodules Detect unlinked DLLs lsadump Dump (decrypted) LSA secrets from the registry machoinfo Dump Mach-O file format information malfind Find hidden and injected code mbrparser Scans for and parses potential Master Boot Records (MBRs) memdump Dump the addressable memory for a process memmap Print the memory map messagehooks List desktop and thread window message hooks mftparser Scans for and parses potential MFT entries moddump Dump a kernel driver to an executable file sample modscan Scan Physical memory for _LDR_DATA_TABLE_ENTRY objects modules Print list of loaded modules mutantscan Scan for mutant objects _KMUTANT netscan Scan a Vista, 2008 or Windows 7 image for connections and sockets patcher Patches memory based on page scans printkey Print a registry key, and its subkeys and values privs Display process privileges procexedump Dump a process to an executable file sample procmemdump Dump a process to an executable memory sample pslist Print all running processes by following the EPROCESS lists psscan Scan Physical memory for _EPROCESS pool allocations pstree Print process list as a tree psxview Find hidden processes with various process listings raw2dmp Converts a physical memory sample to a windbg crash dump screenshot Save a pseudo-screenshot based on GDI windows sessions List details on _MM_SESSION_SPACE (user logon sessions) shellbags Prints ShellBags info shimcache Parses the Application Compatibility Shim Cache registry key ssdt Display SSDT entries strings Match physical offsets to virtual addresses (may take a while, VERY verbose) svcscan Scan for Windows services symlinkscan Scan for symbolic link objects thrdscan Scan physical memory for _ETHREAD objects threads Investigate _ETHREAD and _KTHREADs timeliner Creates a timeline from various artifacts in memory timers Print kernel timers and associated module DPCs unloadedmodules Print list of unloaded modules userassist Print userassist registry keys and information userhandles Dump the USER handle tables vaddump Dumps out the vad sections to a file vadinfo Dump the VAD info vadtree Walk the VAD tree and display in tree format vadwalk Walk the VAD tree vboxinfo Dump virtualbox information vmwareinfo Dump VMware VMSS/VMSN information volshell Shell in the memory image windows Print Desktop Windows (verbose details) wintree Print Z-Order Desktop Windows Tree wndscan Pool scanner for tagWINDOWSTATION (window stations) yarascan Scan process or kernel memory with Yara signatures [/plain] Note that there are a lot of commands we can use to analyze the system memory. First we can list active processes by using the pslist command: [plain] # ./vol.py -f windows7.dump –profile=Win7SP1x86 pslist [/plain] After that we can use any number of commands to gather the information that we need.

Conclusion

In this article we’ve presented how we can dump memory of a Linux system and create our own profile that can be used together with Volatility to analyze memory. We’ve also dumped memory of a Qemu virtual machine and printed its processes. At such point, we can start looking for interesting information like passwords and certificates that security-unaware applications may have left in memory for an attacker to obtain.

Sources

Process Dumper LiME LinuxMemoryForensics The Volatility Framework