By Guest Blogger Dave Kleiman:
Recently I had a need to check a network consisting of a few hundred systems in order to identify systems that had certain USB devices attached. There was not a need to check for “deleted” registry keys or unallocated space in the registry database. I needed to collect the standard USB keys, and compare them to a list of “Friendly Names” and “Serial Numbers” provided to me.
Standard keys I collected:
\HKLM\SYSTEM\ControlSet001\Enum\USBSTOR
\HKLM\SYSTEM\ControlSet001\Enum\USB
\HKLM\SYSTEM\MountedDevices
\HKLM\SYSTEM\ControlSet001\Control\DeviceClasses\{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
Additionally, I wanted to collect the times stamps for each respective registry entry. The challenge was to do this quickly without having to traverse a building to each office and collect them direct with a standard forensic tool.
My solution, Log Parser. That is right Log Parser(r), a free tool from Microsoft (http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07) that will parse the File System, Registry, and whole lot more.
Log Parser allows for variables in scripts. I created a script for each registry key I wanted to retrieve, and added a variable so I could enter the Host name for each.
First, I told Log Parser what I wanted values I wanted to retrieve from each registry key with a SELECT statement (Note I chose select 2000 for these scripts, you can change that number to as much or as little as you see fit, in this the top 2000 entries are retrieved):
SSELECT TOP 2000
ComputerName,
Path,
KeyName,
Valuename,
ValueType,
Value,
LastWriteTime
Then I indicated the output with the INTO statement and utilized an asterisk (*) to allow it to append the variable name to each file name
INTO *-USBSTOR.csv
Finally the FROM statement tells Log Parser what key to retrieve, and the variable %NAME% allows for entry of a Hostname at the command prompt.
FROM \\%NAME%\HKLM\SYSTEM\ControlSet001\Enum\USBSTOR
You can download the easy to use scripts HERE.
Unzip the package into a directory.
Drop down to a command prompt and type:
logparser file:_DeviceClasses.sql?name=HostA
logparser file:_MountedDevice.sql?name=HostA
logparser file:_USBSTOR.sql?name=HostA
logparser file:_USB.sql?name=HostA
Continue to do this for each Host, and it will return and individual CSV for each script separated by Host Name as outlined below:
HostA.network.local-DeviceClass.csv
HostA.network.local-MountedDevices.csv
HostA.network.local-USBSTOR.csv
HostA.network.local-USB.csv
I have many Log Parser scripts made for Forensics and the instructions on how to use them available on my website: http://www.computerforensicexaminer.com/computer-forensics-expert-florida-miami-palm-beach-lauderdale-dave-kleiman-forensic-training-files/
Respectfully, Dave Kleiman – http://www.ComputerForensicExaminer.com – sans@davekleiman.com

One Comment
I wrote a meterpreter script which can be used to pull the USB device information from a system.
[code]
#
# This is a Meterpreter script designed to be used by the Metasploit Framework
#
# Meterpreter script for pulling forensics data from registry for any USB device
# connected to system
#
# Provided by Dimitrios Kapsalis
# Verion: 0.1
require 'fileutils'
#Function for writing data to a file
def m_filewrt(file2wrt, data2wrt)
output = ::File.open(file2wrt, "a")
data2wrt.each_line do |d|
output.puts(d)
end
output.close
end
# ====================================================================================================================================
# Checking for UAC
# ====================================================================================================================================
def m_uaccheck(session)
uac = false
winversion = session.sys.config.sysinfo
if winversion['OS']=~ /Windows Vista/ or winversion['OS']=~ /Windows 7/
if session.sys.config.getuid != "NT AUTHORITY\\SYSTEM"
begin
print_status("Checking if UAC is enabled .....")
key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System')
if key.query_value('Identifier') == 1
print_status("UAC is Enabled")
uac = true
end
key.close
rescue::Exception => e
print_status("Error Checking UAC: #{e.class} #{e}")
end
end
end
return uac
end
# ====================================================================================================================================
# Print message to file on target
# ====================================================================================================================================
def m_writetofile(session,file,message)
cmd = "cmd /c echo #{message} >> #{file}"
m_exec(session, cmd)
end
# ====================================================================================================================================
# Delete a file (meterpreter has no unlink API yet)
# ====================================================================================================================================
def m_unlink(session, path)
r = session.sys.process.execute("cmd.exe /c del /F /S /Q " + path, nil, {'Hidden' => 'true'})
while(r.name)
select(nil, nil, nil, 0.10)
end
r.close
end
# ====================================================================================================================================
# Exec a command and return the results
# ====================================================================================================================================
def m_exec(session, cmd)
begin
r = session.sys.process.execute(cmd, nil, {'Hidden' => true, 'Channelized' => true})
b = ""
while(d = r.channel.read)
b < e
print_status("Error Running Command #{cmd}: #{e.class} #{e}")
end
end
# ====================================================================================================================================
# Function to upload files
# ====================================================================================================================================
def m_upload(session,file)
location = session.fs.file.expand_path("%temp%")
fileontrgt = "#{location}\\#{rand(100)}.exe"
print_status(" -- Uploading #{file}....")
session.fs.file.upload_file("#{fileontrgt}","#{file}")
print_status(" -- #{file} uploaded!")
print_status(" -- File on target #{fileontrgt}")
return fileontrgt
end
# ====================================================================================================================================
# Function to download files
# ====================================================================================================================================
def m_download(session,src,dst)
location = session.fs.file.expand_path("%temp%")
print_status(" -- Downloading #{src}....")
session.fs.file.download_file("#{dst}","#{src}")
print_status(" -- #{dst} downloaded!")
end
# ====================================================================================================================================
# Script proper
# ====================================================================================================================================
# The 'client' object holds the Meterpreter session
# Aliasing here for plugin compatibility
session = client
script_name = "installedsoftware"
# Extract the host and port
host,port = session.tunnel_peer.split(':')
print_status("New session on #{host}:#{port}...")
# Create a directory for the logs
logs = ::File.join(Msf::Config.config_directory, 'logs',script_name , host + "_" + Time.now.strftime("%Y%m%d.%M%S")+sprintf("%.5d",rand(100000)) )
# Create the log directory
::FileUtils.mkdir_p(logs)
print_status("-- Files saved to #{logs}...")
location = session.fs.file.expand_path("%temp%")
filename = "#{rand(100)}.dat"
fileontrgt = "#{location}\\#{filename}"
print_status("-- Data logged to #{fileontrgt}....")
begin
#===============================================================================================================================
#===============================================================================================================================
#===============================================================================================================================
# Pull USB history Pull USB history Pull USB history Pull USB history Pull USB history Pull USB history Pull USB history
#===============================================================================================================================
#===============================================================================================================================
#===============================================================================================================================
#===========================================================================================
# Dump USB device history
#===========================================================================================
key = "HKLM\\SYSTEM\\CurrentControlSet\\Enum\\USBSTOR"
root_key, base_key = session.sys.registry.splitkey(key)
log = "#{logs}\\installedusb.txt"
message = ""
message << "---------------------------------------------------------------------\n"
message << "Dumping software installed on pc per registry #{key}... \n"
message << "---------------------------------------------------------------------\n"
m_filewrt(log, message)
session.sys.registry.create_key(root_key, base_key).each_key() do |device|
puts device
# =========================================
# ...
# =========================================
session.sys.registry.create_key(root_key, "#{base_key}\\#{device}").each_key() do |intermediate|
puts intermediate
message = ""
rk = session.sys.registry.open_key(root_key, "#{base_key}\\#{device}\\#{intermediate}", KEY_READ)
cl = rk.query_value("class")
deviceDesc = rk.query_value("DeviceDesc")
friendlyName = rk.query_value("FriendlyName")
hardwareID = rk.query_value("HardwareID")
rk.close
message << " ========================================================================================================================\n"
message << " Friendly Name : #{friendlyName.data}\n"
message << " - Class : #{cl.data}\n"
message << " - DeviceDesc : #{deviceDesc.data}\n"
message << " - HardwareID : #{hardwareID.data}\n"
hdid = hardwareID.data
ids = hdid.split("USBSTOR")
ids.each do |num|
message < e
print_status("Exception: #{e.class} #{e} #{e.backtrace}")
end
print_status("Completed processing on #{host}:#{port}...")
[/code]