Inv Plan: Win5mem : WinXP memory image triage
Case: 20150124BSK : Suspicious IE/Java behaviour on workstation
Investigator: Ben S. Knowles (bsk@dfirnotes.org)
Response Phase: Identification
Refs: Problem reported to Helpdesk in ticket 1202, Incident case record 20150124BSK
Date/times of interest: Memory image acquired 2014-04-17 11:00:53 -0400
Evidence location: /cases/win5mem/winxp_java6-meterpreter.vmem, VMWare memory image
from 504.5 (2014) p42
Use Volatility imageinfo plugin to check which profile to use and verify Vol can read the memory image. Once that's settled we can build a script for a batch run, process the memory image for our first batch of results, and look at the data with Pandas.
In [4]:
!vol.py --plugins=/home/sosift/f/dfirnotes/ -f /cases/win5mem/winxp_java6-meterpreter.vmem --profile WinXPSP2x86 imageinfo
In [6]:
## Get setup to process memory with Volatility, analyse data with Pandas, chart with matplotlib
## Charting tips from https://datasciencelab.wordpress.com/2013/12/21/beautiful-plots-with-pandas-and-matplotlib/
import pandas as pd
%matplotlib inline
import matplotlib as mpl
import matplotlib.pylab as plt
##
case_folder = '/cases/win5mem/'
memimage = '/cases/win5mem/winxp_java6-meterpreter.vmem'
vol_profile = 'WinXPSP2x86' ## use vol.py imageinfo if you don't know this
## Assemble the volatility commands for batch execution in a shell
## start with sift3 volatility + custom modules sample
vol24 = '/usr/bin/vol.py --plugins=/home/sosift/f/dfirnotes/ '
vol_cmd = vol24 + '-f ' + memimage + ' --profile=' + vol_profile
## Configure plugins and output formats, completion flags:
vol_cmd_ps = vol_cmd + ' pscsv --output=csv ' + '> ' + case_folder + 'ps.csv' + ' && echo PS CSV Done!'
vol_cmd_conns = vol_cmd + ' connscan ' + '> ' + case_folder + 'connscan.txt' + ' && echo Connscan Done!'
vol_script = case_folder + 'volscript'
with open(vol_script, 'wb') as f:
f.write(vol_cmd_ps+'\n')
f.write(vol_cmd_conns)
In [81]:
! /bin/sh /cases/win5mem/volscript
Batch processing is complete. Let's pull our results in Pandas DataFrames so we can take a look, starting with the processes CSV file from the demo pscsv plugin. We can easily import CSV with Pandas and let it know which column is the date/time data on import, and then set the PID number field as our index. We use the Pandas df.info() function to see a summary of what we imported before continuing.
In [2]:
procs = pd.read_csv('/cases/win5mem/ps.csv', parse_dates=['Created'])
procs.set_index(['Pid'])
procs.info()
Here's quick histogram of processes by process name. Only svchost, Java, VmWare, and Internet Explorer have more than one instance.
In [28]:
# Create a figure of given size
fig = plt.figure(figsize=(12,8))
# Add a subplot
ax = fig.add_subplot(111)
# Remove grid lines (dotted lines inside plot)
ax.grid(False)
# Remove plot frame
ax.set_frame_on(False)
# Pandas trick: remove weird dotted line on axis
#ax.lines[0].set_visible(False)
# Set title
ttl = title='Process Counts'
# Set color transparency (0: transparent; 1: solid)
a = 0.7
# Create a colormap
customcmap = [(x/24.0, x/48.0, 0.05) for x in range(len(procs))]
## chart the data frame with these params
procs['Process'].sort_index().value_counts().plot(kind='barh', title=ttl, ax=ax, alpha=a)
plt.savefig('Process Counts.png', bbox_inches='tight', dpi=300)
Pandas can handle fixed width text tables almost as adroitly as CSV using the read_fwf function. We use it to load in the output of the standard Volatility connscan, set the Pid field as our index, and check import with info().
(FIXME) We need to get rid of one null line that is an import artifact.
In [31]:
conns = pd.read_fwf('/cases/win5mem/conns.txt')
conns.set_index(['Pid'])
conns.info()
Here is a quick histogram of the remote IP addresses in use, including the port numbers. Reviewing the x-axis we see common web service ports (80 and 443), Windows service ports (139), and some less obvious ones. High ports 1337, 4444, and 1648 may all be worth followup as they are less expected on a Windows XP system than the first set.
In [32]:
# Create a figure of given size
fig = plt.figure(figsize=(12,8))
# Add a subplot
ax = fig.add_subplot(111)
# Remove grid lines (dotted lines inside plot)
ax.grid(False)
# Remove plot frame
ax.set_frame_on(False)
# Pandas trick: remove weird dotted line on axis
#ax.lines[0].set_visible(False)
# Set title
ttl = title='Remote Connections'
# Set color transparency (0: transparent; 1: solid)
a = 0.7
# Create a colormap
customcmap = [(x/24.0, x/48.0, 0.05) for x in range(len(procs))]
## chart the data frame with these params
conns['Remote Address'].sort_index().value_counts().plot(kind='barh', title=ttl, ax=ax, alpha=a)
plt.savefig('Remote Connections.png', bbox_inches='tight', dpi=300)
Let's slice out just those IE processes and see who they were talking to. We pull the process IDs from the process data and use it to look for processes with connection in the connection data from connscan.
In [92]:
procs[procs.Process=="iexplore.exe"]
Out[92]:
In [34]:
## not all processes have connections, but this one does
ie_conns = conns[conns.Pid == '2576']
In [36]:
# Create a figure of given size
fig = plt.figure(figsize=(12,8))
# Add a subplot
ax = fig.add_subplot(111)
# Remove grid lines (dotted lines inside plot)
ax.grid(False)
# Remove plot frame
ax.set_frame_on(False)
# Pandas trick: remove weird dotted line on axis
#ax.lines[0].set_visible(False)
# Set title
ttl = title='IE Remote Connections'
# Set color transparency (0: transparent; 1: solid)
a = 0.7
# Create a colormap
customcmap = [(x/24.0, x/48.0, 0.05) for x in range(len(procs))]
## chart the data frame with these params
conns['Remote Address'].sort_index().value_counts()
ie_conns['Remote Address'].sort_index().value_counts().plot(kind='barh', title=ttl, ax=ax, alpha=a)
plt.savefig('IE Remote Connections.png', bbox_inches='tight', dpi=300)
We can see that IE was talking to several Internet addresses on web service ports and one local (RFC1918) address on 1337. And Java?
In [100]:
## not all processes have connections, this one does
java_conns = conns[conns.Pid=='3156']
java_conns['Remote Address'].sort_index().value_counts().plot(kind='bar')
Out[100]:
One Java process was also communicating with the unknown 1337 service on the local network.
In [69]:
procs
Out[69]:
In [38]:
conns
Out[38]:
Internet Explorer and Java processes were communicating with an unidentified services on a local network host. Those processes and the host they were communicating with are worth further investigation to get to the bottom of the supicious activity in the evidence presented.
In [102]:
procs[procs.Process=="iexplore.exe"]
Out[102]:
In [104]:
procs[procs.Process=="java.exe"]
Out[104]:
There are definite signs of supicious activity in the evidence gathered so far. Recommend proceding with response efforts in accordance with the IRP: Contain the desktop system and gather more evidence from other sources.