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.