Saturday, September 14, 2019

USB History Part 2 [Live Machine]

Get Last insert date of MSC Type USB Devices

Scope And Usage:

This script runs on a live machine.

On a live machine, without SYSTEM level access this is the maximum USB timestamp data we can fetch. I know we can also get first connect time but that is easy and is not part of this blog post.

It is not possible to get more USB data from USBSTOR properties with nt-authority\system privileges. If you have SYSTEM level privileges use the previous post to retrieve.

the below PowerShell script queries local HKLM hive to get only USB disk data logged under \\SYSTEM\ControlSet001\Enum\USB\. Only pen drives get logged here, so you will not see phone history.

So let us begin.....

The first portion of the script is only to create a function that will allow us to get the last write time of any key in the registry. The complete script can be found at [reference] and I did not create it, I am using it as is.
If you can import modules in powershell you can delete the function and import the script directly as a module.
#use import-module "path the script"

My part of the script is an implementation of the research paper published (reference), to query locations we can touch with god-level access on a live machine to get last connect data of USB devices.

A big shout out to the research team who published the article.
##############################Part 1 ######################################
#Output of script in: C:\Windows\temp\usbdata.csv
#source: https://gallery.technet.microsoft.com/scriptcenter/Get-RegistryKeyLastWriteTim-63f4dd96
Function Get-RegistryKeyTimestamp { <# .SYNOPSIS Retrieves the registry key timestamp from a local or remote system. .DESCRIPTION Retrieves the registry key timestamp from a local or remote system. .PARAMETER RegistryKey Registry key object that can be passed into function. .PARAMETER SubKey The subkey path to view timestamp. .PARAMETER RegistryHive The registry hive that you will connect to. Accepted Values: ClassesRoot CurrentUser LocalMachine Users PerformanceData CurrentConfig DynData .NOTES Name: Get-RegistryKeyTimestamp Author: Boe Prox Version History: 1.0 -- Boe Prox 17 Dec 2014 -Initial Build .EXAMPLE $RegistryKey = Get-Item "HKLM:\System\CurrentControlSet\Control\Lsa" $RegistryKey | Get-RegistryKeyTimestamp | Format-List FullName : HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa Name : Lsa LastWriteTime : 12/16/2014 10:16:35 PM Description ----------- Displays the lastwritetime timestamp for the Lsa registry key. .EXAMPLE Get-RegistryKeyTimestamp -Computername Server1 -RegistryHive LocalMachine -SubKey 'System\CurrentControlSet\Control\Lsa' | Format-List FullName : HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa Name : Lsa LastWriteTime : 12/17/2014 6:46:08 AM Description ----------- Displays the lastwritetime timestamp for the Lsa registry key of the remote system. .INPUTS System.String Microsoft.Win32.RegistryKey .OUTPUTS Microsoft.Registry.Timestamp #> [OutputType('Microsoft.Registry.Timestamp')] [cmdletbinding( DefaultParameterSetName = 'ByValue' )] Param ( [parameter(ValueFromPipeline=$True, ParameterSetName='ByValue')] [Microsoft.Win32.RegistryKey]$RegistryKey, [parameter(ParameterSetName='ByPath')] [string]$SubKey, [parameter(ParameterSetName='ByPath')] [Microsoft.Win32.RegistryHive]$RegistryHive, [parameter(ParameterSetName='ByPath')] [string]$Computername ) Begin { #region Create Win32 API Object Try { [void][advapi32] } Catch { #region Module Builder $Domain = [AppDomain]::CurrentDomain $DynAssembly = New-Object System.Reflection.AssemblyName('RegAssembly') $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) # Only run in memory $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('RegistryTimeStampModule', $False) #endregion Module Builder #region DllImport $TypeBuilder = $ModuleBuilder.DefineType('advapi32', 'Public, Class') #region RegQueryInfoKey Method $PInvokeMethod = $TypeBuilder.DefineMethod( 'RegQueryInfoKey', #Method Name [Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl', #Method Attributes [IntPtr], #Method Return Type [Type[]] @( [Microsoft.Win32.SafeHandles.SafeRegistryHandle], #Registry Handle [System.Text.StringBuilder], #Class Name [UInt32 ].MakeByRefType(), #Class Length [UInt32], #Reserved [UInt32 ].MakeByRefType(), #Subkey Count [UInt32 ].MakeByRefType(), #Max Subkey Name Length [UInt32 ].MakeByRefType(), #Max Class Length [UInt32 ].MakeByRefType(), #Value Count [UInt32 ].MakeByRefType(), #Max Value Name Length [UInt32 ].MakeByRefType(), #Max Value Name Length [UInt32 ].MakeByRefType(), #Security Descriptor Size [long].MakeByRefType() #LastWriteTime ) #Method Parameters ) $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String])) $FieldArray = [Reflection.FieldInfo[]] @( [Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'), [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError') ) $FieldValueArray = [Object[]] @( 'RegQueryInfoKey', #CASE SENSITIVE!! $True ) $SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder( $DllImportConstructor, @('advapi32.dll'), $FieldArray, $FieldValueArray ) $PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute) #endregion RegQueryInfoKey Method [void]$TypeBuilder.CreateType() #endregion DllImport } #endregion Create Win32 API object } Process { #region Constant Variables $ClassLength = 255 [long]$TimeStamp = $null #endregion Constant Variables #region Registry Key Data If ($PSCmdlet.ParameterSetName -eq 'ByPath') { #Get registry key data $RegistryKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RegistryHive, $Computername).OpenSubKey($SubKey) If ($RegistryKey -isnot [Microsoft.Win32.RegistryKey]) { Throw "Cannot open or locate $SubKey on $Computername" } } $ClassName = New-Object System.Text.StringBuilder $RegistryKey.Name $RegistryHandle = $RegistryKey.Handle #endregion Registry Key Data #region Retrieve timestamp $Return = [advapi32]::RegQueryInfoKey( $RegistryHandle, $ClassName, [ref]$ClassLength, $Null, [ref]$Null, [ref]$Null, [ref]$Null, [ref]$Null, [ref]$Null, [ref]$Null, [ref]$Null, [ref]$TimeStamp ) Switch ($Return) { 0 { #Convert High/Low date to DateTime Object $LastWriteTime = (Get-Date $TimeStamp).AddYears(1600) #Return object $Object = [pscustomobject]@{ FullName = $RegistryKey.Name Name = $RegistryKey.Name -replace '.*\\(.*)','$1' LastWriteTime = $LastWriteTime } #$Object.pstypenames.insert(0,'Microsoft.Registry.Timestamp') $Object } 122 { Throw "ERROR_INSUFFICIENT_BUFFER (0x7a)" } Default { Throw "Error ($return) occurred" } } #endregion Retrieve timestamp } } #####################################Part 2##################################### $usbstor =Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR\*\*' # get all usb serial id foldername from usbstor, eg, 061719-24143&0 function list_msc_devices{ $usbstor =Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR\*\*' $output=@() foreach ($x in $usbstor){ $instance_name=$x.PSParentPath.Split("\")[-1] $serial='' if($x.PSChildName -match '&0$'){ $serial=$x.PSChildName.Substring(0,$x.PSChildName.Length-2)} # this is the usb serial ID else {$serial=$x.PSChildName} $friendlyname=$x.FriendlyName $output += New-Object -TypeName psobject -Property @{Name=$friendlyname;Serial=$serial;instance=$instance_name} } return $output } #SYSTEM\CurrentControlSet\Enum\USB\VID_090C&PID_1000\061719-24143 #Get-RegistryKeyTimestamp -RegistryHive LocalMachine -SubKey $subkey_last function add_Last_in{ $lastin=@() $output=list_msc_devices $serial = list_msc_devices | select -Property Serial foreach($o in $output){ $ss= $o.Serial.tostring() $path='HKLM:\SYSTEM\ControlSet001\Enum\USB\*\'+ $ss #find usb serial ID under "USB" not (USBstor) $u=Get-ItemProperty -Path $path #fetch path to grab enclosing folder name foreach($usbpath in $u) { $path =$usbpath.PSPath.Split(":")[2] if ($path -ne $null) { $instanceid=$path.Split("\")[-2] #this is the instanceid, also the folder name under which lies serial id,eg VID_0781&PID_5567 $subkey_last="SYSTEM\ControlSet001\Enum\USB\"+$instanceid+"\" +$ss $last_time=Get-RegistryKeyTimestamp -RegistryHive LocalMachine -SubKey $subkey_last #$last_time.LastWriteTime.ToString() $o | Add-Member -MemberType NoteProperty "Last_In" -Value $last_time.LastWriteTime.ToString() $lastin+=$o } } } return $lastin } #ControlSet001\Control\DeviceClasses\{53f56307-b6bf-11d0-94f2-00a0c91efb8b}\##?#USBSTOR#Instance_name#Serial_ID&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b} function add_First_in{ $first_in=@() $inputobject=add_Last_in foreach ($row in $inputobject) { $keypath='SYSTEM\ControlSet001\Control\DeviceClasses\{53f56307-b6bf-11d0-94f2-00a0c91efb8b}\##?#USBSTOR#'+$row.instance+"#"+$row.Serial +"&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}" $last_time=(Get-RegistryKeyTimestamp -RegistryHive LocalMachine -SubKey $keypath.ToString()).LastWriteTime.ToString() $row | Add-Member -MemberType NoteProperty "First_In" -Value $last_time $first_in+=$row } return $first_in } Function get_msc_usb{ $usb=add_First_in $usb | select -Property Name,First_In,Last_In,Serial | Export-Csv "C:\Windows\Temp\usbdata.csv" } get_msc_usb



References:
https://gallery.technet.microsoft.com/scriptcenter/Get-RegistryKeyLastWriteTim-63f4dd96
https://www.researchgate.net/publication/318514858_USB_Storage_Device_Forensics_for_Windows_10


No comments:

Post a Comment