F-Response + Volatility = <3

This really is a match made in heaven. F-Response is really slick from a remote memory acquisition standpoint. Combine that with Volatility and you have an easy 30-minute meal recipe for memory forensics and incident response.

I set F-Response up to allow me to connect to a domain-joined machine on my network by deploying the F-Response agent from F-Response Enterprise. F-Response has a great mission guide on how to accomplish this with a Windows target.

Using my Kali machine on the same subnet, I was able to connect to the system using iscsiadm (which is also what the F-Response examiner client uses on Windows, but on Linux all you have to do is apt-get iscsi, do a little configuration work, and you're good to go).

Once the F-Response agent is deployed on the system you want to analyze, you can start working on configuring your analysis host (in my case, the Kali machine with Volatility installed on it) to handle the connection.

According to a blog post over at F-Response, you first need to set up an interface for a given connection. So make yourself an ifaces folder:

mkdir /etc/iscsi/ifaces

Within there, we'll use the iscsiadm command to generate an interface config file for each connection we want to make using iscsi.

iscsiadm -m iface -I iface0 --op=new

We then set the MAC address of the analysis machine in the newly created config:

iscsiadm -m iface -I iface0 --op=update -n iface.hwaddress -v AA:BB:CC:DD:EE:FF

The only remaining thing to do is to configure iscsi with the appropriate credentials to connect to the F-Response agent that you set up during the initial F-Response deployment process. The configuration is in /etc/iscsi/iscsid.conf and you'll want to update both of these sections:

# To enable CHAP authentication set node.session.auth.authmethod
# to CHAP. The default is None.
node.session.auth.authmethod = CHAP

# To set a CHAP username and password for initiator
# authentication by the target(s), uncomment the following 	lines:
node.session.auth.username = grayhatninja
node.session.auth.password = Sup3rS3cret!

# To enable CHAP authentication for a discovery session to the target
# set discovery.sendtargets.auth.authmethod to CHAP. The default is None.
discovery.sendtargets.auth.authmethod = CHAP

# To set a discovery session CHAP username and password for the initiator
# authentication by the target(s), uncomment the following lines:
discovery.sendtargets.auth.username = grayhatninja
discovery.sendtargets.auth.password = Sup3rS3cret!

Good. Now we're set up to discover available iscsi targets and connect to them:

iscsiadm -m discovery -t st -p 10.40.2.73 -P 1

That will yield results that look like this:

root@valvalis:/etc/iscsi# iscsiadm -m discovery -t st -p 10.40.2.73 -P 1
Target: iqn.2008-02.com.f-response.dummyhostname:disk-0
	Portal: 10.40.2.73:3260,1
		Iface Name: iface0
Target: iqn.2008-02.com.f-response.dummyhostname:vol-c
	Portal: 10.40.2.73:3260,1
		Iface Name: iface0
Target: iqn.2008-02.com.f-response.dummyhostname:pmem
	Portal: 10.40.2.73:3260,1
		Iface Name: iface0

So, now that you know what iscsi targets are available on the system. We're doing memory analysis so we'll first try and map the pmem target since that's the physical memory F-Response found.

iscsiadm -m node -T iqn.2008-02.com.f-response.dummyhostname:pmem -l

And we get this:

Logging in to [iface: iface0, target: iqn.2008-02.com.f-response.dummyhostname:pmem, portal: 10.40.2.73,3260] (multiple)
Login to [iface: iface0, target: iqn.2008-02.com.f-response.dummyhostname:pmem, portal: 10.40.2.73,3260] successful.

So let's take a look at our disks:

root@valvalis:/etc/iscsi# fdisk -l
Disk /dev/sda: 42.9 GB, 42949672960 bytes
255 heads, 63 sectors/track, 5221 cylinders, total 83886080 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00050374

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048      499711      248832   83  Linux
/dev/sda2          501758    83884031    41691137    5  Extended
/dev/sda5          501760    83884031    41691136   8e  Linux LVM

Disk /dev/mapper/valvalis-root: 40.9 GB, 40907046912 bytes
255 heads, 63 sectors/track, 4973 cylinders, total 79896576 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/mapper/valvalis-root doesn't contain a valid partition table

Disk /dev/mapper/valvalis-swap_1: 1782 MB, 1782579200 bytes
255 heads, 63 sectors/track, 216 cylinders, total 3481600 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/mapper/valvalis-swap_1 doesn't contain a valid partition table
Note: sector size is 4096 (not 512)

Disk /dev/sdb: 5033 MB, 5033164800 bytes
155 heads, 62 sectors/track, 127 cylinders, total 1228800 sectors
Units = sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disk identifier: 0x00000000

Disk /dev/sdb doesn't contain a valid partition table

Our last entry /dev/sdb is our memory. So the next step is to image that memory to a physical file located on our analysis machine using dc3dd. This command forensically copies the image to my machine (note the md5 hashes).

mkdir /cases
dc3dd if=/dev/sdb of=/cases/dummyhostname.img hash=md5 hof=/cases/dummyhostname.md5

dc3dd 7.1.614 started at 2014-09-04 13:02:59 -0700
compiled options:
command line: dc3dd if=/dev/sdb of=/cases/dummyhostname.img hash=md5 hof=/cases/dummyhostname.md5
device size: 1228800 sectors (probed)
sector size: 4096 bytes (probed)
5033164800 bytes (4.7 G) copied (100%), 1277.95 s, 3.8 M/s                    
output hashing (100%)                                                         

input results for device `/dev/sdb':
   1228800 sectors in
   0 bad sectors replaced by zeros
   69262c7c02b315a10fb80ad59a81d218 (md5)

output results for file `/cases/dummyhostname.img':
   1228800 sectors out

output results for file `/cases/dummyhostname.md5':
   1228800 sectors out
   [ok] 69262c7c02b315a10fb80ad59a81d218 (md5)

dc3dd completed at 2014-09-04 13:24:17 -0700

Excellent! We successfully imaged the physical memory of our subject to our analysis machine. Now all we need to do is point Volatility at our image and we're in business.

root@valvalis:/usr/share/volatility_2.4/volatility# ./vol.py imageinfo -f /cases/dummyhostname.img 
Volatility Foundation Volatility Framework 2.4
Determining profile based on KDBG search...

      Suggested Profile(s) : Win7SP0x64, Win7SP1x64, Win2008R2SP0x64, Win2008R2SP1x64
                 AS Layer1 : AMD64PagedMemory (Kernel AS)
                 AS Layer2 : FileAddressSpace (/cases/na00034l.img)
                  PAE type : No PAE
                       DTB : 0x187000L
                      KDBG : 0xf80002c540a0
      Number of Processors : 4
 Image Type (Service Pack) : 1
            KPCR for CPU 0 : 0xfffff80002c55d00L
            KPCR for CPU 1 : 0xfffff88003307000L
            KPCR for CPU 2 : 0xfffff88003377000L
            KPCR for CPU 3 : 0xfffff880033e7000L
         KUSER_SHARED_DATA : 0xfffff78000000000L
       Image date and time : 2014-09-04 20:03:00 UTC+0000
 Image local date and time : 2014-09-04 13:03:00 -0700

You can see that Volatility suggests profiles for us to use. I happen to know this is a Win7SP1x64 machine so I'll go ahead and run a Volatility plugin against our image using that profile:

root@valvalis:/usr/share/volatility_2.4/volatility# ./vol.py psxview -f /cases/dummyhostname.img --profile=Win7SP1x64
Volatility Foundation Volatility Framework 2.4
Offset(P)          Name                    PID pslist psscan thrdproc pspcid csrss session deskthrd ExitTime
------------------ -------------------- ------ ------ ------ 	-------- ------ ----- ------- -------- --------
0x0000000127ac5060 svchost.exe            1188 True   True   False    True   True  True    False    
0x0000000126842b30 unsecapp.exe           3036 True   True   False    True   True  True    False    
0x0000000126f0b060 WmiPrvSE.exe           2096 True   True   False    True   True  True    False
.
.
.
0x000000012bf64b30 f-response-ent         7760 False  True   False    True   True  True    False

You can see that the F-Response agent shows up in the list (psxview is a plugin that reveals hidden processes) but its value is "False" in the pslist column, indicating that it's hidden in the Processes tab of Task Manager. A quick look on my target system reveals this is true.

Make sure you check out all of the plugins Volatility has to offer by running ./vol.py -h

Now that you've acquired the physical memory and you don't need your iscsi target for anything else, simply disconnect. Since we're only connected to one target, we can simply issue the following command which will disconnect us from all iscsi targets.

iscsiadm -m node -u

And you're out.

One note that might save you some heartache. I first tried this exercise using a virtual machine as the subject under analysis. Despite joining the VM to the domain, successfuly deploying the F-Response agent and successfully (I think) connecting with iscsi I could never get Volatility to work with the resulting image. I could successfully generate imageinfo with the correct profile suggestions and I could even run strings against the image to find signatures I knew would be present in the image and yet Volatility plugins would never work quite right.

In this case, I've split my workflow. If our subject is a VM, just use the vmem or snapshot files with Volatility (or, use a program like Mandiant Memoryze to capture the memory). If our subject is bare metal, use F-Response.