Tuesday, August 25, 2015

Volatility Updates Summer 2015

Summer 2015 has been quite a busy time for the memory forensics community. We wanted to write a quick update to talk about some recent events and research as well as upcoming news.

Conferences

Black Hat Vegas 2015

We wanted to again thank everyone who came out and supported us during Black Hat. Between our Arsenal demo, book signing, and party, we met hundreds of Volatility users and fans. Your support and enthusiasm is greatly appreciated. Come back next year for twice the champagne, twice the suite size, and twice the fun!

HTCIA International Conference (Orlando) 

We're putting on a lab session at HTCIA's International Conference in Orlando next week. You can also stop by the Volexity booth for a chance to win a free seat at any upcoming Windows Malware and Memory Forensics Training course.

Open Source Digital Forensics Conference (OSDFC) 2015

The Volatility team will once again be presenting the latest in memory forensic research at OSDFC 2015. This year we will be focusing on the anti-forensic capabilities of PlugX as well as new Volatility capabilities that can auto-detect them. We will also be discussing the results of the 2015 Volatility Plugin contest. 

OSDFC has a great lineup this year so you should try and attend. We hope to see many Volatility users while we are out there.

Research

A New Paper on OS X Memory Forensics

At DFRWS 2015, Dr. Golden Richard and I published a paper on OS X memory forensics entitled: Advancing OS X Rootkit Detection. The purpose of this paper was to document gaps in existing OS X rootkit detection techniques and then develop new methods, in the form of Volatility plugins, to close these gaps. The plugins introduced in the paper will be committed to GitHub in the coming weeks.

DFRWS had a number of good submissions this year, and we recommend browsing the program for other interesting forensics research.

Volatility vs Hacking Team

The malware used by Hacking Team to control victim's computers is known as Galileo RCS, and in a well done blog post, Joe Greenwood shows how to use Volatility to detect RCS in a number of ways.

RCS now joins a long list (Stuxnet, Careto, Flame, and more) of 'advanced', 'stealthy' malware that immediately falls to inspection by memory forensics.

Volatility at PyCon

At PyCon 2015, Ying Li showed how to use newly developed Volatility capabilities in order to find artifacts of Python scripts that were executing on the system. This was very interesting work, and we suggest watching the video of her talk.

Projects Building on Volatility

VolDiff

VolDiff is a project that compares the results of a number of Volatility plugins against two memory samples and automatically the reports the differences. Compared to manually running and comparing the plugins, this can save a substantial amount of time.

The purpose of VolDiff is to compare in-memory artifacts both before (clean state) and after (post-install state) an application, such as a malware sample, has executed. The new artifacts that appear post-installation can be immediately isolated for further analysis and/or for the creation of highly-effective IOCs.

If you wanted to get started with VolDiff then you should read the author's post on analyzing DarkComet with VolDiff.


Evolve

Evolve is an open source web interface to Volatility. It is under very active development and is constantly having new features added. Consult the README on GitHub for the latest features, and be sure to follow the tool's author on Twitter.

To see Evolve in action, check out a video showing the basic features here and advanced features here.

As much as we love the command line, it is sometimes nice to have a GUI visualize and shuffle data for you!


Plugin Contest

The 2015 Volatility Plugin Contest is underway and accepting submissions until October. The contest is a great way to win cash and other prizes, gain recognition in the community and become more familiar with Volatility and Python. We feature the research submitted to the contest on this blog, during conferences, presentations, and all throughout social media and our mailing lists.

New Volatility Capabilities


Windows 10 Support

While not merged in the official Volatility branch (yet), the Windows 10 branch is currently under active development. Nearly all of the plugins are working at the current time, and we would be very appreciative of any bug reports you may have when testing the branch. Please post any bugs to the GitHub issue tracker. Currently supported functionality includes process and kernel module listing, all pool scanning plugins (files, mutexes, processes, drivers, etc.), handles, DLLs, PE file extraction, process memory (VAD) parsing, service enumeration, cached file extraction, and memory signature scanning with Yara.


OS X 10.10.x Support and New Plugins

Volatility now has official support for OS X 10.10.4 and 10.10.5, which are the latest two versions. We have also tested Volatility on a preview release of 10.11, and it appears that all of the plugins work as expected. We will release an official profile for 10.11 once Apple releases debug kits (we are currently using special custom built profiles).

Volatility also has a new plugin named mac_get_profile. This plugin allows Volatility to auto-detect which profile (OS version) matches the given memory sample. To use this plugin you do NOT need any OS X profiles installed. Instead, you can run a fresh checkout of Volatility, determine the profile by using mac_get_profile, and then download the correct profile from our profiles repository.

To use mac_get_profile, simply pass the path to your memory sample as the -f option and then put mac_get_profile after it:
$ python vol.py -f <path to memory sample> mac_get_profile


Linux

Volatility Linux support has now been tested through kernel version 3.19. As many of the data structures do not change between versions, we expect that most or all of the plugins will work with bleeding edge developments kernels as well. Please file an issue if you encounter any bugs.


Memory Forensic Trainings

Our memory forensics training class in Amsterdam is now SOLD OUT.  We appreciate the support and word of mouth praise from past attendees as well as fans of the project.

Our current course is 5 days of memory forensics and malware analysis training against Windows systems. Full information on the course, as well as upcoming dates and locations, can be found here. If our current set of public offerings does not work for your company then please contact us about conducting a private training at one of your facilities.

Saturday, August 1, 2015

Recovering TeamViewer (and other) Credentials from RAM with EditBox

I recently stumbled upon the TeamViewer-dumper-in-CPP project, which shows just how easy it is to recover TeamViewer IDs, passwords, and account information from a running TV instance by enumerating child windows (on a live machine). The method is based on sending a WM_GETTEXT message to the TV GUI controls that contain the credentials. In particular, we're looking for the two fields under the "Allow Remote Control" heading (Your ID: 567 744 114 and Password q16jp7).


The equivalent of TeamViewer-dumper for memory forensics analysts is Adam Bridge's EditBox plugin for Volatility. Adam's submission won 3rd place in last years Volatility Plugin Contest, but I still feel like many people don't realize the full potential of this plugin. While TeamViewer-dumper is specific to TV, the EditBox plugin recovers text from editbox controls for all applications (that depend on Microsoft Common Controls) across all user sessions (local or remote via RDP/VNC), even for "special" editboxes that contain passwords and show up as asterisks on the screen.

Here's an example of the editbox plugin's output when TV is running:

$ python vol.py -f memory.dmp --profile=Win7SP1x64 editbox Volatility Foundation Volatility Framework 2.4 41 processes to check. ******************************************************* Wnd context : 1\WinSta0\Default Window title : - pointer-to tagWND : 0xfffff900c062b510 [0x67dc6510] pid : 2524 imageFileName : TeamViewer.exe wow64 : Yes atom_class : 6.0.7601.17514!Edit address-of cbwndExtra: 0xfffff900c062b5f8 [0x67dc65f8] value-of cbwndExtra : 4 (0x4) address-of WndExtra : 0xfffff900c062b638 [0x67dc6638] value-of WndExtra : 0x46e0480 [0x67302480] pointer-to hBuf : 0x46af000 [0x67e28000] hWnd : 0x10228 parenthWnd : 0x1020a nChars : 6 (0x6) selStart : 0 (0x0) selEnd : 0 (0x0) text_md5 : 7a62c5fa901ff86a1562b9c7075674f8 isPwdControl : No q16jp7 ******************************************************* Wnd context : 1\WinSta0\Default Window title : - pointer-to tagWND : 0xfffff900c062b150 [0x67dc6150] pid : 2524 imageFileName : TeamViewer.exe wow64 : Yes atom_class : 6.0.7601.17514!Edit address-of cbwndExtra: 0xfffff900c062b238 [0x67dc6238] value-of cbwndExtra : 4 (0x4) address-of WndExtra : 0xfffff900c062b278 [0x67dc6278] value-of WndExtra : 0x46a0f98 [0x689d7f98] pointer-to hBuf : 0x46bf390 [0x6769d390] hWnd : 0x10224 parenthWnd : 0x1020a nChars : 11 (0xb) selStart : 0 (0x0) selEnd : 0 (0x0) text_md5 : b45dfe635940d5490276a5ae41e1422f isPwdControl : No 567 744 114 ******************************************************* Wnd context : 1\WinSta0\Default Window title : - pointer-to tagWND : 0xfffff900c0631a50 [0x552cea50] pid : 2524 imageFileName : TeamViewer.exe wow64 : Yes atom_class : 6.0.7601.17514!Edit address-of cbwndExtra: 0xfffff900c0631b38 [0x552ceb38] value-of cbwndExtra : 4 (0x4) address-of WndExtra : 0xfffff900c0631b78 [0x552ceb78] value-of WndExtra : 0x4781678 [0x6648b678] pointer-to hBuf : 0x46fac80 [0x68493c80] hWnd : 0x801aa parenthWnd : 0x70186 nChars : 15 (0xf) selStart : 0 (0x0) selEnd : 0 (0x0) text_md5 : 2cbe388f82d11af92a8d4950e24db799 isPwdControl : No WIN-948O8I1DO91 [snip]
As you can see, the ID, password, computer name, and various other fields are recovered. This is a powerful way to reconstruct the state of the user interface from memory. Although technically you could also find the values by brute force string scanning in process memory, but there's no need to brute force when you can use a structured, focused approach. Kudos to Adam for creating such a useful extension to last year's plugin contest.

Thursday, July 16, 2015

The 2015 Volatility Plugin contest is now live!

This is a quick update to announce that the 2015 Volatility Plugin contest is now live and accepting submissions until October 1st. Winners of this year's contest will be receiving over $2,000 in cash prizes as well as plenty of Volatility swag (t-shirts, stickers, etc.).

The purpose of the contest is to encourage open memory forensics research and development. It is a great opportunity for students to become familiar with memory forensics, develop a master's thesis or PhD project, as well as gain experience that will be very desirable by future employers. For those already in the field, submitting to the contest is a great way to gain experience and visibility in the memory forensics community. After the contest is over we promote the work in our conference presentations, blogs, and social media.

If you are looking for inspiration or to see the past winners, please check out the pages from 2013 and 2014. You will find projects that allow for inspection of virtual machines guests from the view of the host, recovery of in-memory browser artifacts, methods to detect stealthy rootkits, and much more.

If you have any questions please feel free to reach out to us. 

We are looking forward to another year of innovative open source research!

Monday, July 13, 2015

Volatility at Black Hat USA & DFRWS 2015!

Due to another year of open research and giving back to the open source community, Volatility will have a strong presence at both Black Hat USA and DFRWS 2015. This includes presentations, a book signing, and even a party!

At Black Hat, the core Volatility Developers (@4tphi, @attrc, @gleeda, and @iMHLv2) will be partaking in a number of events including:
  • Demoing Volatility at Black Hat Arsenal. This will include new plugins targeted at the PlugX malware, showing how to write simple, but effective Volatility plugins, and more!
  • Book signing for The Art of Memory Forensics starting at 11:10AM on Wednesday in the Black Hat book store. All four authors will be present, so be sure to bring your book along or purchase a copy on-site in the bookstore.
  • Volatility Happy Hour: This will be an open bar party where you can meet our team, bring books to be signed, and get Volatility swag all while enjoying tasty beverages. You must register (free) if you wish to attend! Note that the party will be at MGM Grand.
Friends of Volatility will also be leading a number of events at Black Hat including Briefing presentations from Jonathan Brossardjduck, and Alex Ionescu as well as Arsenal Demos from Brian Baskin, Marc Ochsenmeier, David Cowen, and Takahiro Haruyama.

At DFRWS, Dr. Golden Richard will be presenting a paper that he and I wrote: Advancing Mac OS X Rootkit Detection. In this paper, we present several new methods to detect rootkits on OS X systems through memory forensic analysis. All the of the plugins described in the paper will be incorporated into Volatility after the conference. 

Also, at DFRWS, Joe Sylve and Vico Marziale will be leading a workshop on creating forensics tools in Go. If you have never seen Go before, or want to gain some hands-on experience, then we recommend checking it out.

And finally, be sure to check out the "Finding your naughty BITS" presentation by Matthew Geiger, who has been a long time friend of the project.

We hope to see everyone at these events, and we are looking forward to an exciting August! 

Wednesday, June 3, 2015

Volshell Quickie: The Case of the Missing Unicode Characters

The other day someone reached out to me because they had a case that involved files with Arabic names.  Unfortunately the filenames were only question marks when using filescan or handles, so I set out to figure out why.

In order to figure out why, I created a few files with Hebrew names (which I can read and write, so I can verify if it is correct) and Arabic names (which was just me tapping on the keyboard, so they don't say anything). After creating them, I interacted with them to make sure they'd show up in filescan. Below you can see the filescan results:
[snip] $ python vol.py -f Win7x86.vmem --profile=Win7SP1x86 filescan 0x000000003d7008d0 16 0 RW-rw- \Device\HarddiskVolume2\Users\user\Desktop\????.txt 0x000000003ddfef20 18 1 RW-r-- \Device\HarddiskVolume2\Windows\Tasks\SCHEDLGU.TXT 0x000000003def9340 16 0 RW-r-- \Device\HarddiskVolume2\Users\user\Desktop\????????????????????.txt [snip]
In order to understand how the filename is output, you can look at the code in filescan:
for file in data: header = file.get_object_header() self.table_row(outfd, file.obj_offset, header.PointerCount, header.HandleCount, file.access_string(), str(file.file_name_with_device() or ''))
The function file_name_with_device() is defined in volatility/plugins/overlays/windows/windows.py and the relevant part is highlighted in red:
class _FILE_OBJECT(obj.CType, ExecutiveObjectMixin): """Class for file objects""" def file_name_with_device(self): """Return the name of the file, prefixed with the name of the device object to which the file belongs""" name = "" if self.DeviceObject: object_hdr = obj.Object("_OBJECT_HEADER", self.DeviceObject - self.obj_vm.profile.get_obj_offset("_OBJECT_HEADER", "Body"), self.obj_native_vm) if object_hdr: name = "\\Device\\{0}".format(str(object_hdr.NameInfo.Name or '')) if self.FileName: name += str(self.FileName) return name
So we can take a look at this in volshell:
1 $ python vol.py -f Win7x86.vmem --profile=Win7SP1x86 volshell 2 [snip] 3 >>> file = obj.Object("_FILE_OBJECT", offset = 0x000000003d7008d0, vm = addrspace().base, native_vm = addrspace()) 4 >>> print file.FileName 5 \Users\user\Desktop\????.txt 6 7 >>> file2 = obj.Object("_FILE_OBJECT", offset = 0x000000003def9340, vm = addrspace().base, native_vm = addrspace()) 8 >>> print file2.FileName 9 \Users\user\Desktop\????????????????????.txt
On line 3 we create a _FILE_OBJECT object. We know the offset where this object resides (0x000000003d7008d0) from filescan. Since this object was obtained from the physical address space, we specify this by setting vm to addrspace().base, or the physical layer, since this is a raw memory sample. Since the _FILE_OBJECT's native address space is virtual, we specify this as well: native_vm = addrspace(). At this point we have instantiated a _FILE_OBJECT in a variable called "file". We then print out the FileName member on line 5 and see its output on line 6. We follow the same process for the second file, except we save the object as "file2". As you can see, the output is not very helpful. So now we need to know what type of member, FileName is. In order to accomplish this, we need to look at the vtypes in the volatility/plugins/overlays/windows/win7_sp1_x86_vtypes.py file:
'_FILE_OBJECT' : [ 0x80, { 'Type' : [ 0x0, ['short']], [snip] 'FileName' : [ 0x30, ['_UNICODE_STRING']], [snip]
We have some functionality added to this type in volatility/plugins/overlays/windows/windows.py:
class _UNICODE_STRING(obj.CType): [snip] def v(self): """ If the claimed length of the string is acceptable, return a unicode string. Otherwise, return a NoneObject. """ data = self.dereference() if data: return unicode(data) return data def dereference(self): length = self.Length.v() if length > 0 and length <= 1024: data = self.Buffer.dereference_as('String', encoding = 'utf16', length = length) return data else: return obj.NoneObject("Buffer length {0} for _UNICODE_STRING not within bounds".format(length)) [snip] def __format__(self, formatspec): return format(self.v(), formatspec) def __str__(self): return str(self.dereference()) [snip]
We know that the file_name_with_device() function uses str() in order to transform the _UNICODE_STRING into something readable and if we look at the overridden __str__() operator in the above code, we see that it uses the dereference() function. The dereference() function never casts the data as unicode, however, so the data is printed incorrectly. If we look at the above v() function, we see that there is a call to dereference() and that the resulting data is case as unicode, so let's see if we get valid data back by calling that function instead:
>>> print file.FileName.v() \Users\user\Desktop\שלום.txt >>> print file2.FileName.v() \Users\user\Desktop\تهحححتهحححتهحححتهححح.txt
Success! So let's modify the __str__() operator to use v() instead and see if that fixes filescan:
[snip] def __str__(self): return str(self.v()) [snip]
Now let's examine the filescan data:
0x000000003d7008d0 16 0 RW-rw- \Device\HarddiskVolume2\Users\user\Desktop\שלום.txt 0x000000003ddfef20 18 1 RW-r-- \Device\HarddiskVolume2\Windows\Tasks\SCHEDLGU.TXT 0x000000003def9340 16 0 RW-r-- \Device\HarddiskVolume2\Users\user\Desktop\تهحححتهحححتهحححتهححح.txt
Success! Just to make dually sure, I then created a user with a Hebrew name: גלידה, and created some files with Hebrew characters as well. If we look back to the file_name_with_device() function, you'll see that the complete file path is populated by using the NameInfo optional header (name = "\\Device\\{0}".format(str(object_hdr.NameInfo.Name or ''))). If you look in the volatility/plugins/overlays/windows/win7.py file, you'll see the following definition:
class _OBJECT_HEADER(windows._OBJECT_HEADER): [snip] optional_header_mask = (('CreatorInfo', '_OBJECT_HEADER_CREATOR_INFO', 0x01), ('NameInfo', '_OBJECT_HEADER_NAME_INFO', 0x02), ('HandleInfo', '_OBJECT_HEADER_HANDLE_INFO', 0x04), ('QuotaInfo', '_OBJECT_HEADER_QUOTA_INFO', 0x08), ('ProcessInfo', '_OBJECT_HEADER_PROCESS_INFO', 0x10))
Now we know the object to find in the types file in order to figure out what type Name is. Look in volatility/plugins/overlays/windows/win7_sp1_x86_vtypes.py:
'_OBJECT_HEADER_NAME_INFO' : [ 0x10, { 'Directory' : [ 0x0, ['pointer', ['_OBJECT_DIRECTORY']]], 'Name' : [ 0x4, ['_UNICODE_STRING']], 'ReferenceCount' : [ 0xc, ['long']], } ],
Since Name is of the same type (_UNICODE_STRING), we should be covered. In the words of Al Bundy, "Let's rock":
$ python vol.py -f Win7x86.vmem --profile=Win7SP1x86 filescan [snip] 0x000000003e8fb1c0 2 0 RW-rw- \Device\HarddiskVolume1\Users\גלידה\Desktop\עצם.txt 0x000000003f83c038 2 0 RW-rw- \Device\HarddiskVolume1\Users\גלידה\AppData\Roaming\Microsoft\Windows\Recent\עצם.lnk [snip]
Success! A lot of other objects use _UNICODE_STRINGs, including mutants, registry paths and symbolic links. So this was an important fix.

Changes have already been reflected in the master branch of Volatility. We hope that you have enjoyed this not so short, quickie ;-)

Friday, May 15, 2015

Using mprotect(.., .., PROT_NONE) on Linux

After deciding to revisit some old code of mine (ok, very old), I realized that there was something different about how Linux was allocating pages of data I wanted to hide.   At first, I was glad that I couldn't see the data using yarascan, but then I realized that I was unable to access the memory regions at all in linux_volshell to verify that they were, in fact, obfuscated. So I decided to take a look at using a smaller, stripped down program. Below is one such example, comments are included to explain what is happening:

int main( int argc, char *argv[]){ // pid: the process ID of this process // so we can print it out int pid; pid = getpid(); //size: an integer to hold the current page size int size; size = getpagesize(); //[1] create two pointers in order to allocate //memory regions char *buffer; char *buffer2; //unprotected buffer: //allocate memory using mmap() buffer2 = (caddr_t) mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0,0); //[2] put some characters in the allocated memory //we're setting these characters one at a time in order //to avoid our strings being detected from the binary itself buffer2[0] = 'n'; buffer2[1] = 'o'; buffer2[2] = 't'; buffer2[3] = ' '; buffer2[4] = 'h'; buffer2[5] = 'e'; buffer2[6] = 'r'; buffer2[7] = 'e'; //protected buffer: //allocate memory with mmap() like before buffer = (caddr_t) mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0,0); //[2] put some characters in the allocated memory //we're setting these characters one at a time in order //to avoid our strings being detected from the binary itself buffer[0] = 'f'; buffer[1] = 'i'; buffer[2] = 'n'; buffer[3] = 'd'; buffer[4] = ' '; buffer[5] = 'm'; buffer[6] = 'e'; //[3] protect the page with PROT_NONE: mprotect(buffer, size, PROT_NONE); //[4] print PID and buffer addresses: printf("PID %d\n", pid); printf("buffer at %p\n", buffer); printf("buffer2 at %p\n", buffer2); //spin until killed so that we know it's in memory: while(1); return 0; }
Now we'll just compile the above program and run it. In short, the above program [1] creates two buffers, [2] places characters in these buffers, [3] then calls mprotect() on one of them with PROT_NONE; [4] the program then prints out its process ID and the virtual addresses of the aforementioned buffers:

$ ./victim PID 29620 buffer at 0x7f2bec9a1000 buffer2 at 0x7f2bec9a2000
Let's set up a config file so that we don't have to type as much:

$ cat linux.config [DEFAULT] LOCATION=file:///Path/to/Virtual%20Machine/Linux%20Mint%20Cinnamon/Mint%2064-bit-d583834d.vmem PROFILE=LinuxLinuxMintCinnamonx64x64 PID="29620"
If we try to search for the strings we placed in the buffers we get:

$ python vol.py --conf-file=linux.config linux_yarascan -Y "not here" Volatility Foundation Volatility Framework 2.4 Task: victim pid 29620 rule r1 addr 0x7f2bec9a2000 0x7f2bec9a2000 6e 6f 74 20 68 65 72 65 00 00 00 00 00 00 00 00 not.here........ 0x7f2bec9a2010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x7f2bec9a2020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [snip] $ python vol.py --conf-file=linux.config linux_yarascan -Y "find me" Volatility Foundation Volatility Framework 2.4

Well that was disappointing, we couldn't find the "find me" string. What you would expect, is to be able to access the memory contents using Volatility. Let's use the linux_volshell plugin to explore the victim process' memory and see if we can access the memory addresses (given to us from the program at run time) directly. First we'll examine the contents at 0x7f2bec9a2000:

$ python vol.py --conf-file=linux.config linux_volshell Volatility Foundation Volatility Framework 2.4 >>> Current context: process victim, pid=29620 DTB=0x3cfb1000 >>> db(0x7f2bec9a2000) 0x7f2bec9a2000 6e 6f 74 20 68 65 72 65 00 00 00 00 00 00 00 00 not.here........ 0x7f2bec9a2010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x7f2bec9a2020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x7f2bec9a2030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x7f2bec9a2040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x7f2bec9a2050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x7f2bec9a2060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x7f2bec9a2070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
As we see, we have the contents that we'd expect. Now to try to access the other memory location:

>>> db(0x7f2bec9a1000) Memory unreadable at 7f2bec9a1000
We see that we've been rejected. After a bit of investigation, we see that the point of failure is in the entry_present() function in the amd64.py address space. In order to find the value of the entry that failed, we'll print it out. First we'll add a print statement to entry_present():

def entry_present(self, entry): if entry: if (entry & 1): return True arch = self.profile.metadata.get('os', 'Unknown').lower() # The page is in transition and not a prototype. # Thus, we will treat it as present. if arch == "windows" and ((entry & (1 << 11)) and not (entry & (1 << 10))): return True # we want a valid entry that hasn't been found valid: print hex(entry) return False

Now let's see what the entry is:
$ python vol.py --conf-file=linux.config linux_yarascan -Y "find me" Volatility Foundation Volatility Framework 2.4 0x2681d160
So let's look a little closer at the page table entry:

>>> print "{0:b}".format(0x2681d160) 100110100000011101000101100000
The way we read this is from right to left.  The entry_present() function checks the 0th bit to see if the entry is present. In this case the bit is not set (0); therefore this function returns False.

At this point, I decided to take a look at the Linux source code to see how mprotect() is actually implemented. As it turns out, the _PAGE_PRESENT bit is cleared when mprotect(...PROT_NONE) is called on a page and the _PAGE_PROTNONE bit is set [3]. Looking at how _PAGE_PROTNONE is defined [4][5][6] we'll see that it's actually equivalent to the global bit (8th bit) [1][2]. So let's look at our page table entry again, we'll notice that the 8th bit is indeed 1:

>>> print "{0:b}".format(0x2681d160) 100110100000011101000101100000


So let's patch the entry_present() function with our findings:

def entry_present(self, entry): if entry: if (entry & 1): return True arch = self.profile.metadata.get('os', 'Unknown').lower() # The page is in transition and not a prototype. # Thus, we will treat it as present. if arch == "windows" and ((entry & (1 << 11)) and not (entry & (1 << 10))): return True # Linux pages that have had mprotect(...PROT_NONE) called on them # have the present bit cleared and global bit set if arch == "linux" and ((entry & (1 << 8))): return True return False


Let's see if we get anything back:
$ python vol.py --conf-file=linux.config linux_yarascan -Y "find me" Volatility Foundation Volatility Framework 2.4 Task: victim pid 29620 rule r1 addr 0x7f2bec9a1000 0x7f2bec9a1000 66 69 6e 64 20 6d 65 00 00 00 00 00 00 00 00 00 find.me......... 0x7f2bec9a1010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x7f2bec9a1020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [snip]

Success! So now we're able to see the "forbidden" string that we couldn't access before.  This goes to show that sometimes you have to dig a little into "why" something is not working as expected. In this case, we lucked out and had source code to examine, but sometimes things are not as easy as all that. Both intel.py and amd64.py have been patched in order to accommodate memory sections that have had mprotect() called on them with PROT_NONE.

References

[1] AMD64 Architecture Programmer's Manual Volume 2: System Programming http://developer.amd.com/wordpress/media/2012/10/24593_APM_v21.pdf

Monday, March 16, 2015

Windows Malware and Memory Forensics Training in the UK

Windows Malware and Memory Forensics Training by The Volatility Project is the only memory forensics course officially designed, sponsored, and taught by the Volatility developers. One of the main reasons we made Volatility open-source is to encourage and facilitate a deeper understanding of how memory analysis works, where the evidence originates, and how to interpret the data collected by the framework's extensive set of plugins. Now you can learn about these benefits first hand from the developers of the most powerful, flexible, and innovative memory forensics tool.

Our last public class in the UK sold out, so we are back again! This training is organized and hosted by CCL Group, the UK's largest provider of digital forensics.

Details

Location: Stratford-Upon-Avon, United Kingdom
Cost: £ 2595 + VAT (lunch provided)
​Dates: Monday June 1st - Friday June 5th 2015
Times: 9 AM - 5 PM daily
Instructors: Michael Ligh, Jamie Levy, Andrew Case 
View this course's full page

Booking

For bookings, please contact training@cclgroupltd.com or call 01789 261200 (UK).

Other Courses

The following courses are also open for registration.