├── .gitignore
├── .vs
├── IRCoreForensicFramework
│ └── v16
│ │ └── .suo
├── ProjectSettings.json
├── VSWorkspaceState.json
└── slnx.sqlite
├── Actions
├── CloudStoragePreparation
│ └── Compress-AllForensicArtefacts.psm1
├── CreateStagingLocation
│ ├── New-CurrentStateStagingLocation.psm1
│ ├── New-EndpointForensicStorageLocation.psm1
│ ├── New-LocalDataStagingLocation.psm1
│ ├── New-ProcessedArtefactsStagingLocation.psm1
│ └── New-RemoteStagingLocation.psm1
├── EventCapture
│ └── Out-Events.psm1
├── RemoveRemoteArtifacts
│ └── Remove-RemoteStagingLocation.psm1
├── WindowsCurrentStateDetailsRetrieval
│ ├── Get-CurrentProcesses.psm1
│ └── Invoke-GetCurrentStateDetails.psm1
├── WindowsEventLogProcessing
│ ├── Export-ProcessStartEvents.psm1
│ ├── Export-ProcessStopEvents.psm1
│ └── Invoke-EventLogProcessing.psm1
├── WindowsEventLogandSRURetrieval
│ ├── Copy-RemoteEventLogging.psm1
│ ├── Get-RemoteEventLogging.psm1
│ └── Invoke-GetRemoteEventLogsandSRU.psm1
├── WindowsMemoryProcessing
│ ├── Format-VolatilityOutput.psm1
│ ├── Invoke-VolatilityCmdline.psm1
│ ├── Invoke-VolatilityPSList.psm1
│ ├── Invoke-VolatilityPSScan.psm1
│ └── Invoke-WindowsMemoryImageProcessing.psm1
├── WindowsMemoryRetrieval
│ ├── Compare-MemoryHashes.psm1
│ ├── Get-ExtractedMemoryHash.psm1
│ ├── Get-MemoryDump.psm1
│ ├── Get-RemoteMemoryHash.psm1
│ ├── Invoke-GetRemoteMemory.psm1
│ ├── Invoke-MemoryDump.psm1
│ └── Move-WinPMEM.psm1
├── WindowsPrefetchProcessing
│ └── Format-WindowsPrefetch.psm1
├── WindowsPrefetchRetrieval
│ ├── Copy-WindowsPrefetch.psm1
│ ├── Get-WindowsPrefetch.psm1
│ └── Invoke-GetWindowsPrefetch.psm1
├── WindowsProcessPostProcessing
│ ├── Join-WIndowsProcessStartProcessStopLogs.psm1
│ └── Join-WindowsProcessArtefacts.psm1
├── WindowsRegistryRetrieval
│ ├── Copy-WindowsRegistry.psm1
│ ├── Get-WindowsRegistryFiles.psm1
│ ├── Invoke-GetWindowsRegistry.psm1
│ └── New-RegistryFileFolder.psm1
└── WindowsSRUProcessing
│ ├── Format-SRUDBtoJSON.psm1
│ ├── Format-SRUDBtoXLSX.psm1
│ └── Format-SrumDumptoJson.psm1
├── CoreEndpointInteraction
├── Get-TargetList.psm1
├── Get-TargetSessions.psm1
├── Invoke-HostCommand.psm1
├── Invoke-HostHunterCommand.psm1
├── New-EndpointSession.psm1
├── New-Target.psm1
├── Remove-EndpointSession.psm1
├── Remove-Target.psm1
└── Update-Credentials.psm1
├── DockerVolume
└── Copy-ToDockerVolume.psm1
├── Dockerfile
├── Executeables
├── PECmd.exe
├── PECmd.zip
├── SRUM_TEMPLATE2.xlsx
├── WinPmem.exe
├── executeablemanifest.json
├── srum_dump2.exe
└── volatility3.zip
├── LICENSE
├── Playbooks
├── Invoke-CoreForensicArtifactGatheringPlaybook.psm1
├── Invoke-CoreForensicArtifactProcessingPlaybook.psm1
├── artefactgatheringmodules.txt
└── artefactprocessingmodules.txt
├── README.md
├── SetupModules
├── Copy-Volatility.psm1
├── Expand-PrefetchParser.psm1
├── Get-Executeable.psm1
├── Get-SetupExecuteables.psm1
├── Import-VolatilitySymbols.psm1
└── Set-PythonAnalysisList.psm1
├── UnifiedMessaging
├── New-TooltipNotification.psm1
└── Write-HostHunterInformation.psm1
├── loadIRCore.ps1
└── modulemanifest.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | /PythonAnalysisList/volatility3
--------------------------------------------------------------------------------
/.vs/IRCoreForensicFramework/v16/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimtin/IRCoreForensicFramework/d5f6a283b9b45364859856b0e0ed7c6f7e6f3aa5/.vs/IRCoreForensicFramework/v16/.suo
--------------------------------------------------------------------------------
/.vs/ProjectSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "CurrentProjectSetting": null
3 | }
--------------------------------------------------------------------------------
/.vs/VSWorkspaceState.json:
--------------------------------------------------------------------------------
1 | {
2 | "ExpandedNodes": [
3 | ""
4 | ],
5 | "SelectedNode": "\\loadIRCore.ps1",
6 | "PreviewInSolutionExplorer": false
7 | }
--------------------------------------------------------------------------------
/.vs/slnx.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimtin/IRCoreForensicFramework/d5f6a283b9b45364859856b0e0ed7c6f7e6f3aa5/.vs/slnx.sqlite
--------------------------------------------------------------------------------
/Actions/CloudStoragePreparation/Compress-AllForensicArtefacts.psm1:
--------------------------------------------------------------------------------
1 | function Compress-AllForensicArtefacts {
2 | <#
3 | .SYNOPSIS
4 | Uses native windows tools to compress full forensic artifacts folder into a more manageable size
5 |
6 | .DESCRIPTION
7 | Uses native windows tools to compress full forensic artifacts folder into a more manageable size
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)]$Target
13 | )
14 |
15 | # Set up the outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Compress-AllForensicArtefacts"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Set up the location and destination paths
26 | $location = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts"
27 | $destination = "C:\ExtractionDirectory\" + $Target + "_Compressed.zip"
28 |
29 | # Add in the compression .NET API
30 | Add-Type -Assembly System.IO.Compression.FileSystem
31 |
32 | # Set the compression level
33 | $compressionlevel = [System.IO.Compression.CompressionLevel]::Optimal
34 |
35 | # Now Zip it
36 | [System.IO.Compression.ZipFile]::CreateFromDirectory($location, $destination, $compressionlevel, $false)
37 |
38 | # Test that the zip file has been created
39 | $zipcreated = Test-Path -Path $destination
40 | $outcome.Add("Outcome", $zipcreated)
41 |
42 | # Stop the stopwatch
43 | $stopwatch.Stop()
44 |
45 | # Add the timing to output
46 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
47 |
48 | # Return back to user
49 | Write-Output $outcome
50 |
51 | }
--------------------------------------------------------------------------------
/Actions/CreateStagingLocation/New-CurrentStateStagingLocation.psm1:
--------------------------------------------------------------------------------
1 | function New-CurrentStateStagingLocation {
2 | <#
3 | .SYNOPSIS
4 | Creates the folder to store current state information
5 |
6 | .DESCRIPTION
7 | Creates the folder to store current state information
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Create the outcome directory
16 | $outcome = @{
17 | "HostHunterObject" = "New-CurrentStateStagingLocation"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Create the location variable
23 | $path = "C:\ExtractionDirectory\" + $Target.ComputerName + "_ForensicArtifacts"
24 | $fullpath = $path + "\CurrentStateInformation"
25 | $outcome.Add("DirectoryLocation", $fullpath)
26 |
27 | # Test if the path exists. If not, create
28 | $ispath = Test-Path -Path $fullpath
29 | if($ispath -ne $true){
30 | $createdpath = New-Item -Path $path -ItemType Directory -Name "CurrentStateInformation"
31 | $outcome.Add("NewPathCreated", $createdpath)
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/Actions/CreateStagingLocation/New-EndpointForensicStorageLocation.psm1:
--------------------------------------------------------------------------------
1 | function New-EndpointForensicStorageLocation {
2 | <#
3 | .SYNOPSIS
4 | Creates a folder to store the forensic information extracted from an endpoint
5 |
6 | .DESCRIPTION
7 | Creates a folder to store the forensic information extracted from an endpoint
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Create output variable
16 | $output = @{
17 | "HostHunterObject" = "New-EndpointStorageLocation"
18 | "DateTime" = (Get-Date).ToString()
19 | }
20 |
21 | # Test path to see if it already exists
22 | $Location = "C:\ExtractionDirectory\" + $Target.ComputerName + "_ForensicArtifacts"
23 | $Location = Test-Path -Path $Location
24 |
25 | # If it doesn't, create it
26 | if($Location -ne $true){
27 | $foldername = $Target + "_ForensicArtifacts"
28 | $createfolder = New-Item -Path "C:\ExtractionDirectory" -Name $foldername -ItemType Directory
29 | }
30 |
31 | # Add to the output
32 | $output.Add("CreatedForensicArtifactStorage", $createfolder)
33 |
34 | # Return output to user
35 | Write-Output $output
36 |
37 | }
--------------------------------------------------------------------------------
/Actions/CreateStagingLocation/New-LocalDataStagingLocation.psm1:
--------------------------------------------------------------------------------
1 | function New-LocalDataStagingLocation{
2 | <#
3 | .SYNOPSIS
4 | Creates the local data staging location
5 |
6 | .DESCRIPTION
7 | Creates the local data staging location
8 | #>
9 |
10 | # Check if the staging location exists
11 | $staginglocation = Test-Path -Path "C:\ExtractionDirectory"
12 |
13 | if($staginglocation -ne $true){
14 | # Write-HostHunterInformation -MessageData "Creating local data staging location" -ForegroundColor "Cyan"
15 | New-Item -Path C:\ -Name "ExtractionDirectory" -ItemType "directory"
16 | }
17 | }
--------------------------------------------------------------------------------
/Actions/CreateStagingLocation/New-ProcessedArtefactsStagingLocation.psm1:
--------------------------------------------------------------------------------
1 | function New-ProcessedArtefactsStagingLocation {
2 | <#
3 | .SYNOPSIS
4 | Creates the folder to store current state information
5 |
6 | .DESCRIPTION
7 | Creates the folder to store current state information
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][string]$Target
13 | )
14 |
15 | # Create the outcome directory
16 | $outcome = @{
17 | "HostHunterObject" = "New-ProcessedArtefactsStagingLocation"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Create the location variable
23 | $path = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts"
24 | $fullpath = $path + "\ProcessedArtefacts"
25 | $outcome.Add("DirectoryLocation", $fullpath)
26 |
27 | # Test if the path exists. If not, create
28 | $ispath = Test-Path -Path $fullpath
29 | if($ispath -ne $true){
30 | $createdpath = New-Item -Path $path -ItemType Directory -Name "ProcessedArtefacts"
31 | $outcome.Add("NewPathCreated", $createdpath)
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/Actions/CreateStagingLocation/New-RemoteStagingLocation.psm1:
--------------------------------------------------------------------------------
1 | function New-RemoteStagingLocation{
2 | <#
3 | .SYNOPSIS
4 | Creates a new folder on remote endpoint(s) to stage the data being gathered
5 |
6 | .DESCRIPTION
7 | Creates a new folder on the remote endpoint(s). This is used to stage the data to be extracted.
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)]$Target
13 | )
14 |
15 | # Set up outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "New-RemoteStagingLocation"
18 | "StagingLocation" = "C:\PerformanceInformation"
19 | "DateTime" = (Get-Date).ToString()
20 | "Target" = $Target
21 | }
22 |
23 | # Test the endpoint to see if the Performance Information folder exists, else create it
24 | $pathexists = Invoke-HostHunterCommand -Target $Target -ScriptBlock{
25 | # Set up output dictionary
26 | $output = @{}
27 | # Get Hostname of the command being run
28 | $output.Add("HostName", $env:COMPUTERNAME)
29 | # Test for the path
30 | $outcome = Test-Path -Path "C:\PerformanceInformation"
31 | # If outcome is false, create the directory
32 | if($outcome -eq $false){
33 | $output.Add("CreatedPerformanceInformationFolderTimestamp", (Get-Date).ToString())
34 | New-Item -Path "C:\" -Name "PerformanceInformation" -ItemType "directory"
35 | }
36 | # Record outcome for posterity
37 | $output.Add("Outcome", $outcome)
38 | Write-Output $output
39 | }
40 |
41 | # Add the results to outcome dictionary
42 | $outcome.Add("EndpointOutcomes", $pathexists)
43 |
44 | # Return results to pwsh
45 | Write-Output $outcome
46 | }
--------------------------------------------------------------------------------
/Actions/EventCapture/Out-Events.psm1:
--------------------------------------------------------------------------------
1 | function Out-Events {
2 | <#
3 | .SYNOPSIS
4 | Writes the events undertaken on a remote endpoint to specified location
5 |
6 | .DESCRIPTION
7 | Writes the events undertaken on a remote endpoint to specified location
8 |
9 | #>
10 | param (
11 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target,
12 | [Parameter(Mandatory=$true)]$CommandHistory
13 | )
14 |
15 | # Set up outcome
16 | $outcome = @{
17 | "HostHunterObject" = "Out-Events"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Test if RemoteEndpointCommandHistory folder exists. If not, create
26 | $Location = "C:\ExtractionDirectory\" + $Target.ComputerName + "_ForensicArtifacts"
27 | $fulllocation = "C:\ExtractionDirectory\" + $Target.ComputerName + "_ForensicArtifacts\RemoteEndpointCommandHistory"
28 | $path = Test-Path -LiteralPath $fulllocation
29 | if($path -ne $true){
30 | New-Item -Path $Location -Name RemoteEndpointCommandHistory -ItemType Directory
31 | }
32 |
33 | # Take the incoming powershell object, turn it into JSON
34 | $outfile = $fulllocation + "\RemoteEndpointCommandHistory.json"
35 | $CommandHistory | ConvertTo-Json | Out-File $outfile
36 |
37 | # Stop the stopwatch
38 | $stopwatch.Stop()
39 |
40 | # Add the timing to output
41 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
42 |
43 | # Return the outcome to the user
44 | Write-Output $outcome
45 | }
--------------------------------------------------------------------------------
/Actions/RemoveRemoteArtifacts/Remove-RemoteStagingLocation.psm1:
--------------------------------------------------------------------------------
1 | function Remove-RemoteStagingLocation{
2 | <#
3 | .SYNOPSIS
4 | Removes the remote staging location from remote endpoint(s)
5 |
6 | .DESCRIPTION
7 | Removes the remote staging location from remote endpoint(s)
8 | Pairs with New-RemoteStagingLocation module
9 |
10 | #>
11 | [CmdletBinding()]
12 | param (
13 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
14 | )
15 |
16 | # Set up outcome variable
17 | $outcome = @{
18 | "HostHunterObject" = "Remove-RemoteStagingLocation"
19 | "StagingLocation" = "C:\PerformanceInformation"
20 | "DateTime" = (Get-Date).ToString()
21 | "Target" = $Target
22 | }
23 |
24 | # Set up the stopwatch variable to measure how long this takes
25 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
26 |
27 | $pathexists = Invoke-HostHunterCommand -Target $Target -ScriptBlock{
28 | # Set up output dictionary
29 | $output = @{}
30 | # Get Hostname of the command being run
31 | $output.Add("HostName", $env:COMPUTERNAME)
32 | # Test for the path
33 | $outcome = Test-Path -Path "C:\PerformanceInformation"
34 | # If outcome is true, remove the directory
35 | if($outcome -eq $true){
36 | $output.Add("RemovedPerformanceInformationFolderTimestamp", (Get-Date).ToString())
37 | Remove-Item -Path "C:\PerformanceInformation" -Recurse
38 | }
39 | # Record outcome for posterity
40 | $output.Add("Outcome", $outcome)
41 | Write-Output $output
42 | }
43 |
44 | # Stop the stopwatch
45 | $stopwatch.Stop()
46 |
47 | # Add the timing to output
48 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
49 |
50 | # Add the results to outcome dictionary
51 | $outcome.Add("EndpointOutcomes", $pathexists)
52 |
53 | # Return results to pwsh
54 | Write-Output $outcome
55 | }
--------------------------------------------------------------------------------
/Actions/WindowsCurrentStateDetailsRetrieval/Get-CurrentProcesses.psm1:
--------------------------------------------------------------------------------
1 | function Get-CurrentProcesses {
2 | <#
3 | .SYNOPSIS
4 | Takes a snapshot of the currently running processes on the target endpoint. This can be used to answer the question "Was this process running when we took the snapshot?"
5 |
6 | .DESCRIPTION
7 | Takes a snapshot of the currently running processes on the target endpoint. This can be used to answer the question "Was this process running when we took the snapshot?"
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Set up outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Get-CurrentProcesses"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Get the processes
26 | $processes = Invoke-HostHunterCommand -Target $Target -Scriptblock{Get-Process}
27 |
28 | # Stop the stopwatch
29 | $stopwatch.Stop()
30 |
31 | # Add the timing to output
32 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
33 |
34 | # Add the results to outcome dictionary
35 | $outcome.Add("EndpointOutcomes", $pathexists)
36 |
37 | # Write directly to file
38 | $outfile = "C:\ExtractionDirectory\" + $Target.ComputerName +"_ForensicArtifacts\CurrentStateInformation\processes.json"
39 | $processes | ConvertTo-Json | Out-File $outfile
40 |
41 | # Return results to pwsh
42 | Write-Output $outcome
43 |
44 | }
--------------------------------------------------------------------------------
/Actions/WindowsCurrentStateDetailsRetrieval/Invoke-GetCurrentStateDetails.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-GetCurrentStateDetails {
2 | <#
3 | .SYNOPSIS
4 | Gets a collection of current state information
5 |
6 | .DESCRIPTION
7 | Gets a collection of the current state information
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Set up outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Invoke-GetCurrentStateDetails"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Create the storage directory
26 | $currentstatedirectory = New-CurrentStateStagingLocation -Target $Target
27 | $outcome.Add("CreateDirectory", $currentstatedirectory)
28 |
29 | # Get the processes
30 | $processes = Get-CurrentProcesses -Target $Target
31 | $outcome.Add("CurrentProcesses", $processes)
32 |
33 | # Stop the stopwatch
34 | $stopwatch.Stop()
35 |
36 | # Add the timing to output
37 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
38 |
39 | # Add the results to outcome dictionary
40 | $outcome.Add("EndpointOutcomes", $pathexists)
41 |
42 | # Return results to pwsh
43 | Write-Output $outcome
44 | }
--------------------------------------------------------------------------------
/Actions/WindowsEventLogProcessing/Export-ProcessStartEvents.psm1:
--------------------------------------------------------------------------------
1 | function Export-ProcessStartEvents {
2 | <#
3 | .SYNOPSIS
4 | Exports process start events from the Security event logs
5 |
6 | .DESCRIPTION
7 | Exports process start events from the Security event logs. Assumes that event log file exists, but checks for process start events.
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][string]$Target
13 | )
14 |
15 | # Create outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Export-ProcessStartEvents"
18 | "DateTimeCreated" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Construct the path
26 | $logpath = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\EventLoggingandSRU\Logs\Security.evtx"
27 |
28 | # First extract the process start logs from security log
29 | $processstartlogs = Get-WinEvent -FilterHashtable @{
30 | Id = "4688"
31 | Path = $logpath
32 | }
33 |
34 | # Create the output dictionary
35 | $formattedlogs = @()
36 |
37 | # Iterate through the logs, create the output needed
38 | foreach($procstart in $processstartlogs){
39 | # Create the object to store everything in
40 | $processobject = @{
41 | "Source" = "ExtractedEventLogs"
42 | "Type" = "ProcessStart"
43 | "Target" = $Target
44 | "DateTime" = $procstart.TimeCreated
45 | "SecurityID" = $procstart.Properties[0].Value.Value
46 | "CreatorAccountName" = $procstart.Properties[1].Value
47 | "CreatorAccountDomain" = $procstart.Properties[2].Value
48 | "CreatorLogonID" = $procstart.Properties[3].Value.Value
49 | "ProcessId" = $procstart.Properties[4].Value
50 | "ProcessStartPath" = $procstart.Properties[5].Value
51 | "TokenElevationType" = $procstart.Properties[6].Value
52 | "ParentProcessId" = $procstart.Properties[7].Value
53 | "ProcessCommandLine" = $procstart.Properties[8].Value
54 | "TargetSecurityId" = $procstart.Properties[9].Value.Value
55 | "TargetAccountName" = $procstart.Properties[10].Value
56 | "TargetAccountDomain" = $procstart.Properties[11].Value
57 | "TargetLogonId" = $procstart.Properties[12].Value
58 | "ParentProcessPath" = $procstart.Properties[13].Value
59 | "CreatorSecurityID" = $procstart.Properties[14].Value.Value
60 | "EventLogRecordId" = $procstart.RecordId
61 | }
62 |
63 | # Add the log object back to formattedlogs array
64 | $formattedlogs += $processobject
65 | }
66 |
67 | # Stop the stopwatch
68 | $stopwatch.Stop()
69 |
70 | # Add the timing to output
71 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
72 |
73 | # Add back to outcome
74 | $outcome.Add("ProcessStartLogs", $formattedlogs)
75 |
76 | # Output formatted logs to processed artifacts
77 | $processedartifactspath = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\ProcessedArtefacts\processstarts.json"
78 | $outcome | ConvertTo-Json | Out-File $processedartifactspath
79 |
80 | # Return back to user
81 | Write-Output $outcome
82 | }
--------------------------------------------------------------------------------
/Actions/WindowsEventLogProcessing/Export-ProcessStopEvents.psm1:
--------------------------------------------------------------------------------
1 | function Export-ProcessStopEvents {
2 | <#
3 | .SYNOPSIS
4 | Exports process stop events from the Security event logs
5 |
6 | .DESCRIPTION
7 | Exports process stop events from the Security event logs. Assumes that event log file exists, but checks for process start events.
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][string]$Target
13 | )
14 |
15 | # Create outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Export-ProcessStopEvents"
18 | "DateTimeCreated" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Construct the path
26 | $logpath = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\EventLoggingandSRU\Logs\Security.evtx"
27 |
28 | # First extract the process start logs from security log
29 | $processstoplogs = Get-WinEvent -FilterHashtable @{
30 | Id = "4689"
31 | Path = $logpath
32 | }
33 |
34 | # Create the output dictionary
35 | $formattedlogs = @()
36 |
37 | # Iterate through the logs, create the output needed
38 | foreach($procstop in $processstoplogs){
39 | # Create the object to store everything in
40 | $processobject = @{
41 | "Source" = "ExtractedEventLogs"
42 | "Type" = "ProcessStop"
43 | "Target" = $Target
44 | "ProcessId" = $procstop.Properties[5].Value
45 | "DateTime" = $procstop.TimeCreated
46 | "SecurityID" = $procstop.Properties[0].Value.Value
47 | "AccountName" = $procstop.Properties[1].Value
48 | "AccountDomain" = $procstop.Properties[2].Value
49 | "LogonID" = $procstop.Properties[3].Value.Value
50 | "ProcessStartPath" = $procstop.Properties[6].Value
51 | "ProcessExitStatus" = $procstop.Properties[4].Value
52 | "EventLogRecordId" = $procstop.RecordId
53 | }
54 |
55 | # Add the log object back to formattedlogs array
56 | $formattedlogs += $processobject
57 | }
58 |
59 | # Stop the stopwatch
60 | $stopwatch.Stop()
61 |
62 | # Add the timing to output
63 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
64 |
65 | # Add back to outcome
66 | $outcome.Add("ProcessStopLogs", $formattedlogs)
67 |
68 | # Output formatted logs to processed artifacts
69 | $processedartifactspath = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\ProcessedArtefacts\processstops.json"
70 | $outcome | ConvertTo-Json | Out-File $processedartifactspath
71 |
72 | # Return back to user
73 | Write-Output $outcome
74 | }
--------------------------------------------------------------------------------
/Actions/WindowsEventLogProcessing/Invoke-EventLogProcessing.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-EventLogProcessing {
2 | <#
3 | .SYNOPSIS
4 | Processes all the Event Logs needed for post processing. This is an ever growing list.
5 |
6 | .DESCRIPTION
7 | Processes all the Event Logs needed for post processing. This is an ever growing list.
8 | 1. ProcessStartEvents
9 |
10 | #>
11 | param (
12 | [Parameter(Mandatory=$true)][string]$Target
13 | )
14 |
15 | # Create outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Export-ProcessStartEvents"
18 | "DateTimeCreated" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Process process start logs
26 | $processstart = Export-ProcessStartEvents -Target $Target
27 | $outcome.Add("ProcessStartLogs", $processstart)
28 |
29 | # Process process stop logs
30 | $processstop = Export-ProcessStopEvents -Target $Target
31 | $outcome.Add("ProcessStopLogs", $processstop)
32 |
33 | # Stop the stopwatch
34 | $stopwatch.Stop()
35 |
36 | # Add the timing to output
37 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
38 |
39 | # Return back to user
40 | Write-Output $outcome
41 |
42 | }
--------------------------------------------------------------------------------
/Actions/WindowsEventLogandSRURetrieval/Copy-RemoteEventLogging.psm1:
--------------------------------------------------------------------------------
1 | function Copy-RemoteEventLogging{
2 | <#
3 | .SYNOPSIS
4 | Copies the remote event logs into the performance information folder
5 |
6 | .DESCRIPTION
7 | Copies the remote event logs into the performance information folder
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Setup overall outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Copy-RemoteEventLogging"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | $copylog = Invoke-HostHunterCommand -Target $Target -ScriptBlock{
26 | # Set up the outcome dictionary
27 | $outcome = @{}
28 |
29 | # Copy item
30 | $copyitem = Copy-Item -LiteralPath C:\Windows\System32\winevt\Logs -Destination C:\PerformanceInformation -Recurse
31 | $outcome.Add("EventLogCopy", $copyitem)
32 | $copysru = Copy-Item -LiteralPath C:\Windows\System32\sru -Destination C:\PerformanceInformation -Recurse
33 | $outcome.Add("SRULogCopy", $copysru)
34 | # Return results
35 | Write-Output $outcome
36 | }
37 | # Add the output from this command to the outcome variable
38 | $outcome.Add("Outcome", $copylog)
39 |
40 | # Stop the stopwatch
41 | $stopwatch.Stop()
42 |
43 | # Add the timing to output
44 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
45 |
46 | # Return outcome from this command
47 | Write-Output $outcome
48 | }
--------------------------------------------------------------------------------
/Actions/WindowsEventLogandSRURetrieval/Get-RemoteEventLogging.psm1:
--------------------------------------------------------------------------------
1 | function Get-RemoteEventLogging{
2 | <#
3 | .SYNOPSIS
4 | Gets the remote event logs from the endpoint. Renames it to the hostname of endpoint.
5 |
6 | .DESCRIPTION
7 | Gets the remote event logs from the endpoint. Renames it to the hostname of the endpoint.
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Setup the outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Get-RemoteEventLogging"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Set up the destination directory
26 | $LoggingPath = "C:\ExtractionDirectory\" + $Target.ComputerName + "_ForensicArtifacts"
27 |
28 | # Test if directory already exists, if not, create it
29 | $ExtractionPath = $LoggingPath + "\EventLoggingandSRU"
30 | $path = Test-Path -Path $testpath
31 | if($path -ne $true){
32 | New-Item -Path $LoggingPath -Name "EventLoggingandSRU" -ItemType "directory" | Out-Null
33 | }
34 |
35 | # Copy the Event Logs
36 | Copy-Item -FromSession $Target -Path "C:\PerformanceInformation\Logs" -Recurse -Destination $ExtractionPath | Out-Null
37 | # Test they were successfully extracted
38 | $logpath = $ExtractionPath + "\Logs"
39 | $eventlogsoutcome = Test-Path -Path $logpath
40 | $outcome.Add("EventLogExtractionOutcome", $eventlogsoutcome)
41 |
42 | # Copy the SRU
43 | $sru = Copy-Item -FromSession $Target -Path "C:\PerformanceInformation\sru" -Recurse -Destination $ExtractionPath
44 | # Test they were successfully extracted
45 | $srupath = $ExtractionPath + "\sru"
46 | $sruoutcome = Test-Path -Path $srupath
47 | $outcome.Add("SRUExtractionOutcome", $sruoutcome)
48 |
49 | # Stop the stopwatch
50 | $stopwatch.Stop()
51 |
52 | # Add the timing to output
53 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
54 |
55 | # Return the outcome to the user
56 | Write-Output $outcome
57 | }
--------------------------------------------------------------------------------
/Actions/WindowsEventLogandSRURetrieval/Invoke-GetRemoteEventLogsandSRU.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-GetRemoteEventLogsandSRU {
2 | <#
3 | .SYNOPSIS
4 | Gets remote event logs folder and SRU, then copies them to this endpoint
5 |
6 | .DESCRIPTION
7 | 1. Copies remote event logs and SRU - Copy-RemoteEventLogging
8 | 2. Extracts them to this endpoing - Get-RemoteEventLogging
9 |
10 | #>
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Set up outcome
16 | $outcome = @{
17 | "HostHunterObject" = "Invoke-GetRemoteEventLogsandSRU"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Copy the event logs
26 | $copylogs = Copy-RemoteEventLogging -Target $Target
27 | $outcome.Add("EventLogCopy", $copylogs)
28 |
29 | # Get the event logs and SRU database
30 | $logextraction = Get-RemoteEventLogging -Target $Target
31 | $outcome.Add("EventLogExtraction", $logextraction)
32 |
33 | # Stop the stopwatch
34 | $stopwatch.Stop()
35 |
36 | # Add the timing to output
37 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
38 |
39 | # Return the outcome to the user
40 | Write-Output $outcome
41 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryProcessing/Format-VolatilityOutput.psm1:
--------------------------------------------------------------------------------
1 | function Format-VolatilityOutput {
2 | param (
3 | [Parameter(Mandatory=$true)]$VolatilityFunctionOutput
4 | )
5 |
6 | # Setup the output variable
7 | $output = @{
8 | "Object" = "Format-VolatilityOutput"
9 | }
10 |
11 | # Format the output
12 | # Filter the results so that only good things are returned. Also, if you're reading this, smile
13 | $results = $VolatilityFunctionOutput[2..$VolatilityFunctionOutput.Count]
14 |
15 | # Reconstruct the results based upon the strings. This will be moved into a separate function when completed
16 | # Get the title strings
17 | $resultstitles = $results[0] -split '\t'
18 |
19 | # Remove the titles from the results string, and trailing new line
20 | $results = $results[2..$results.Count]
21 |
22 | # Set up the results HashTables
23 | $resultstable = @()
24 |
25 | # Iterate through the results and turn into Powershell HashTables
26 | foreach($line in $results[2..$results.Count]){
27 | # Split the line based upon tabs
28 | $linesplit = $line -split "\t"
29 |
30 | # Setup a dictionary object
31 | $object = @{}
32 |
33 | # For each object in titles, associate with the incoming linesplit options
34 | for($i=0; $i -lt $resultstitles.Count; $i++){
35 | $object.Add($resultstitles[$i], $linesplit[$i])
36 | }
37 |
38 | $resultstable += $object
39 |
40 | }
41 |
42 | Write-Output $resultstable
43 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryProcessing/Invoke-VolatilityCmdline.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-VolatilityCmdline {
2 | <#
3 | .SYNOPSIS
4 | Runs the Cmdline module from Volatility3
5 |
6 | .DESCRIPTION
7 | Using the modules from Volatility3, Cmdline then formats output into a Powershell object
8 | References:
9 | 1. Volatility3: https://github.com/volatilityfoundation/volatility3
10 | 2. Modules: https://volatility3.readthedocs.io/en/latest/
11 |
12 | Target can be selected, but defaults to all targets
13 | #>
14 | [CmdletBinding()]
15 | param (
16 | [Parameter(Mandatory=$true)]$Target
17 | )
18 |
19 | # Set up the outcome variable
20 | $outcome = @{
21 | "HostHunterObject" = "Invoke-VolatilityCmdline"
22 | "DateTime" = (Get-Date).ToString()
23 | "Target" = $Target
24 | }
25 |
26 | # Wait 5 seconds before kicking off the process
27 | Start-Sleep -Seconds 5
28 |
29 | # Set up the stopwatch variable to measure how long this takes
30 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
31 |
32 | # Construct the file location
33 | $memfilelocation = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\memory.raw"
34 |
35 | # Construct the output directory
36 | $outputdir = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\"
37 |
38 | # Run volatility command PSScan
39 | $results = python .\PythonAnalysisList\volatility3\vol.py --file $memfilelocation --output-dir $outputdir windows.cmdline
40 |
41 | # Turn into powershell objects
42 | $volatilityobjects = Format-VolatilityOutput -VolatilityFunctionOutput $results
43 | $outcome.Add("CmdlineResults", $volatilityobjects)
44 |
45 | # Output to a file in case future forensic work is needed
46 | # Create the file string
47 | $outfilestring = "C:\ExtractionDirectory\" + $target + "_ForensicArtifacts\ProcessedArtefacts\VolatilityCmdlineResults.json"
48 |
49 | # Stop the stopwatch
50 | $stopwatch.Stop()
51 |
52 | # Add the timing to output
53 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
54 |
55 | # Output to the folder
56 | $outcome | ConvertTo-Json -Depth 100 | Out-File $outfilestring
57 |
58 | # Return output to user
59 | Write-Output $outcome
60 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryProcessing/Invoke-VolatilityPSList.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-VolatilityPSList {
2 | <#
3 | .SYNOPSIS
4 | Runs the PSList module from Volatility3
5 |
6 | .DESCRIPTION
7 | Using the modules from Volatility3, PsLIst then formats output into a Powershell object
8 | References:
9 | 1. Volatility3: https://github.com/volatilityfoundation/volatility3
10 | 2. Modules: https://volatility3.readthedocs.io/en/latest/
11 |
12 | Target can be selected, but defaults to all targets
13 | #>
14 | [CmdletBinding()]
15 | param (
16 | [Parameter(Mandatory=$true)]$Target
17 | )
18 |
19 | # Set up the outcome variable
20 | $outcome = @{
21 | "HostHunterObject" = "Invoke-VolatilityPSList"
22 | "DateTime" = (Get-Date).ToString()
23 | "Target" = $Target
24 | }
25 |
26 | # Set up the stopwatch variable to measure how long this takes
27 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
28 |
29 | # Construct the file location
30 | $memfilelocation = "C:\ExtractionDirectory\" + $target + "_ForensicArtifacts\memory.raw"
31 |
32 | # Construct the output directory
33 | $outputdir = "C:\ExtractionDirectory\" + $target + "_ForensicArtifacts\"
34 |
35 | # Run volatility command PSScan
36 | $results = python .\PythonAnalysisList\volatility3\vol.py --file $memfilelocation --output-dir $outputdir windows.pslist.PsList
37 |
38 | # Turn into powershell objects
39 | $volatilityobjects = Format-VolatilityOutput -VolatilityFunctionOutput $results
40 |
41 | # Add to Target Object
42 | $outcome.Add("PSListResults", $volatilityobjects)
43 |
44 | # Output to a file in case future forensic work is needed
45 | # Create the file string
46 | $outfilestring = "C:\ExtractionDirectory\" + $target + "_ForensicArtifacts\ProcessedArtefacts\VolatilityPsListResults.json"
47 |
48 | # Stop the stopwatch
49 | $stopwatch.Stop()
50 |
51 | # Add the timing to output
52 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
53 |
54 | # Output to the folder
55 | $outcome | ConvertTo-Json | Out-File $outfilestring
56 |
57 | # Return output to user
58 | Write-Output $outcome
59 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryProcessing/Invoke-VolatilityPSScan.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-VolatilityPSScan {
2 | <#
3 | .SYNOPSIS
4 | Runs the PsScan module from Volatility3
5 |
6 | .DESCRIPTION
7 | Using the modules from Volatility3, PsScan then formats output into a Powershell object
8 | References:
9 | 1. Volatility3: https://github.com/volatilityfoundation/volatility3
10 | 2. Modules: https://volatility3.readthedocs.io/en/latest/
11 |
12 | Target can be selected, but defaults to all targets
13 | #>
14 | [CmdletBinding()]
15 | param (
16 | [Parameter(Mandatory=$true)]$Target
17 | )
18 |
19 | # Set up the outcome variable
20 | $outcome = @{
21 | "HostHunterObject" = "Invoke-VolatilityPSList"
22 | "DateTime" = (Get-Date).ToString()
23 | "Target" = $Target
24 | }
25 |
26 | # Set up the stopwatch variable to measure how long this takes
27 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
28 |
29 | # Construct the file location
30 | $memfilelocation = "C:\ExtractionDirectory\" + $target + "_ForensicArtifacts\memory.raw"
31 |
32 | # Construct the output directory
33 | $outputdir = "C:\ExtractionDirectory\" + $target + "_ForensicArtifacts\"
34 |
35 | # Run volatility command PSScan
36 | $results = python .\PythonAnalysisList\volatility3\vol.py --file $memfilelocation --output-dir $outputdir windows.psscan.PsScan
37 |
38 | # Turn into powershell objects
39 | $volatilityobjects = Format-VolatilityOutput -VolatilityFunctionOutput $results
40 |
41 | # Add to the output variable
42 | $outcome.Add("PSScanResults", $volatilityobjects)
43 |
44 | # Output to a file in case future forensic work is needed
45 | # Create the file string
46 | $outfilestring = "C:\ExtractionDirectory\" + $target + "_ForensicArtifacts\ProcessedArtefacts\VolatilityPsScanResults.json"
47 |
48 | # Stop the stopwatch
49 | $stopwatch.Stop()
50 |
51 | # Add the timing to output
52 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
53 |
54 | # Output to the folder
55 | $outcome | ConvertTo-Json | Out-File $outfilestring
56 |
57 | # Return output to user
58 | Write-Output $outcome
59 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryProcessing/Invoke-WindowsMemoryImageProcessing.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-WindowsMemoryImageProcessing {
2 | <#
3 | .SYNOPSIS
4 | Runs all the volatility commands added in on extracted memory image
5 |
6 | .DESCRIPTION
7 | Runs all the volatility commands added in on extracted memory image. So far:
8 | 1. Cmdline
9 | 2. PSList
10 | 3. PSScan
11 | #>
12 | [CmdletBinding()]
13 | param (
14 | [Parameter(Mandatory=$true)]$Target
15 | )
16 |
17 | # Set up the outcome variable
18 | $outcome = @{
19 | "HostHunterObject" = "Invoke-WindowsMemoryImageProcessing"
20 | "DateTime" = (Get-Date).ToString()
21 | "Target" = $Target
22 | }
23 |
24 | # Set up the stopwatch variable to measure how long this takes
25 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
26 |
27 | # Get Windows Volatility Commandline
28 | $cmdline = Invoke-VolatilityCmdline -Target $Target
29 | $outcome.Add("VolatilityCmdlineOutcome", $cmdline)
30 |
31 | # Get Windows PSList
32 | $pslist = Invoke-VolatilityPSList -Target $Target
33 | $outcome.Add("VolatilityPSListOutcome", $pslist)
34 |
35 | # Get Windows PSScan
36 | $psscan = Invoke-VolatilityPSScan -Target $Target
37 | $outcome.Add("VolatilityPSScanOutcome", $psscan)
38 |
39 | # Stop the stopwatch
40 | $stopwatch.Stop()
41 |
42 | # Add the timing to output
43 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
44 |
45 | # Return back to user
46 | Write-Output $outcome
47 |
48 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryRetrieval/Compare-MemoryHashes.psm1:
--------------------------------------------------------------------------------
1 | function Compare-MemoryHashes {
2 | <#
3 | .SYNOPSIS
4 | Function which compares hashes together from before and after extraction over network
5 |
6 | .DESCRIPTION
7 | Takes hashes from before and after network extraction and compares them together
8 |
9 | #>
10 | param (
11 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
12 | )
13 |
14 | # Set up outcome
15 | $outcome = @{
16 | "HostHunterObject" = "Compare-MemoryHashes"
17 | "DateTime" = (Get-Date).ToString()
18 | "Target" = $Target
19 | }
20 |
21 | # Set up the stopwatch variable to measure how long this takes
22 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
23 |
24 | # Get the remote memory hash
25 | $RemoteMemoryHash = Get-RemoteMemoryHash -Target $Target
26 | $outcome.Add("RemoteHash", $RemoteMemoryHash)
27 |
28 | # Get the local memory hash
29 | $LocalMemoryHash = Get-ExtractedMemoryHash -Target $Target
30 | $outcome.Add("LocalHash", $LocalMemoryHash)
31 |
32 | # Compare SHA256 Hashes
33 | if($RemoteMemoryHash.SHA256Hash.Hash -eq $LocalMemoryHash.SHA256Hash.Hash){
34 | $outcome.Add("HashComparison", $true)
35 | }else{
36 | $outcome.Add("HashComparison", $false)
37 | }
38 |
39 | # Stop the stopwatch
40 | $stopwatch.Stop()
41 |
42 | # Add the timing to output
43 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
44 |
45 | # Return outcome to the user
46 | Write-Output $outcome
47 |
48 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryRetrieval/Get-ExtractedMemoryHash.psm1:
--------------------------------------------------------------------------------
1 | function Get-ExtractedMemoryHash {
2 | <#
3 | .SYNOPSIS
4 | Gets the SHA256 and MD5 hash of the remote memory dump
5 |
6 | .DESCRIPTION
7 | Gets the SHA256 and MD5 has of the remote memory dump. This hash is used to confirm the extracted memory dump matches the original
8 |
9 | #>
10 | param (
11 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
12 | )
13 |
14 | # Set up the output dictionary
15 | $outcome = @{
16 | "HostHunterObject" = "Get-ExtractedMemoryHash"
17 | "DateTime" = (Get-Date).ToString()
18 | "Target" = $Target
19 | }
20 |
21 | # Set up the stopwatch variable to measure how long this takes
22 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
23 |
24 | # Construct the path where the hash will exist
25 | $path = "C:\ExtractionDirectory\" + $Target.ComputerName + "_ForensicArtifacts\memory.raw"
26 |
27 | # Get the SHA256 Hash
28 | $sha256hash = Get-FileHash -Path $path -Algorithm SHA256
29 | $outcome.Add("SHA256Hash", $sha256hash)
30 |
31 | # Stop the stopwatch
32 | $stopwatch.Stop()
33 |
34 | # Add the timing to output
35 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
36 |
37 | # Return to the user
38 | Write-Output $outcome
39 |
40 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryRetrieval/Get-MemoryDump.psm1:
--------------------------------------------------------------------------------
1 | function Get-MemoryDump{
2 | <#
3 | .SYNOPSIS
4 | Gets the memory dump from the target endpoints using a Powershell Session
5 |
6 | .DESCRIPTION
7 | Retrieves the memory dump using a Powershell Session
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Set up the outcome dictionary
16 | $outcome = @{
17 | "HostHunterObject" = "Get-MemoryDump"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Setup the extraction path
26 | $ExtractionPath = "C:\ExtractionDirectory\" + $Target.ComputerName + "_ForensicArtifacts"
27 |
28 | # Copy the memory dump file from the remote endpoint
29 | $memdump = Copy-Item -FromSession $Target -Path C:\PerformanceInformation\memory.raw -Destination $ExtractionPath
30 | $outcome.Add("MemDumpOutcome", $memdump)
31 |
32 | # Stop the stopwatch
33 | $stopwatch.Stop()
34 |
35 | # Add the timing to output
36 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
37 |
38 | # Return object to the user
39 | Write-Output $outcome
40 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryRetrieval/Get-RemoteMemoryHash.psm1:
--------------------------------------------------------------------------------
1 | function Get-RemoteMemoryHash {
2 | <#
3 | .SYNOPSIS
4 | Gets the SHA256 and MD5 hash of the remote memory dump
5 |
6 | .DESCRIPTION
7 | Gets the SHA256 and MD5 has of the remote memory dump. This hash is used to confirm the extracted memory dump matches the original
8 |
9 | #>
10 | param (
11 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
12 | )
13 |
14 | # Set up the output dictionary
15 | $outcome = @{
16 | "HostHunterObject" = "Get-RemoteMemoryHash"
17 | "DateTime" = (Get-Date).ToString()
18 | "Target" = $Target
19 | }
20 |
21 | # Set up the stopwatch variable to measure how long this takes
22 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
23 |
24 | $remotehashval = Invoke-HostHunterCommand -Target $Target -Scriptblock{
25 | # Set up the output variable
26 | $output = @{
27 | "Endpoint" = $env:COMPUTERNAME
28 | "DateTime" = (Get-Date).ToString()
29 | }
30 |
31 | # Get the SHA256 Hash
32 | $sha256hash = Get-FileHash -Path C:\PerformanceInformation\memory.raw -Algorithm SHA256
33 | $output.Add("SHA256Hash", $sha256hash)
34 | }
35 |
36 | # Add the outcome of all the hash values to the output
37 | $outcome.Add("HashValue", $remotehashval)
38 |
39 | # Stop the stopwatch
40 | $stopwatch.Stop()
41 |
42 | # Add the timing to output
43 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
44 |
45 | # Return to the user
46 | Write-Output $outcome
47 |
48 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryRetrieval/Invoke-GetRemoteMemory.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-GetRemoteMemory {
2 | <#
3 | .SYNOPSIS
4 | Combines all the HostHunter Commandlets together to go and get a remote memory dump.
5 |
6 | .DESCRIPTION
7 | 1. Pushes WinPmem executeable across to remote machine - Move-WinPMEM
8 | 2. Invokes a memory dump - Invoke-MemoryDump
9 | 3. Retrieves the remote memory dump - Get-MemoryDump
10 | 4. Gets a SHA256 Hash of the initial memory dump - Get-RemoteMemoryHash
11 | 5. Gets a SHA256 Hash of the extracted memory dump - Get-ExtractedMemoryHash
12 | 6. Compares the memory hashes together - Compare-MemoryHashes
13 |
14 | #>
15 | param (
16 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
17 | )
18 |
19 | # Setup the outcome variable
20 | $outcome = @{
21 | "HostHunterObject" = "Invoke-GetRemoteMemory"
22 | "DateTime" = (Get-Date).ToString()
23 | "Target" = $Target
24 | }
25 |
26 | # Set up the stopwatch variable to measure how long this takes
27 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
28 |
29 | # Move WinPmem to remote target
30 | $winpmemmove = Move-WinPmem -Target $Target
31 | $outcome.Add("WinPMEMMove", $winpmemmove)
32 |
33 | # Invoke a memory dump
34 | $memdump = Invoke-MemoryDump -Target $Target
35 | $outcome.Add("Memdump", $memdump)
36 |
37 | # Get the memory dump
38 | $memdumpretrieval = Get-MemoryDump -Target $Target
39 | $outcome.Add("MemdumpRetrieval", $memdumpretrieval)
40 |
41 | # Get and compare memory hashes
42 | $hashcomparison = Compare-MemoryHashes -Target $Target
43 | $outcome.Add("MemoryHashComparison", $hashcomparison)
44 |
45 | # todo: if memory hashes don't match, go and get memory again
46 |
47 | # Confirm that the memory dump has been retrieved successfully
48 | $location = "C:\ExtractionDirectory\" + $target.ComputerName + "_ForensicArtifacts\memory.raw"
49 | $memoryretrieved = Test-Path -Path $location
50 | $outcome.Add("MemoryDumpRetrieved", $memoryretrieved)
51 |
52 | # Stop the stopwatch
53 | $stopwatch.Stop()
54 |
55 | # Add the timing to output
56 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
57 |
58 | # Return outcomes to user
59 | Write-Output $outcome
60 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryRetrieval/Invoke-MemoryDump.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-MemoryDump{
2 | <#
3 | .SYNOPSIS
4 | Invokes memory dump on a remote endpoint
5 | .DESCRIPTION
6 | Uses WinPmem 1.6.2 on the remote endpoint to dump memory into performance data
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
12 | )
13 |
14 | # Set up outcome variable
15 | $outcome = @{
16 | "HostHunterObject" = "Invoke-MemoryDump"
17 | "DateTime" = (Get-Date).ToString()
18 | "Target" = $Target
19 | }
20 |
21 | # Set up the stopwatch variable to measure how long this takes
22 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
23 |
24 | # Run command
25 | $memdump = Invoke-HostHunterCommand -Target $Target -ScriptBlock{
26 | # Create outcome dictionary
27 | $outcome = @{}
28 |
29 | # Get the timestamp of the command
30 | $outcome.Add("MemoryDumpTimestamp", (Get-Date).ToString())
31 |
32 | # Test for path
33 | $path = Test-Path -LiteralPath "C:\PerformanceInformation\mem_info.exe"
34 | $outcome.Add("PathExists", $path)
35 |
36 | # Confirm enough space exists on endpoint
37 | # Get the total physical memory size
38 | $ramsize = [Math]::Round((Get-WmiObject -Class win32_computersystem -ComputerName localhost).TotalPhysicalMemory/1Gb)
39 | # Check that there is enough space on disk
40 | $disk = (Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" ).FreeSpace/1GB
41 | # Setup outcome
42 | $outcome.Add("MemorySize", $ramsize)
43 | $outcome.Add("FreeDiskSpace", $disk)
44 |
45 | if($disk -gt $ramsize){
46 | $outcome.Add("EnoughSpace", $true)
47 | if($path -eq $true){
48 | $memdump = C:\PerformanceInformation\mem_info.exe -o "C:\PerformanceInformation\memory.raw" --format raw --volume_format raw
49 | $outcome.Add("MemdumpInfo", $memdump)
50 | }
51 | }else{
52 | $outcome.Add("EnoughSpace", $false)
53 | }
54 | Write-Output $outcome
55 | }
56 |
57 | # Stop the stopwatch
58 | $stopwatch.Stop()
59 |
60 | # Add the timing to output
61 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
62 |
63 | # Add the outcome from the command to the outcome variable
64 | $outcome.Add("Outcome", $memdump)
65 |
66 | # Return the results to the user
67 | Write-Output $outcome
68 | }
--------------------------------------------------------------------------------
/Actions/WindowsMemoryRetrieval/Move-WinPMEM.psm1:
--------------------------------------------------------------------------------
1 | function Move-WinPmem{
2 | <#
3 | .SYNOPSIS
4 | Moves WinPmem 1.6 across to target machine
5 | .DESCRIPTION
6 | Uses WinRM protocol to move Winpmem across to the local machine.
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
12 | )
13 | # Set up outcome dictionary
14 | $outcome = @{
15 | "HostHunterObject" = "Move-WinPmem"
16 | "DateTime" = (Get-Date).ToString()
17 | "Target" = $Target
18 | }
19 |
20 | # Set up the stopwatch variable to measure how long this takes
21 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
22 |
23 | # Copy WinPMEM using powershell session
24 | $winpmem = Copy-Item -Path .\Executeables\WinPmem.exe -Destination "C:\PerformanceInformation\mem_info.exe" -ToSession $Target
25 |
26 | # Stop the stopwatch
27 | $stopwatch.Stop()
28 |
29 | # Add the timing to output
30 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
31 |
32 | # Add result to outcome variable
33 | $outcome.Add("WinPMEMTransferOutcome", $winpmem)
34 |
35 | # Return the outcome
36 | Write-Output $outcome
37 |
38 | }
--------------------------------------------------------------------------------
/Actions/WindowsPrefetchProcessing/Format-WindowsPrefetch.psm1:
--------------------------------------------------------------------------------
1 | function Format-WindowsPrefetch {
2 | <#
3 | .SYNOPSIS
4 | Formats windows prefetch files into JSON, preparing for post processing
5 |
6 | .DESCRIPTION
7 | Formats windows prefetch files into JSON, preparing for post processing.
8 | Uses Eric Zimmermans excellent tool PECmd.exe https://ericzimmerman.github.io/#!index.md
9 |
10 | #>
11 | [CmdletBinding()]
12 | param (
13 | [Parameter(Mandatory=$true)]$Target
14 | )
15 |
16 | # Set up the outcome variable
17 | $outcome = @{
18 | "HostHunterObject" = "Format-WindowsPrefetch"
19 | "DateTime" = (Get-Date).ToString()
20 | "Target" = $Target
21 | }
22 |
23 | # Set up the stopwatch variable to measure how long this takes
24 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
25 |
26 | # Set up the location variables
27 | $prefetchfolder = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\Prefetch"
28 | $outputfolder = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\ProcessedArtefacts"
29 |
30 | # Run the executeable with output json
31 | .\Executeables\PECmd.exe -d $prefetchfolder --json $outputfolder --jsonf "Prefetch.json" | Out-Null
32 |
33 | # Test that file successfully created
34 | $prefetchjson = $outputfolder + "\Prefetch.json"
35 | $prefetchjsonexists = Test-Path -Path $prefetchjson
36 | $outcome.Add("PrefetchOutcome", $prefetchjsonexists)
37 |
38 | # Stop the stopwatch
39 | $stopwatch.Stop()
40 |
41 | # Add the timing to output
42 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
43 |
44 | # Return back to user
45 | Write-Output $outcome
46 |
47 | }
--------------------------------------------------------------------------------
/Actions/WindowsPrefetchRetrieval/Copy-WindowsPrefetch.psm1:
--------------------------------------------------------------------------------
1 | function Copy-WindowsPrefetch{
2 | <#
3 | .SYNOPSIS
4 | Copies Windows Prefetch into the performance information folder
5 |
6 | .DESCRIPTION
7 | Copies Windows Prefetch into the performance information folder
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Setup overall outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Copy-WindowsPrefetch"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | $copylog = Invoke-HostHunterCommand -Target $Target -ScriptBlock{
26 | # Set up the outcome dictionary
27 | $outcome = @{}
28 |
29 | # Copy item
30 | $copyitem = Copy-Item -LiteralPath C:\Windows\Prefetch -Destination C:\PerformanceInformation -Recurse
31 | $outcome.Add("EventLogCopy", $copyitem)
32 |
33 | # Return results
34 | Write-Output $outcome
35 | }
36 | # Add the output from this command to the outcome variable
37 | $outcome.Add("Outcome", $copylog)
38 |
39 | # Stop the stopwatch
40 | $stopwatch.Stop()
41 |
42 | # Add the timing to output
43 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
44 |
45 | # Return outcome from this command
46 | Write-Output $outcome
47 | }
--------------------------------------------------------------------------------
/Actions/WindowsPrefetchRetrieval/Get-WindowsPrefetch.psm1:
--------------------------------------------------------------------------------
1 | function Get-WindowsPrefetch {
2 | <#
3 | .SYNOPSIS
4 | Gets windows prefetch from staging location, brings it back to the processing machine
5 |
6 | .DESCRIPTION
7 | Gets windows prefetch from staging location, brings it back to the processing machine
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Setup overall outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Get-WindowsPrefetch"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Set up the destination directory
26 | $ExtractionPath = "C:\ExtractionDirectory\" + $Target.ComputerName + "_ForensicArtifacts"
27 |
28 | # Copy the prefetch folder, recursively
29 | Copy-Item -FromSession $target -Path "C:\PerformanceInformation\Prefetch" -Destination $ExtractionPath -Recurse
30 | # Test they were copied successfully
31 | $prefetchpath = $ExtractionPath + "\Prefetch"
32 | $prefetchcopied = Test-Path -Path $prefetchpath
33 | $outcome.Add("PrefetchExtractionOutcome", $prefetchcopied)
34 |
35 | # Stop the stopwatch
36 | $stopwatch.Stop()
37 |
38 | # Add the timing to output
39 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
40 |
41 | # Return the outcome to the user
42 | Write-Output $outcome
43 | }
--------------------------------------------------------------------------------
/Actions/WindowsPrefetchRetrieval/Invoke-GetWindowsPrefetch.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-GetWindowsPrefetch {
2 | <#
3 | .SYNOPSIS
4 | Gets window prefetch from a remote machine
5 |
6 | .DESCRIPTION
7 | Gets window prefetch from a remote machine
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
13 | )
14 |
15 | # Setup overall outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Get-WindowsPrefetch"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Copy window prefetch
26 | $prefetchcopy = Copy-WindowsPrefetch -Target $Target
27 | $outcome.Add("PrefetchCopyOutcome", $prefetchcopy)
28 |
29 | # Retrieve Prefetch folder from endpoint
30 | $prefetchretrieve = Get-WindowsPrefetch -Target $Target
31 | $outcome.Add("PrefetchGetOutcome", $prefetchretrieve)
32 |
33 | # Stop the stopwatch
34 | $stopwatch.Stop()
35 |
36 | # Add the timing to output
37 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
38 |
39 | # Return the outcome to the user
40 | Write-Output $outcome
41 |
42 | }
--------------------------------------------------------------------------------
/Actions/WindowsProcessPostProcessing/Join-WIndowsProcessStartProcessStopLogs.psm1:
--------------------------------------------------------------------------------
1 | function Join-WindowsProcessStartProcessStopLogs {
2 | <#
3 | .SYNOPSIS
4 | Joins together the process start and process stop logs from event logs
5 |
6 | .DESCRIPTION
7 | Joins together the process start and process stop logs from event logs
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)]$Target
13 | )
14 |
15 | # Set up the outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Join-WindowsProcessArtefacts"
18 | "DateTime" = (Get-Date).ToString()
19 | "Target" = $Target
20 | }
21 |
22 | # Set up the stopwatch variable to measure how long this takes
23 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
24 |
25 | # Set up the base location
26 | $baselocation = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\ProcessedArtefacts"
27 |
28 | # Get the process start logs
29 | $location = $baselocation + "\processstarts.json"
30 | $processstartlogs = Get-Content -Path $location | ConvertFrom-Json
31 | $processstartlogs = $processstartlogs.ProcessStartLogs
32 |
33 | # Get the process stop logs
34 | $location = $baselocation + "\processstops.json"
35 | $processstoplogs = Get-Content -Path $location | ConvertFrom-Json
36 | $processstoplogs = $processstoplogs.ProcessStopLogs
37 |
38 | $results = @()
39 |
40 | # For each process start, find the corresponding process stop if it exists
41 | foreach($processstart in $processstartlogs){
42 | # Get the Process Id
43 | $processid = $processstart.ProcessID
44 | $processstartpath = $processstart.ProcessStartPath
45 | $exename = $processstartpath.Split("\")[-1]
46 |
47 | # Get the process start date
48 | $processstartdate = $processstart.DateTime
49 |
50 | # Confirm if that value exists in the Process Stop logs
51 | $procstopexists = $processstoplogs.ProcessId -contains $processid
52 |
53 | # Set up the processstop results intermediate storage
54 | $intermediateresults = @()
55 |
56 | # If it does, iterate through the list and store any of those Process Ids
57 | if($procstopexists -eq $true){
58 | # Iterate through all the process stop events to add them to an initial holding array
59 | foreach($processstop in $processstoplogs){
60 | # Get the time the process stopped
61 | $processstopdate = $processstop.DateTime
62 | if($processstopdate -gt $processstartdate){
63 | # Find the process Id
64 | if($processstop.ProcessId -eq $processid){
65 | # Confirm the process start path matches
66 | if($processstop.ProcessStartPath -eq $processstartpath){
67 | # Store the intermediate results so they can be de-duped
68 |
69 | $intermediateresults += $processstop
70 | }
71 | }
72 | }
73 |
74 | }
75 | }else {
76 | $processobject = @{
77 | "ProcessId" = $processid
78 | "ProcessStartPath" = $processstartpath
79 | "ProcessStopFound" = $false
80 | }
81 | }
82 |
83 | # Sort the intermediate results by DateTime, select the one closest to the start time of the process start
84 | $firstprocessstop = $intermediateresults | Sort-Object -Property DateTime | Select-Object -First 1
85 |
86 | # Create the process object to output
87 | $processobject = @{
88 | "ProcessId" = $processid
89 | "StartPath" = $processstartpath
90 | "ProcessStartTime" = $processstart.DateTime
91 | "ProcessStopTime" = $firstprocessstop.DateTime
92 | "ProcessCommandLine" = $processstart.ProcessCommandLine
93 | "ParentProcessID" = $processstart.ParentProcessID
94 | "SecurityID" = $processstart.SecurityID
95 | "CreatorSecurityID" = $processstart.CreatorSecurityID
96 | "EventLogProcessStartRecordId" = $processstart.EventLogRecordId
97 | "EventLogProcessStopRecordId" = $firstprocessstop.EventLogRecordId
98 | "ProcessStartEventLog" = $true
99 | "ProcessStopEventLog" = $true
100 | "FullProcessStartObject" = $processstart
101 | "FullProcessStopObject" = $firstprocessstop
102 | "ExecutableName" = $exename
103 | }
104 |
105 | # Add to the results array
106 | $results += $processobject
107 | }
108 |
109 | # Add the results to the outcome
110 | $outcome.Add("ProcessObjects", $results)
111 |
112 | # Stop the stopwatch
113 | $stopwatch.Stop()
114 |
115 | # Add the timing to output
116 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
117 |
118 | # Return back to user
119 | Write-Output $outcome
120 |
121 | }
--------------------------------------------------------------------------------
/Actions/WindowsProcessPostProcessing/Join-WindowsProcessArtefacts.psm1:
--------------------------------------------------------------------------------
1 | function Join-WindowsProcessArtefacts {
2 | <#
3 | .SYNOPSIS
4 | Processes the avaiable forensic artefacts for processes together to create a single unified process object.
5 |
6 | .DESCRIPTION
7 | Processes the avaiable forensic artefacts for processes together to create a single unified process object.
8 | Requires the Invoke-CoreForensicArtifactGathering and Processing Playbooks to have run.
9 |
10 | #>
11 | [CmdletBinding()]
12 | param (
13 | [Parameter(Mandatory=$true)]$Target
14 | )
15 |
16 | # Set up the outcome variable
17 | $outcome = @{
18 | "HostHunterObject" = "Join-WindowsProcessArtefacts"
19 | "DateTime" = (Get-Date).ToString()
20 | "Target" = $Target
21 | }
22 |
23 | # Set up the stopwatch variable to measure how long this takes
24 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
25 |
26 | # Set up the base location
27 | $baselocation = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\ProcessedArtefacts"
28 |
29 | # Join Windows ProcessStart and ProcessStop Event Logs together
30 | $process = Join-WindowsProcessStartProcessStopLogs -Target $Target
31 |
32 | # Search through Prefetch and try to match the Processes
33 |
34 | # Add in PSList from Volatility
35 |
36 | # Add in PSScan from Volatility
37 |
38 |
39 |
40 | # For now, let's work with a single process to develop a search strategy
41 | # 1. Get a current process which I know about
42 | # 2. Let's work through all the artefacts I have - process start, process stop, prefetch, memory, SRUM. What is unique across all of them?
43 |
44 | # Add the outcomes from process into the object to be returned
45 | $outcome.Add("ProcessObjects", $process)
46 |
47 | # Stop the stopwatch
48 | $stopwatch.Stop()
49 |
50 | # Add the timing to output
51 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
52 |
53 | # Return back to user
54 | Write-Output $outcome
55 |
56 | }
--------------------------------------------------------------------------------
/Actions/WindowsRegistryRetrieval/Copy-WindowsRegistry.psm1:
--------------------------------------------------------------------------------
1 | function Copy-WindowsRegistry{
2 | <#
3 | .SYNOPSIS
4 | Copies Windows Registry hive from target endpoints
5 |
6 | .DESCRIPTION
7 | Copies the Windows Registry hive from target endpoint. Current registry hives targeted outlined below:
8 | 1. HKCR. HKEY_CLASSES_ROOT
9 | 2. HKCU. HKEY_CURRENT_USER
10 | 3. HKLM. HKEY_LOCAL_MACHINE
11 | 4. HKU. HKEY_USERS
12 | 5. HKEY_CURRENT_CONFIG
13 | #>
14 |
15 | [CmdletBinding()]
16 | param (
17 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
18 | )
19 |
20 | # Set up the outcome variable
21 | $outcome = @{
22 | "HostHunterObject" = "Copy-WindowsRegistry"
23 | "DateTime" = (Get-Date).ToString()
24 | "TargetHostName" = $target
25 | }
26 |
27 |
28 | $copylog = Invoke-HostHunterCommand -Target $Target -Scriptblock{
29 | # Set up the output variable
30 | $Output = @{
31 | "DateTime" = (Get-Date).ToString()
32 | }
33 |
34 | # Create a registry folder in PerformanceInformation
35 | $registry = New-Item -Path "C:\PerformanceInformation" -Name "Registry" -ItemType Directory
36 | $Output.Add("RegistryFolderCreated", $registry)
37 |
38 | # Use reg export to get HKCR
39 | reg export HKCR C:\PerformanceInformation\Registry\HKCR.reg /y
40 |
41 | # Use reg export to get HKCU
42 | reg export HKCU C:\PerformanceInformation\Registry\HKCU.reg /y
43 |
44 | # Use reg export to get HKLM
45 | reg export HKLM C:\PerformanceInformation\Registry\HKLM.reg /y
46 |
47 | # Use reg export to get HKU
48 | reg export HKU C:\PerformanceInformation\Registry\HKU.reg /y
49 |
50 | # Use reg export to get HKCC
51 | reg export HKCC C:\PerformanceInformation\Registry\HKCC.reg /y
52 | }
53 |
54 | # Add output to the outcome variable
55 | $outcome.Add("CopyWindowsRegistryOutcome", $copylog)
56 |
57 | # Return outcomes to users
58 | Write-Output $outcome
59 |
60 | }
--------------------------------------------------------------------------------
/Actions/WindowsRegistryRetrieval/Get-WindowsRegistryFiles.psm1:
--------------------------------------------------------------------------------
1 | function Get-WindowsRegistryFiles {
2 | <#
3 | .SYNOPSIS
4 | Gets the Registry files dumped by Copy-WindowsRegistry command
5 |
6 | .DESCRIPTION
7 | Copies the following Windows Registry hives from remote endpoint https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry
8 | 1. HKCR. HKEY_CLASSES_ROOT
9 | 2. HKCU. HKEY_CURRENT_USER
10 | 3. HKLM. HKEY_LOCAL_MACHINE
11 | 4. HKU. HKEY_USERS
12 | 5. HKEY_CURRENT_CONFIG
13 |
14 | #>
15 | [CmdletBinding()]
16 | param (
17 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
18 | )
19 |
20 | # Set up outcome variable
21 | $outcome = @{
22 | "HostHunterObject" = "Get-WindowsRegistryFiles"
23 | "DateTime" = (Get-Date).ToString()
24 | "TargetEndpoint" = $Target
25 | }
26 |
27 | # Set up the stopwatch variable to measure how long this takes
28 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
29 |
30 | # Get the HostName from the session
31 | $hostname = $target.ComputerName
32 |
33 | # Set up the location where artifacts will be extracted to
34 | $location = "C:\ExtractionDirectory\" + $hostname + "_ForensicArtifacts"
35 |
36 | # Copy the folder across, including recursive files
37 | $copyitem = Copy-Item -FromSession $Target -Path "C:\PerformanceInformation\Registry" -Recurse -Destination $location
38 |
39 | # Check for a range of Registry Artefacts being successfully extracted
40 | $reglocation = $location + "\Registry"
41 |
42 | # Check for registry folder
43 | $regfolder = Test-Path -Path $reglocation
44 | $outcome.Add("RegistryFolder", $regfolder)
45 |
46 | # Check for software hive
47 | $softwarehivelocation = $reglocation + "\HKLM.reg"
48 | $softwarehive = Test-Path -Path $softwarehivelocation
49 | $outcome.Add("SoftwareRegistryHive", $softwarehive)
50 |
51 | # Add the outcome to the outcome variable
52 | $outcome.Add("CopyInformation", $copyitem)
53 |
54 | # Stop the stopwatch
55 | $stopwatch.Stop()
56 |
57 | # Add the timing to output
58 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
59 |
60 | # Return outcome to the user
61 | Write-Output $outcome
62 |
63 | }
--------------------------------------------------------------------------------
/Actions/WindowsRegistryRetrieval/Invoke-GetWindowsRegistry.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-GetWindowsRegistry{
2 | <#
3 | .SYNOPSIS
4 | Combines the Copy-WindowsRegistryFiles and Get-WindowsRegistryFiles cmdlets together to enable Incident Responder to get registry files from specified target
5 |
6 | .DESCRIPTION
7 | Combines the Copy-WindowsRegistry and Get-WindowsRegistryFiles cmdlets together to enable Incident Responder to get registry files from specified target
8 |
9 | #>
10 |
11 | [CmdletBinding()]
12 | param (
13 | [Parameter(Mandatory=$true)][System.Management.Automation.Runspaces.PSSession]$Target
14 | )
15 |
16 | # Set up the output variable
17 | $output = @{
18 | "HostHunterObject" = "Invoke-GetWindowsRegistry"
19 | "DateTime" = (Get-Date).ToString()
20 | "TargetHostName" = $Target
21 | }
22 |
23 | # If a playbook is being used, set this up to run in parallel
24 |
25 | # Copy the registry files, add the output to the output variable
26 | $copyfiles = Copy-WindowsRegistry -Target $Target
27 | $output.Add("CopyWindowsRegistryFiles", $copyfiles)
28 |
29 | # Extract the registry files to target endpoint and add the results to the output variable
30 | $getfiles = Get-WindowsRegistryFiles -Target $Target
31 | $output.Add("GetWindowsRegistryFiles", $getfiles)
32 |
33 |
34 | # Return the output to the user
35 | Write-Output $output
36 |
37 | }
--------------------------------------------------------------------------------
/Actions/WindowsRegistryRetrieval/New-RegistryFileFolder.psm1:
--------------------------------------------------------------------------------
1 | function New-RegistryFileFolder{
2 | <#
3 | .SYNOPSIS
4 | Creates a new folder in Extracted Artifacts to store extracted registry files
5 |
6 | .DESCRIPTION
7 | Creates a new folder in Extracted Artifacts to store extracted registry files
8 | #>
9 |
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)][string]$Target
13 | )
14 |
15 | # Create output variable
16 | $output = @{
17 | "HostHunterObject" = "New-RegistryFileFolder"
18 | "DateTime" = (Get-Date).ToString()
19 | }
20 |
21 | # Set up the path to be used for the extraction directory
22 | $location = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts"
23 |
24 | # Test to see if folder already exists
25 | $path = Test-Path -Path C:\ExtractionDirectory\Registry
26 |
27 | # If path does not exist, create
28 | if($path -ne $true){
29 | New-Item -Path $location -Name "Registry" -ItemType Directory | Out-Null
30 | }
31 |
32 | # Store output
33 | $output.Add("FolderCreated", $true)
34 |
35 | # Return output to user
36 | Write-Output $output
37 | }
--------------------------------------------------------------------------------
/Actions/WindowsSRUProcessing/Format-SRUDBtoJSON.psm1:
--------------------------------------------------------------------------------
1 | function Format-SRUDBtoJSON {
2 | <#
3 | .SYNOPSIS
4 | Converts an extracted SRU Database into a series of JSON files
5 |
6 | .DESCRIPTION
7 | Converts an extracted SRU Database into a series of JSON files. Does this using two commandlets
8 |
9 |
10 | #>
11 | [CmdletBinding()]
12 | param (
13 | [Parameter(Mandatory=$true)]$Target,
14 | [Parameter()][switch]$registryexists
15 | )
16 |
17 | # Set up the outcome variable
18 | $outcome = @{
19 | "HostHunterObject" = "Format-SRUDBtoJSON"
20 | "DateTime" = (Get-Date).ToString()
21 | "Target" = $Target
22 | }
23 |
24 | # Set up the stopwatch variable to measure how long this takes
25 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
26 |
27 | # Convert SRU to XLSX using Mark Baggerts SRUMDUMP2
28 | if($registryexists){
29 | $srumdump = Format-SRUDBtoXLSX -Target $Target -registryexists
30 | }else {
31 | $srumdump = Format-SRUDBtoXLSX -Target $Target
32 | }
33 |
34 | $outcome.Add("SRUMDumpOutcome", $srumdump)
35 |
36 | #Convert SRUM Dump to JSON
37 | $srumtojson = Format-SrumDumptoJson -Target $Target
38 | $outcome.Add("SRUMtoJSON", $srumtojson)
39 |
40 | # Stop the stopwatch
41 | $stopwatch.Stop()
42 |
43 | # Add the timing to output
44 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
45 |
46 | # Return back to user
47 | Write-Output $outcome
48 |
49 | }
--------------------------------------------------------------------------------
/Actions/WindowsSRUProcessing/Format-SRUDBtoXLSX.psm1:
--------------------------------------------------------------------------------
1 | function Format-SRUDBtoXLSX {
2 | <#
3 | .SYNOPSIS
4 | Gets the SRUDB.dat file and runs the excellent srum-dump executeable by Mark Baggett
5 |
6 | .DESCRIPTION
7 | Uses the excellent work done by Mark Baggett here: https://github.com/MarkBaggett/srum-dump
8 | Transforms the information from SRUDB into an excel file
9 |
10 | #>
11 | param (
12 | [Parameter(Mandatory=$true)][string]$Target,
13 | [Parameter()][switch]$registryexists
14 | )
15 |
16 | # Create the outcome dictionary
17 | $outcome = @{
18 | "HostHunterObject" = "Format-SRUDBtoXLSX"
19 | "DateTime" = (Get-Date).ToString()
20 | "Target" = $target
21 | }
22 |
23 | # Set up the stopwatch variable to measure how long this takes
24 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
25 |
26 | # Create input location
27 | $inputloc = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\EventLoggingandSRU\sru\SRUDB.dat"
28 |
29 | # Add to the output object
30 | $outcome.Add("InputLocation", $inputloc)
31 |
32 | # Create the output location
33 | $outputloc = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\ProcessedArtefacts\sru_database.xlsx"
34 |
35 | # Add to the output object
36 | $outcome.Add("OutputLocation", $outputloc)
37 |
38 | # If registry exists, run file with registry option
39 | if($registryexists){
40 | $outcome.Add("RegistryExists", $true)
41 |
42 | # Set up the registry hive location
43 | $registryhive = "C:\ExtractionDirectory\" + $target + "_ForensicArtifacts\Registry\HKLM.reg"
44 | $outcome.Add("RegistryHiveLocation", $registryhive)
45 |
46 | # Run the executeable
47 | $srumdb = .\Executeables\srum_dump2.exe --SRUM_INFILE $inputloc --XLSX_OUTFILE $outputloc --XLSX_TEMPLATE ".\Executeables\SRUM_TEMPLATE2.xlsx" --REG_HIVE $registryhive
48 | $outcome.Add("SRUMDump2Output", $srumdb)
49 | }else {
50 | $outcome.Add("RegistryExists", $false)
51 |
52 | # Set up the registry hive location
53 | $registryhive = "Doesnotexist"
54 | $outcome.Add("RegistryHiveLocation", $srumdb)
55 |
56 | # Run the executeable
57 | $srumdb = .\Executeables\srum_dump2.exe --SRUM_INFILE $inputloc --XLSX_OUTFILE $outputloc --XLSX_TEMPLATE ".\Executeables\SRUM_TEMPLATE2.xlsx"
58 | $outcome.Add("SRUMDump2Output", $srumdb)
59 | }
60 |
61 | # Test SRU Formatted file exists
62 | $sruoutput = Test-Path -Path $outputloc
63 | $outcome.Add("SRUXLSFileOutcome", $sruoutput)
64 |
65 | # Convert XLS file into JSON
66 | if($sruoutput -eq $true){
67 |
68 | }
69 |
70 | # Stop the stopwatch
71 | $stopwatch.Stop()
72 |
73 | # Add the timing to output
74 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
75 |
76 | # Return outcomes to the user
77 | Write-Output $output
78 | }
--------------------------------------------------------------------------------
/Actions/WindowsSRUProcessing/Format-SrumDumptoJson.psm1:
--------------------------------------------------------------------------------
1 | function Format-SrumDumptoJson {
2 | <#
3 | .SYNOPSIS
4 | Takes the output from srumdump2 and converts key sheets into Json
5 |
6 | .DESCRIPTION
7 | Takes the output from srumdump2 and converts key sheets into Json. Does this by first converting into csv, then doing conversion.
8 | Uses the ImportExcel module by dfinke https://github.com/dfinke/ImportExcel
9 |
10 | #>
11 | [CmdletBinding()]
12 | param (
13 | [Parameter(Mandatory=$true)]$Target
14 | )
15 |
16 | # Set up the outcome variable
17 | $outcome = @{
18 | "HostHunterObject" = "Format-SrumDumptoJson"
19 | "DateTime" = (Get-Date).ToString()
20 | "Target" = $Target
21 | }
22 |
23 | # Set up the stopwatch variable to measure how long this takes
24 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
25 |
26 | # Set up the filepath
27 | $location = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\ProcessedArtefacts\sru_database.xlsx"
28 | $location2 = "C:\ExtractionDirectory\" + $Target + "_ForensicArtifacts\ProcessedArtefacts"
29 |
30 | # Extract the worksheets I want and turn them into CSVs. Then import and turn into json. This is done as trying to convert directly to JSON is extremely time consuming
31 | # SRUM Network Usage Sheet
32 | $networkusage = Import-Excel -Path $location -WorksheetName "Network Usage"
33 | $outfile = $location2 + "\srum_network_usage.json"
34 | $networkusage | ConvertTo-Json | Out-File $outfile
35 | $outcome.Add("SRUMNetworkUsageJSON", $true)
36 |
37 | # SRUM Application Resource Usage
38 | $applicationresourceusage = Import-Excel -Path $location -WorksheetName "Application Resource Usage"
39 | $outfile = $location2 + "\srum_application_resource_usage.json"
40 | $applicationresourceusage | ConvertTo-Json | Out-File $outfile
41 | $outcome.Add("SRUMApplicationResourceUsageJSON", $true)
42 |
43 | # SRUM Network Connections
44 | $networkconnections = Import-Excel -Path $location -WorksheetName "Network Connections"
45 | $outfile = $location2 + "\srum_network_connections.json"
46 | $networkconnections | ConvertTo-Json | Out-File $outfile
47 | $outcome.Add("SRUMNetworkConnectionsJSON", $true)
48 |
49 | # Stop the stopwatch
50 | $stopwatch.Stop()
51 |
52 | # Add the timing to output
53 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
54 |
55 | # Return back to user
56 | Write-Output $outcome
57 |
58 | }
--------------------------------------------------------------------------------
/CoreEndpointInteraction/Get-TargetList.psm1:
--------------------------------------------------------------------------------
1 | function Get-TargetList{
2 | <#
3 | .SYNOPSIS
4 | Gets a list of the current targets, and because it's fun prints them in red
5 |
6 | .DESCRIPTION
7 | Gets the private variable "GlobalTargetList" and prints a list of the endpoints being targeted
8 | #>
9 | param (
10 |
11 | )
12 |
13 | if ($GlobalTargetList -ne $null){
14 | $message = $GlobalTargetList.Keys
15 | }else{
16 | $message = "No Targets at this time"
17 | }
18 |
19 | #Write-HostHunterInformation -MessageData "Targets:" -ForegroundColor "Blue"
20 | #Write-HostHunterInformation -MessageData $message -ForegroundColor "Red"
21 |
22 | Write-Output $message
23 |
24 | }
--------------------------------------------------------------------------------
/CoreEndpointInteraction/Get-TargetSessions.psm1:
--------------------------------------------------------------------------------
1 | function Get-TargetSessions{
2 | <#
3 | .SYNOPSIS
4 | Returns a list of the current sessions available
5 |
6 | .DESCRIPTION
7 | Returns a list of the current sessions available
8 | #>
9 | param (
10 |
11 | )
12 |
13 | # Set up the output variable
14 | $output = @()
15 |
16 | # Get a list of the keys in the GlobalTargetList
17 | $targets = Get-Variable -Name GlobalTargetList
18 | $endpoints = $targets.Value.keys
19 |
20 | # Get the associated sessions from the target list
21 | foreach ($target in $endpoints){
22 | # Get the associated session
23 | $session = $targets.Value[$target]["PSSession"]
24 | $output += $session
25 | }
26 |
27 | # Return the output to the user
28 | Write-Output $output
29 |
30 | }
--------------------------------------------------------------------------------
/CoreEndpointInteraction/Invoke-HostCommand.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-HostCommand{
2 | <#
3 | .SYNOPSIS
4 | Provides a mechanism to track and master the commands entered to remote endpoints
5 |
6 | .DESCRIPTION
7 | Complete alias for Invoke-Command using sessions
8 |
9 | #>
10 |
11 | [CmdletBinding()]
12 | param (
13 | [Parameter(Mandatory=$true)]$Scriptblock,
14 | [Parameter()][switch]$RegisterCommand,
15 | [Parameter()]$SimpleCommand,
16 | [Parameter()]$Targets="",
17 | [Parameter()][switch]$silent,
18 | [Parameter()][switch]$partofplaybook,
19 | [Parameter()][switch]$notjob,
20 | [Parameter()][System.Management.Automation.PSCredential]$Credential
21 | )
22 |
23 |
24 |
25 | # Determine how command is to be run. Is this going to be a job, silent, part of a playbook etc
26 | if($partofplaybook){
27 | # A new session will need to be created
28 | $session = New-PSSession -ComputerName $Targets -Credential $cred
29 | # Take command and run it without piping it into a job
30 | $HostHunterCommand = Invoke-Command -Session $session -ScriptBlock $Scriptblock
31 | }elseif (notjob) {
32 | # Set up targets
33 | if($Targets -eq ""){
34 | # Get the current list of target powershell sessions
35 | $targets = Get-PSSession
36 | }else{
37 | $Targets = Get-PSSession | Where-Object {$_.ComputerName -eq $Targets}
38 | }
39 |
40 | # Run command without using a job
41 | $HostHunterCommand = Invoke-Command -Session $targets -ScriptBlock $Scriptblock
42 | }
43 | else{
44 | # Set up targets
45 | if($Targets -eq ""){
46 | # Get the current list of target powershell sessions
47 | $targets = Get-PSSession
48 | }else{
49 | $Targets = Get-PSSession | Where-Object {$_.ComputerName -eq $Targets}
50 | }
51 | # Take command and run as a job
52 | $HostHunterCommand = Invoke-Command -Session $targets -ScriptBlock $Scriptblock -AsJob
53 | # Set up the SimpleCommand text for tooltip notification
54 | if($SimpleCommand -eq $null){
55 | $SimpleCommand = $Scriptblock.toString()
56 | }
57 |
58 | # If RegisterCommand switch selected, register the job
59 | if ($RegisterCommand){
60 | # Set up Message title
61 | $MessageTitle = $SimpleCommand + " Remote Job"
62 | # Update the message
63 | $Message = "Powershell job " + $SimpleCommand + " started"
64 | New-ToolTipNotification -MessageTitle $MessageTitle -MessageData $Message
65 | Register-ObjectEvent -InputObject $HostHunterCommand -EventName StateChanged -Action {
66 | if($sender.State -eq "Completed"){
67 | $MessageTitle = $SimpleCommand + " Remote Job"
68 | $global:RegisteredCommandOutput = Receive-Job -Id $sender.Id -AutoRemoveJob -Wait
69 | $Message = "Powershell job " + $SimpleCommand + " completed"
70 | New-TooltipNotification -MessageTitle $MessageTitle -Message $Message
71 | $eventSubscriber | Unregister-Event
72 | $eventSubscriber.Action | Remove-Job -Force
73 | }
74 | } | Out-Null
75 | }else{
76 | Do{
77 | $status = Get-Job -Id $HostHunterCommand.Id
78 | if($status.State -eq "Completed"){
79 | # If completed, get the results
80 | $output = Receive-Job -id $HostHunterCommand.Id
81 | # Now delete the job as it is completed
82 | Receive-Job -Job $HostHunterCommand -AutoRemoveJob -Wait
83 | Write-Output $output
84 | break
85 | }else{
86 | if($silent){
87 |
88 | }else{
89 | Write-HostHunterInformation -MessageData "Powershell job still running"
90 | }
91 | Start-Sleep -Seconds 1
92 | }
93 |
94 | }while ($true)
95 | }
96 | }
97 |
98 |
99 | }
--------------------------------------------------------------------------------
/CoreEndpointInteraction/Invoke-HostHunterCommand.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-HostHunterCommand {
2 | <#
3 | .SYNOPSIS
4 | Core of the endpoint interaction functions. Uses a combination of sessions, Invoke-Commands, jobs and so on to enable framework to operate at scale
5 |
6 | .DESCRIPTION
7 | To be updated
8 | #>
9 |
10 | [CmdletBinding()]
11 | param (
12 | [Parameter(Mandatory=$true)]$Scriptblock,
13 | [Parameter()]$Target
14 | # todo: DomainCommand variable
15 | )
16 |
17 | # Set up the output variable
18 | $output = @{
19 | "HostHunterObject" = "Invoke-HostHunterCommand"
20 | "DateTime" = (Get-Date).ToString()
21 | "CommandRun" = $Scriptblock
22 | "Target" = $Target
23 | }
24 |
25 | # Get the Data type of the connection
26 | $targetdatataype = $Target.GetType()
27 | $targetdatataype = $targetdatataype.Name
28 | $output.Add("TargetDataType", $targetdatataype)
29 |
30 | # If the data type is a PSSession, the command can be passed straight into the session. This reduces the number of forensic artefacts from the framework for forming new connections
31 | if($targetdatataype = "PSSession"){
32 | $runcommand = Invoke-Command -Session $Target -ScriptBlock $Scriptblock
33 | $output.Add("Outcome", $runcommand)
34 | }
35 |
36 | Write-Output $output
37 | }
--------------------------------------------------------------------------------
/CoreEndpointInteraction/New-EndpointSession.psm1:
--------------------------------------------------------------------------------
1 | function New-EndpointSession{
2 | <#
3 | .SYNOPSIS
4 | Creates a new endpoint session
5 | .DESCRIPTION
6 | Creates a session on specified endpoint, updates the GlobalTargetList
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | [Parameter(Mandatory=$true)]$Target,
12 | [Parameter(Mandatory=$true)][System.Management.Automation.PSCredential]$Credential
13 | )
14 |
15 | # Create output dictionary
16 | $output = @{
17 | "ObjectName" = "New-EndpointSession"
18 | "DateTime" = (Get-Date).ToString()
19 | }
20 |
21 | # Create the session depending on outcome
22 | try{
23 | $session = New-PSSession -ComputerName $Target -Credential $Credential -ErrorAction SilentlyContinue
24 | $output.Add("PSSession", $session)
25 | # Get some initial details about the endpoint
26 | $endpointdetails = Invoke-Command -Session $session -ScriptBlock{$env:COMPUTERNAME}
27 | $output.Add("EndpointDetails", $endpointdetails)
28 | # Add the new endpoint to GlobalTargetList
29 | $GlobalTargetList.Add($target, $output)
30 | }
31 | catch{
32 | $message = $target + " not created successfully"
33 | Write-HostHunterInformation -MessageData $message
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/CoreEndpointInteraction/New-Target.psm1:
--------------------------------------------------------------------------------
1 | function New-Target{
2 | <#
3 | .SYNOPSIS
4 | Creates a new target to be targeted
5 | .DESCRIPTION
6 | Creates a new target to be targeted
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | [Parameter(Mandatory=$true)][string[]]$Target
12 | )
13 |
14 | # Confirm if creds variable is set
15 | if ($cred -eq $null){
16 | $cred = Get-Credential
17 | }
18 |
19 | # Iterate through the input target and setup sessions
20 | foreach ($endpoint in $Target){
21 | # Check if already in list
22 | if($GlobalTargetList.ContainsKey($endpoint)){
23 | $message = "Target " + $endpoint + " already exists"
24 | Write-HostHunterInformation -MessageData $message
25 | }else{
26 | $targets = $endpoint
27 | if($GlobalTargetList.Count -ge 1){
28 | # Extract each target name
29 | foreach($targettobeadded in $GlobalTargetList.Values){
30 | Write-Host $targettobeadded.PSSession.ComputerName
31 | $targets = $targets + "," + $targettobeadded.PSSession.ComputerName
32 | }
33 |
34 | }
35 |
36 | Write-Host $targets
37 |
38 | # Notify user
39 | $message = "Adding " + $endpoint + " to TrustedHosts list"
40 | Write-HostHunterInformation -MessageData $message -ForegroundColor "Green"
41 |
42 | # Set the trusted hosts registry key
43 | Set-Item WSMan:\localhost\Client\TrustedHosts $targets -Force
44 |
45 | # Now create the endpoint session
46 | New-EndpointSession -Target $endpoint -Credential $cred
47 | }
48 | }
49 |
50 | # At the end of adding them all all, give the user a list of targets
51 | Get-TargetList
52 |
53 | }
--------------------------------------------------------------------------------
/CoreEndpointInteraction/Remove-EndpointSession.psm1:
--------------------------------------------------------------------------------
1 | function Remove-EndpointSession{
2 | <#
3 | .SYNOPSIS
4 | Removes an endpoint session
5 | .DESCRIPTION
6 | Removes an endpoint session
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | [Parameter(Mandatory=$true)]$Target
12 | )
13 |
14 | # Create output dictionary
15 | $output = @{
16 | "ObjectName" = "SessionRemoved"
17 | "DateTime" = (Get-Date).ToString()
18 | "Outcome" = "Failed"
19 | }
20 |
21 | # Find the session in the GlobalTargetList
22 | $contains = $GlobalTargetList.Contains($Target)
23 |
24 | # If the session exists, be awesome, close the session down then remove from the GlobalTargetList
25 | if($contains -eq $true){
26 | Get-PSSession | Where-Object {$_.ComputerName -eq $Target} | Remove-PSSession
27 | $output.Add("Endpoint", $Target)
28 | $GlobalTargetList.Remove($Target)
29 | $output.Outcome = "Success"
30 | }else{
31 | $message = $Target + ": Endpoint does not exist in target list"
32 | Write-HostHunterInformation -MessageData $message
33 | $output.Outcome = "DoesNotExist"
34 | }
35 |
36 | Write-Output $output
37 |
38 | }
--------------------------------------------------------------------------------
/CoreEndpointInteraction/Remove-Target.psm1:
--------------------------------------------------------------------------------
1 | function Remove-Target{
2 | <#
3 | .SYNOPSIS
4 | Removes a target from target list
5 | .DESCRIPTION
6 | Removes a target from the target list
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | [Parameter(Mandatory=$true)][string[]]$Target
12 | )
13 |
14 | # Iterate through the input target and setup sessions
15 | foreach ($endpoint in $Target){
16 | # Check if already in list
17 | if($GlobalTargetList.ContainsKey($endpoint)){
18 | # If yes, remove
19 | Remove-EndpointSession -Target $endpoint | Out-Null
20 | $message = "Target " + $endpoint + " removed"
21 |
22 | # todo: need to be able to remove targets dynamically
23 |
24 | }else{
25 | $message = "Target " + $endpoint + " is not currently targeted"
26 | }
27 |
28 | # Inform user
29 | Write-HostHunterInformation -MessageData $message
30 | }
31 |
32 | # At the end of adding them all all, give the user a list of targets
33 | Get-TargetList
34 |
35 | }
--------------------------------------------------------------------------------
/CoreEndpointInteraction/Update-Credentials.psm1:
--------------------------------------------------------------------------------
1 | function Update-Credentials {
2 | <#
3 | .SYNOPSIS
4 | Updates the global credential variable with new credentials
5 |
6 | .DESCRIPTION
7 | Updates the global credential variable with new credentials
8 |
9 | #>
10 | param (
11 |
12 | )
13 |
14 | $cred = Get-Credential
15 | Set-Variable -Name "cred" -Scope global -Visibility Public -Value $cred
16 |
17 | }
--------------------------------------------------------------------------------
/DockerVolume/Copy-ToDockerVolume.psm1:
--------------------------------------------------------------------------------
1 | function Copy-ToDockerVolume {
2 | <#
3 | .SYNOPSIS
4 | Copies data from the Extraction Directory to the Docker Volume 'forensicdata'
5 |
6 | .DESCRIPTION
7 | Copies data from the Extraction Directory to the Docker Volume 'forensicdata'. This allows the data to persist once container is destroyed
8 | #>
9 | [CmdletBinding()]
10 | param (
11 |
12 | )
13 |
14 | # Create outcome object
15 | $outcome = @{
16 | "HostHunterObject" = "Copy-ToDockerVolume"
17 | }
18 |
19 | # Copy item across to the volume
20 | Copy-Item -Path "C:\ExtractionDirectory\" -Destination "C:\forensicdata" -Recurse | Out-Null
21 |
22 | }
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Set the base image to be Microsoft provided Powershell Core image
2 | FROM mcr.microsoft.com/powershell:7.0.2-windowsservercore-1909
3 |
4 | # Set up some environment variables. Credit to Jung-Hyun Nam https://medium.com/rkttu/creating-python-docker-image-for-windows-nano-server-151e1ab7188a
5 | ENV PYTHON_VERSION 3.8.3
6 |
7 | # Change the shell to be powershell by default
8 | SHELL ["pwsh", "-Command", "$ErrorActionPreference = 'Stop';"]
9 |
10 | # Add in Python
11 | ADD https://www.python.org/ftp/python/3.8.3/python-3.8.3-amd64.exe /python-3.8.3.exe
12 |
13 | # Add in HostHunter
14 | ADD https://github.com/jimtin/IRCoreForensicFramework/archive/master.zip /HostHunter.zip
15 |
16 | # Expand the HostHunter zip
17 | RUN Expand-Archive -Path C:\\HostHunter.zip -Destination C:\\HostHunter
18 |
19 | # Rename the extracted HostHunter folder
20 | RUN Rename-Item -Path C:\\HostHunter\\IRCoreForensicFramework-master -NewName IRCoreForensicFramework
21 |
22 | # Download HostHunter executables to the install directory
23 | ## WinPmem
24 | ADD https://github.com/Velocidex/c-aff4/releases/download/v3.3.rc3/winpmem_v3.3.rc3.exe C:\\HostHunter\\IRCoreForensicFramework\\Executeables\\WinPmem.exe
25 | ## Srum_Dump2
26 | ADD https://github.com/MarkBaggett/srum-dump/blob/master/srum_dump2.exe C:\\HostHunter\\IRCoreForensicFramework\\Executeables\\srum_dump2.exe
27 | ## SRUM Dump Template
28 | ADD https://github.com/MarkBaggett/srum-dump/blob/master/SRUM_TEMPLATE2.xlsx C:\\HostHunter\\IRCoreForensicFramework\\Executeables\\SRUM_TEMPLATE2.exe
29 | ## Volatility3
30 | ADD https://github.com/volatilityfoundation/volatility3/archive/master.zip C:\\HostHunter\\IRCoreForensicFramework\\Executeables\\volatility3.zip
31 | ## Prefetch Parser PECmd.zip
32 | ADD https://f001.backblazeb2.com/file/EricZimmermanTools/PECmd.zip C:\\HostHunter\\IRCoreForensicFramework\\Executeables\\PECmd.zip
33 | ## ImportExcel Powershell module
34 | ### Set PSGallery to be trusted to avoid it being declined
35 | RUN Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted
36 | ### Install the module
37 | RUN Install-Module -Name ImportExcel -Force
38 | ### Set the repository back to untrusted
39 | RUN Set-PSRepository -Name 'PSGallery' -InstallationPolicy Untrusted
40 |
41 | # Create the Extraction Folder
42 | RUN mkdir C://ExtractionDirectory
43 |
44 | # Create the PythonAnalysisList folder
45 | RUN mkdir C://HostHunter//IRCoreForensicFramework//PythonAnalysisList
46 |
47 | # Expand Volatility
48 | RUN Expand-Archive -Path C:\\HostHunter\\IRCoreForensicFramework\\Executeables\\volatility3.zip C:\\HostHunter\IRCoreForensicFramework\\PythonAnalysisList
49 |
50 | # Rename to volatility 3
51 | RUN Rename-Item -Path C:\\HostHunter\IRCoreForensicFramework\\PythonAnalysisList\\volatility3-master -NewName volatility3
52 |
53 | # Delete the .github and development aspects of volatility3
54 | RUN Remove-Item -Path C:\\HostHunter\\IRCoreForensicFramework\\PythonAnalysisList\\volatility3\\.github -recurse
55 | RUN Remove-Item -Path C:\\HostHunter\\IRCoreForensicFramework\\PythonAnalysisList\\volatility3\\development -recurse
56 | RUN Remove-Item -Path C:\\HostHunter\\IRCoreForensicFramework\\PythonAnalysisList\\volatility3\\.gitignore
57 |
58 | # Add in the symbols tables to volatility3
59 | ## Windows Symbols
60 | ADD https://downloads.volatilityfoundation.org/volatility3/symbols/windows.zip C:\\HostHunter\\IRCoreForensicFramework\\PythonAnalysisList\\volatility3\\volatility\\symbols\\windows.zip
61 | ## MacOS Symbols
62 | ADD https://downloads.volatilityfoundation.org/volatility3/symbols/mac.zip C:\\HostHunter\\IRCoreForensicFramework\\PythonAnalysisList\\volatility3\\volatility\\symbols\\mac.zip
63 | ## Linux Symbols
64 | ADD https://downloads.volatilityfoundation.org/volatility3/symbols/linux.zip C:\\HostHunter\\IRCoreForensicFramework\\PythonAnalysisList\\volatility3\\volatility\\symbols\\linux.zip
65 |
66 | # Install python
67 | RUN C:\\python-3.8.3.exe /quiet InstallAllUsers=1 PrependPath=1
68 |
69 | # Enable Powershell Remoting
70 | RUN Enable-PSRemoting -Force
71 |
72 | # Set up the working directory
73 | WORKDIR C:\\HostHunter\\IRCoreForensicFramework
74 |
75 | # Upon start up, load HostHunter into memory space
76 | #CMD pwsh C://HostHunter//IRCoreForensicFramework//loadIRCore.ps1
--------------------------------------------------------------------------------
/Executeables/PECmd.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimtin/IRCoreForensicFramework/d5f6a283b9b45364859856b0e0ed7c6f7e6f3aa5/Executeables/PECmd.exe
--------------------------------------------------------------------------------
/Executeables/PECmd.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimtin/IRCoreForensicFramework/d5f6a283b9b45364859856b0e0ed7c6f7e6f3aa5/Executeables/PECmd.zip
--------------------------------------------------------------------------------
/Executeables/SRUM_TEMPLATE2.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimtin/IRCoreForensicFramework/d5f6a283b9b45364859856b0e0ed7c6f7e6f3aa5/Executeables/SRUM_TEMPLATE2.xlsx
--------------------------------------------------------------------------------
/Executeables/WinPmem.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimtin/IRCoreForensicFramework/d5f6a283b9b45364859856b0e0ed7c6f7e6f3aa5/Executeables/WinPmem.exe
--------------------------------------------------------------------------------
/Executeables/executeablemanifest.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "ExecutableName": "WinPmem.exe",
4 | "DownloadURL": "https://github.com/Velocidex/c-aff4/releases/download/v3.3.rc3/winpmem_v3.3.rc3.exe",
5 | "OutputPath": "Executeables"
6 | },
7 | {
8 | "ExecutableName": "srum_dump2.exe",
9 | "DownloadURL": "https://github.com/MarkBaggett/srum-dump/blob/master/srum_dump2.exe",
10 | "OutputPath": "Executeables"
11 | },
12 | {
13 | "ExecutableName": "SRUM_TEMPLATE2.xlsx",
14 | "DownloadURL": "https://github.com/MarkBaggett/srum-dump/blob/master/SRUM_TEMPLATE2.xlsx",
15 | "OutputPath": "Executeables"
16 | },
17 | {
18 | "ExecutableName": "volatility3.zip",
19 | "DownloadURL": "https://github.com/volatilityfoundation/volatility3/archive/master.zip",
20 | "OutputPath": "Executeables"
21 | },
22 | {
23 | "ExecutableName": "PECmd.zip",
24 | "DownloadURL": "https://f001.backblazeb2.com/file/EricZimmermanTools/PECmd.zip",
25 | "OutputPath": "Executeables"
26 | }
27 | ]
--------------------------------------------------------------------------------
/Executeables/srum_dump2.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimtin/IRCoreForensicFramework/d5f6a283b9b45364859856b0e0ed7c6f7e6f3aa5/Executeables/srum_dump2.exe
--------------------------------------------------------------------------------
/Executeables/volatility3.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimtin/IRCoreForensicFramework/d5f6a283b9b45364859856b0e0ed7c6f7e6f3aa5/Executeables/volatility3.zip
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/Playbooks/Invoke-CoreForensicArtifactGatheringPlaybook.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-CoreForensicArtifactGatheringPlaybook {
2 | <#
3 | .SYNOPSIS
4 | This orchestration (powershell would call it a workflow, but Powershell 7 no longer supports workflows) gets the core forensic outputs from an endpoint
5 |
6 | .DESCRIPTION
7 | This orchestration module invokes the following modules to get core forensic artefacts
8 | 1. Creates remote and local data staging locations
9 | 2. Captures some current state details for later comparison
10 | 3. Captures registry
11 | 4. Captures eventlogs and the SRU database
12 | 5. Dumps and extracts memory
13 |
14 | Can run on an arbitary number of remote machines, depending on disk space and network bandwidth
15 |
16 | #>
17 | [CmdletBinding()]
18 | param (
19 | [Parameter()]$targets=""
20 | )
21 |
22 | # Create output variable
23 | $output = @{
24 | "HostHunterObject" = "Invoke-CoreForensicArtifactGatheringPlaybook"
25 | "DateTimeCreated" = (Get-Date).ToString()
26 | "Target" = $targets
27 | }
28 |
29 | # Set the target
30 | if($targets -eq ""){
31 | $targets = Get-TargetList
32 | }
33 |
34 | # Provide feedback to user on what is going to progress
35 | foreach($target in $targets){
36 | $message = "Invoking CoreForensicArtifactsGathering Playbook on: " + $target
37 | Write-HostHunterInformation -MessageData $message -ForegroundColor "Green"
38 | }
39 |
40 | # Check that current endpoint has a local data staging location set up
41 | $localdata = New-LocalDataStagingLocation
42 |
43 | foreach($target in $targets){
44 | # Set up the target name
45 | $name = $target + ": ArtefactCollectionPlaybook"
46 |
47 | # Notify the user that it's started
48 | Write-HostHunterInformation -ToolTipNotification -MessageTitle $name -MessageData "Started"
49 |
50 | # Set up the root for importing modules
51 | $env:WhereAmI = Get-Location
52 | $endpointjob = Start-Job -Name $name -InitializationScript{
53 | # Import the modules needed for this playbook
54 | $modulepath = $env:WhereAmI + "\Playbooks\artefactgatheringmodules.txt"
55 | $modules = Get-Content -Path $modulepath
56 | foreach($module in $modules){
57 | Import-Module $module
58 | }
59 | } -ScriptBlock{
60 | # Set up the stopwatch variable to measure how long this takes
61 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
62 |
63 | # Create the endpoint outcomes
64 | $endpointoutcomes = @{
65 | "Target" = $args[0]
66 | }
67 |
68 | $target = $args[0]
69 | $cred = $args[1]
70 |
71 | # Create a new powershell session on the target. This is required as a Powershell Job is a brand new memory space
72 | $session = New-PSSession -ComputerName $target -Credential $cred
73 | $endpointoutcomes.Add("TargetSession", $session)
74 |
75 | # Convert the target variable into a session
76 | $target = $session
77 |
78 | # Create the staging location on the remote endpoint
79 | $remotedatastaginglocation = New-RemoteStagingLocation -Target $target
80 | $endpointoutcomes.Add("RemoteDataStaging", $remotedatastaginglocation)
81 |
82 | # Get current state details before being polluted with the rest of the artifact gathering
83 | $currentstate = Invoke-GetCurrentStateDetails -Target $target
84 | $endpointoutcomes.Add("CurrentState", $currentstate)
85 |
86 | # Get Windows prefetch information
87 | $prefetch = Invoke-GetWindowsPrefetch -Target $Target
88 | $endpointoutcomes.Add("Prefetch", $prefetch)
89 |
90 | # Get Windows Registry files
91 | $windowsregistry = Invoke-GetWindowsRegistry -Target $target
92 | $endpointoutcomes.Add("WindowsRegistry", $windowsregistry)
93 |
94 | # Get remote memory
95 | $remotememory = Invoke-GetRemoteMemory -Target $Target
96 | $endpointoutcomes.Add("WindowsRemoteMemory", $remotememory)
97 |
98 | # Get event logs and SRU
99 | $windowseventlogsandsru = Invoke-GetRemoteEventLogsandSRU -Target $target
100 | $endpointoutcomes.Add("WindowsEventLogs", $windowseventlogsandsru)
101 |
102 | # Remove artifacts from remote endpoint
103 | $removal = Remove-RemoteStagingLocation -Target $target
104 | $endpointoutcomes.Add("RemoveStagingLocation", $removal)
105 |
106 | # Stop the stopwatch
107 | $stopwatch.Stop()
108 |
109 | # Add the timing to output
110 | $endpointoutcomes.Add("TimeTaken", $stopwatch.Elapsed)
111 |
112 | # Write the events undertaken to the folder
113 | Out-Events -Target $target -CommandHistory $endpointoutcomes
114 |
115 | Write-Output $endpointoutcomes
116 | } -ArgumentList $target, $cred
117 |
118 | Register-ObjectEvent -InputObject $endpointjob -EventName StateChanged -MessageData $target -Action {
119 | if($sender.State -eq "Completed"){
120 | $target = ($sender.Name -split ":")[0]
121 | $name = $target + ": ArtefactCollectionPlaybook"
122 |
123 | # Notify the user that it's completed
124 | Write-HostHunterInformation -ToolTipNotification -MessageTitle $name -MessageData "Completed"
125 |
126 | # Receive the sending job and remove it from the list
127 | Receive-Job -Id $sender.Id -AutoRemoveJob -Wait
128 |
129 | # Unregister the event
130 | $eventSubscriber | Unregister-Event
131 | $eventSubscriber.Action | Remove-Job -Force
132 | }
133 | } | Out-Null
134 |
135 |
136 | }
137 |
138 | # Return outcome to user
139 | Write-Output $output
140 | }
--------------------------------------------------------------------------------
/Playbooks/Invoke-CoreForensicArtifactProcessingPlaybook.psm1:
--------------------------------------------------------------------------------
1 | function Invoke-CoreForensicArtifactProcessingPlaybook {
2 | <#
3 | .SYNOPSIS
4 | Processes all available forensic artifacts collected by the CoreForensicArtifactGathering Playbook
5 |
6 | .DESCRIPTION
7 | Processes all available forensic artifacts collected by the CoreForensicArtifactGathering Playbook
8 |
9 | #>
10 | [CmdletBinding()]
11 | param (
12 | [Parameter()]$Target = ""
13 | )
14 |
15 | # Set up the outcome variable
16 | $outcome = @{
17 | "HostHunterObject" = "Invoke-CoreForensicArtifactProcessingPlabook"
18 | "DateTime" = (Get-Date).ToString()
19 | }
20 |
21 | # Set up the stopwatch variable to measure how long this takes
22 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
23 |
24 | # If a specific endpoint is not requested, get targets from the ExtractionDirectory
25 | if($Target -eq ""){
26 | # Declare $target as an array
27 | $target = @()
28 |
29 | # Get the directories under C:\ExtractionDirectory
30 | $endpoints = Get-ChildItem -Path C:\ExtractionDirectory
31 |
32 | # Get the Target name from the Command History file. If this doesn't exist, this playbook cannot be used
33 | foreach($computer in $endpoints){
34 | # Construct the path
35 | $commandhistorypath = "C:\ExtractionDirectory\" + $computer.Name + "\RemoteEndpointCommandHistory\RemoteEndpointCommandHistory.json"
36 |
37 | # Test if it exists
38 | $path = Test-Path -Path $commandhistorypath
39 |
40 | # If it exists, extract the Target and create a processed artefacts folder
41 | if($path -eq $true){
42 | $targetinfo = Get-Content -Path $commandhistorypath | ConvertFrom-Json
43 | $target += $targetinfo.Target
44 | New-ProcessedArtefactsStagingLocation -Target $targetinfo.Target
45 | }
46 | }
47 | }else {
48 | # Simply create the processed artefact staging location
49 | New-ProcessedArtefactsStagingLocation -Target $Target
50 | }
51 |
52 | # For each target, start a job
53 | foreach($endpoint in $Target){
54 | # Set up the environment variable to declare root directory
55 | $env:WhereAmI = Get-Location
56 |
57 | # Set up the name of the job
58 | $name = $Target + ": ArtefactProcessingPlaybook"
59 |
60 | # Notify user in commandline
61 | $message = $name + " started. Job registered."
62 | Write-HostHunterInformation -MessageData $message -ForegroundColor "Green"
63 |
64 | # Notify user that job has started
65 | Write-HostHunterInformation -ToolTipNotification -MessageTitle $name -MessageData "Started"
66 |
67 | # Convert to a string
68 | $name = $name.tostring()
69 |
70 | # Start the job
71 | $artefactprocessing = Start-Job -Name $name -InitializationScript{
72 | # Import the modules needed for this playbook
73 | $modulepath = $env:WhereAmI + "\Playbooks\artefactprocessingmodules.txt"
74 | $modules = Get-Content -Path $modulepath
75 | foreach($module in $modules){
76 | Import-Module $module
77 | }
78 | } -ScriptBlock{
79 | # Create the endpoint outcomes dictionary
80 | $endpointoutcomes = @{
81 | "Target" = $args[0]
82 | }
83 |
84 | # Set up the stopwatch variable to measure how long this takes
85 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
86 |
87 | # Set up the target
88 | $target = $args[0]
89 |
90 | # Get the outcome from the ArtifactGathering Process
91 | $artifactgatheringoutcomes = "C:\ExtractionDirectory\" + $target + "_ForensicArtifacts\RemoteEndpointCommandHistory\RemoteEndpointCommandHistory.json"
92 | $targetinfo = Get-Content $artifactgatheringoutcomes | ConvertFrom-Json
93 |
94 | # If remote srudb successful, process it
95 | if($targetinfo.WindowsEventLogs.EventLogExtraction.SRUExtractionOutcome -eq $true){
96 | # Depending on if registry hive successfully extracted, process SRU DB
97 | if($targetinfo.WindowsRegistry.GetWindowsRegistryFiles.SoftwareRegistryHive -eq $true){
98 | $sruformat = Format-SRUDBtoJson -Target $target -registryexists
99 | }else {
100 | $sruformat = Format-SRUDBtoJSON -Target $target
101 | }
102 |
103 | # Add outcome to endpoint outcomes
104 | $endpointoutcomes.Add("SRUProcessed", $sruformat)
105 | }
106 |
107 | # If getting event logs is successful, process them
108 | if($targetinfo.WindowsEventLogs.EventLogExtraction.EventLogExtractionOutcome -eq $true){
109 | $eventlogs = Invoke-EventLogProcessing -Target $target
110 | $endpointoutcomes.Add("EventLogProcessing", $eventlogs)
111 | }
112 |
113 | # If getting prefetch was successful, process this
114 | if($targetinfo.Prefetch.PrefetchGetOutcome.PrefetchExtractionOutcome -eq $true){
115 | $prefetch = Format-WindowsPrefetch -Target $target
116 | $endpointoutcomes.Add("Prefetch", $prefetch)
117 | }
118 |
119 | # If getting windows memory was successful, process this
120 | if($targetinfo.WindowsRemoteMemory.MemoryDumpRetrieved -eq $true){
121 | $memoryprocessing = Invoke-WindowsMemoryImageProcessing -Target $target
122 | $endpointoutcomes.Add("MemoryProcessing", $memoryprocessing)
123 | }
124 |
125 | # Stop the stopwatch
126 | $stopwatch.Stop()
127 |
128 | # Add the timing to output
129 | $endpointoutcomes.Add("TimeTaken", $stopwatch.Elapsed)
130 |
131 | # Convert all the information on performance etc into JSON and then save in ProcessedArtefacts folder
132 | $fileloc = "C:\ExtractionDirectory\" + $target + "_ForensicArtifacts\ProcessedArtefacts\commandhistory.json"
133 | $endpointoutcomes | ConvertTo-Json | Out-File $fileloc
134 |
135 | # Return outcome to user
136 | Write-Output $endpointoutcomes
137 | } -ArgumentList $endpoint
138 |
139 | Register-ObjectEvent -InputObject $artefactprocessing -EventName StateChanged -MessageData $target -Action {
140 | if($sender.State -eq "Completed"){
141 | $target = ($sender.Name -split ":")[0]
142 | $name = $target + ": ArtefactProcessingPlaybook"
143 |
144 | # Notify the user that it's completed
145 | Write-HostHunterInformation -ToolTipNotification -MessageTitle $name -MessageData "Completed"
146 |
147 | # Receive the sending job and remove it from the list
148 | Receive-Job -Id $sender.Id -AutoRemoveJob -Wait
149 |
150 | # Unregister the event
151 | $eventSubscriber | Unregister-Event
152 | $eventSubscriber.Action | Remove-Job -Force
153 | }
154 | } | Out-Null
155 | }
156 |
157 | # Add the timing to output
158 | $outcome.Add("TimeTaken", $stopwatch.Elapsed)
159 |
160 | # Add the results to outcome dictionary
161 | $outcome.Add("EndpointOutcomes", $pathexists)
162 |
163 | # Return results to pwsh
164 | Write-Output $outcome
165 | }
--------------------------------------------------------------------------------
/Playbooks/artefactgatheringmodules.txt:
--------------------------------------------------------------------------------
1 | .\Actions\WindowsRegistryRetrieval\Copy-WindowsRegistry.psm1
2 | .\Actions\WindowsRegistryRetrieval\Invoke-GetWindowsRegistry.psm1
3 | .\Actions\WindowsRegistryRetrieval\Get-WindowsRegistryFiles.psm1
4 | .\Actions\CreateStagingLocation\New-RemoteStagingLocation.psm1
5 | .\CoreEndpointInteraction\Invoke-HostHunterCommand.psm1
6 | .\Actions\WindowsMemoryRetrieval\Compare-MemoryHashes.psm1
7 | .\Actions\WindowsMemoryRetrieval\Get-ExtractedMemoryHash.psm1
8 | .\Actions\WindowsMemoryRetrieval\Get-MemoryDump.psm1
9 | .\Actions\WindowsMemoryRetrieval\Get-RemoteMemoryHash.psm1
10 | .\Actions\WindowsMemoryRetrieval\Invoke-GetRemoteMemory.psm1
11 | .\Actions\WindowsMemoryRetrieval\Invoke-MemoryDump.psm1
12 | .\Actions\WindowsMemoryRetrieval\Move-WinPMEM.psm1
13 | .\Actions\WindowsEventLogandSRURetrieval\Invoke-GetRemoteEventLogsandSRU.psm1
14 | .\Actions\WindowsEventLogandSRURetrieval\Copy-RemoteEventLogging.psm1
15 | .\Actions\WindowsEventLogandSRURetrieval\Get-RemoteEventLogging.psm1
16 | .\Actions\RemoveRemoteArtifacts\Remove-RemoteStagingLocation.psm1
17 | .\Actions\EventCapture\Out-Events.psm1
18 | .\Actions\CreateStagingLocation\New-CurrentStateStagingLocation.psm1
19 | .\Actions\WindowsCurrentStateDetailsRetrieval\Get-CurrentProcesses.psm1
20 | .\Actions\WindowsCurrentStateDetailsRetrieval\Invoke-GetCurrentStateDetails.psm1
21 | .\Actions\WindowsPrefetchRetrieval\Copy-WindowsPrefetch.psm1
22 | .\Actions\WindowsPrefetchRetrieval\Get-WindowsPrefetch.psm1
23 | .\Actions\WindowsPrefetchRetrieval\Invoke-GetWindowsPrefetch.psm1
--------------------------------------------------------------------------------
/Playbooks/artefactprocessingmodules.txt:
--------------------------------------------------------------------------------
1 | .\Actions\WindowsSRUProcessing\Format-SRUDBtoXLSX.psm1
2 | .\Actions\WindowsEventLogProcessing\Export-ProcessStartEvents.psm1
3 | .\Actions\WindowsEventLogProcessing\Invoke-EventLogProcessing.psm1
4 | .\Actions\WindowsPrefetchProcessing\Format-WindowsPrefetch.psm1
5 | .\Actions\WindowsMemoryProcessing\Format-VolatilityOutput.psm1
6 | .\Actions\WindowsMemoryProcessing\Invoke-VolatilityCmdline.psm1
7 | .\Actions\WindowsMemoryProcessing\Invoke-VolatilityPSList.psm1
8 | .\Actions\WindowsMemoryProcessing\Invoke-VolatilityPSScan.psm1
9 | .\Actions\WindowsMemoryProcessing\Invoke-WindowsMemoryImageProcessing.psm1
10 | .\Actions\WindowsSRUProcessing\Format-SrumDumptoJson.psm1
11 | .\Actions\WindowsSRUProcessing\Format-SRUDBtoJSON.psm1
12 | .\Actions\WindowsEventLogProcessing\Export-ProcessStopEvents.psm1
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IRCoreForensicFramework
2 | Powershell 7 (Powershell Core)/ C# cross platform forensic framework. Built by incident responders for incident responders.
3 |
4 | ## Core Concepts
5 | * Laser focused on automating incident response actions, rather than system monitoring. Aims to eliminate Tier I and Tier II adversaries described in the article *Resilient Military Systems and the Advanced Cyber Threat* (https://nsarchive2.gwu.edu/NSAEBB/NSAEBB424/docs/Cyber-081.pdf)
6 | * Tightly controlled and well recorded interation with remote systems
7 | * Fun and interesting
8 | * No need to use a host agent - this tool uses living off the land techniques, combined with the WinPmem executeable
9 |
10 | ## Setup (What you need to use if you don't want to use the docker image)
11 | 1. Your own endpoint with the following installed:
12 | * Powershell Core
13 | * Python 3.7 (minimum)
14 | * Plenty of storage space (I'd recommend at least 100Gb if you're looking to extract memory)
15 | * Plenty of processing power. (I'd recommend at least a 9th generation i5 or AMD equivalent). The framework makes extensive use of parallelization to operate at scale, so the more powerful the greater your reach will be.
16 | 2. Reasonable Powershell experience. This program is currently in Beta, so there's likely to be a bit of interaction to use it.
17 |
18 | ## Setup (Docker)
19 | 1. Navigate to https://hub.docker.com/r/jimtin/hosthunter
20 | 2. Check out if this is what you're looking for and then download and use. Let me know how it goes if there's anything I can do to improve :)
21 |
22 | ## How to use
23 | 1. Clone repository into your own directory
24 | 2. Open Powershell Core as administrator
25 | 3. Run the loadIRCore script. `.\loadIRCore.ps1`
26 | * Note: If you are not an Administrator, you will be prompted to restart console as admin
27 | * This script will download a number of files for you. Take time to understand what is being downloaded.
28 | * You will be prompted for credentials.
29 | 4. Create a target: `New-Target -Target 127.0.0.1`
30 | 5. Start running commands against the target. Some examples:
31 | * Range of basic forensic artefacts on all targets: `Invoke-CoreForensicArtifactGatheringPlaybook`
32 | * Range of basic forensic artefacts on specific target: `Invoke-CoreForensicArtifactGatheringPlaybook -Target 127.0.0.1`
33 | 6. To process artefacts into JSON format:
34 | * After using the CoreForensicArtifactGathering Playbook: `Invoke-CoreForensicArtifactProcessingPlaybook`
35 | * After using the CoreForensicArtifactGathering Playbook, but processing a specific target: `Invoke-CoreForensicArtifactProcessingPlaybook -Target 127.0.0.1`
36 |
37 | ## Assumptions
38 | * You have administrative access to your network
39 | * The access you use on your network is secure
40 |
41 | ## A cool example of what happens when you combine operational experience with engineering expertise to automate common Incident Response processes
42 |
43 | ### Playbook: Invoke-CoreForensicArtifactGatheringPlaybook
44 | #### Overview
45 | This playbook automates the gathering of core forensic artefacts. Moreover, it's simple to add more in if you need to. These artefacts are almost always asked for by incident reponders, yet no tool on the market does it as seamlessly as this.
46 |
47 | #### What it does
48 | 1. Records all actions it does, so that when you inevitably need to figure out what has happened on the endpoint, you know which actions were you and which were the adversaries.
49 | 2. Creates a remote staging location, innocuously named "PerformanceInformation"
50 | 3. Pushes winpmem across to the remote endpoint
51 | 4. *Checks if there is enough space on the endpoint to dump memory*
52 | 5. Dumps memory
53 | 6. Extracts the following artefacts to your remote endpoint:
54 | * Memory Dump (and confirms that the hash of what was dumped matches what actually ends up on your machine)
55 | * All the event logs (i.e. the entire event log folder, not just the event logs that some random engineering team thinks are what you need)
56 | * SRUM database (i.e. the forensic artifact which could allow you to a link a user, process and network activity together)
57 | * Key Registry hives
58 | * Prefetch Folder
59 | * Current running processes (for the inevitable question 'Was this process running when we touched this machine?')
60 | 7. Finishes up by going and deleting the Remote Staging location so that the endpoint doesn't get all clogged up by what you've done
61 | 8. Runs the entire process as Powershell Job, so can be mulithreaded. Registers the job with the native windows notification icon, so will simply notify you when completed
62 |
63 | Pretty awesome. And it's just the start. Using this platform, significant post-processing is also available :)
64 |
65 | ### Playbook: Invoke-CoreForensicArtifactProcessingPlaybook
66 | #### Overview
67 | This playbooks automatically processes all the artefacts gathered by the CoreForensicArtifactGatheringPlaybook. Naturally there will be times when not all artefacts are gathered, so this playbook processes what is available and continues onwards. Best of all, all artefacts are output in JSON so they can be easily uploaded to your SIEM of choice.
68 |
69 | #### What it does
70 | 1. Records all actions it does, so that when you inevitably need to figure out what has happened on the endpoint, you know which actions were you and which were the adversaries.
71 | 2. Processes the following artefacts:
72 | * SRU Database, using Mark Baggerts srum_dump2
73 | * Prefetch, using Eric Zimmerman's PECmd
74 | * Volatility commands using Volatility3
75 | * Some Windows EventLogs (with more being added) using my own custom processing
76 | 3. Outputs all results in JSON, into a folder title "ProcessedArtefacts"
77 | 4. Runs the entire process as Powershell Job, so can be mulithreaded. Registers the job with the native windows notification icon, so will simply notify you when completed
78 |
79 | #### Some cool things
80 | 1. Makes use of the Windows ToolTip API. Combined with the use of jobs to multithread operations, this framework can gather these artefacts from multiple endpoints simultaneously.
81 | 2. Means you can continue to do other actions while the time consuming actions (i.e. extracting memory) continue.
82 | 3. By using extensive use of living-off-the-land techniques, the artefacts left behind by this framework are minimal. Contrast this to many SOC tools and Incident Responders will appreciate the cleanliness of these actions.
83 |
84 | ## Next steps
85 | 1. Integrate the ability to zip using native windows tools
86 | 2. Integrate the ability to automatically upload to cloud storage (likely Amazon s3)
87 | 3. Start doing some basic post-processing analysis to make IR jobs even easier
88 |
--------------------------------------------------------------------------------
/SetupModules/Copy-Volatility.psm1:
--------------------------------------------------------------------------------
1 | function Copy-Volatility {
2 | <#
3 | .SYNOPSIS
4 | Copies volatility from the download location across to the PythonAnalysisList location
5 |
6 | .DESCRIPTION
7 | Copies volatility3 from Executeables folder across to PythonAnalysisList folder, then unzips
8 |
9 | #>
10 | param (
11 |
12 | )
13 |
14 | # Create output dictionary
15 | $output = @{}
16 |
17 | # Set up the path correctly
18 | $location = (Get-Location).ToString()
19 |
20 | # Check if volatility3 folder already exists
21 | $volatilitylocation = $location + "\PythonAnalysisList\volatility3"
22 | $volatility = Test-Path -Path $volatilitylocation
23 | $output.Add("VolatilityPresent", $volatility)
24 |
25 | # If it doesnt exist, copy then unzip
26 | if($volatility -ne $true){
27 | $volzip = $location + "\Executeables\volatility3.zip"
28 | $destvolzip = $volatilitylocation + ".zip"
29 | # Copy zipped file to PythonAnalysisList
30 | $copy = Copy-Item -Path $volzip -Destination $destvolzip
31 | $output.Add("VolatilityTransferred", $copy)
32 |
33 | # Unzip file
34 | $volmaster = $location + "\PythonAnalysisList"
35 | $expandedvolatility = Expand-Archive -Path $destvolzip -DestinationPath $volmaster
36 | $output.Add("VolatilityExpanded", $expandedvolatility)
37 |
38 | # Delete the original unzip
39 | Remove-Item -Path $destvolzip
40 |
41 | # Rename extracted folder
42 | $volmaster = $location + "\PythonAnalysisList\volatility3-master"
43 | Rename-Item -Path $volmaster -NewName volatility3
44 |
45 | # Delete the git and development folders in volatility
46 | $githubpath = $volatilitylocation + "\.github"
47 | Remove-Item -Path $githubpath -Recurse
48 | $devpath = $volatilitylocation + "\development"
49 | Remove-Item -Path $devpath -Recurse
50 |
51 | }else {
52 | Write-HostHunterInformation -MessageData "Volatility exists"
53 | }
54 |
55 | # Return output to the user
56 | Write-Output $output
57 |
58 | }
--------------------------------------------------------------------------------
/SetupModules/Expand-PrefetchParser.psm1:
--------------------------------------------------------------------------------
1 | function Expand-PrefetchParser {
2 | <#
3 | .SYNOPSIS
4 | Extracts the prefetch parser from the zip download
5 |
6 | .DESCRIPTION
7 | Extracts Eric Zimmermans excellent prefetch tool from the zip file it downloaded to.
8 | Credits: https://ericzimmerman.github.io/#!index.md
9 | Please consider supporting Eric Zimmerman
10 |
11 | #>
12 | [CmdletBinding()]
13 | param (
14 |
15 | )
16 |
17 | # Set up the location of the prefetch parser
18 | $location = (Get-Location).ToString()
19 | $prefetchlocation = $location + "\Executeables\PECmd.zip"
20 | $prefetchunzipped = $location + "\Executeables\PECmd.exe"
21 | $exeloc = $location + "\Executeables"
22 |
23 | # Test if unzipped file exists
24 | $prefetchready = Test-Path -Path $prefetchunzipped
25 |
26 | # If it doesn't, expand the zip file
27 | if($prefetchready -ne $true){
28 | Write-HostHunterInformation -MessageData "Expanding prefetch parser"
29 | Expand-Archive -Path $prefetchlocation -DestinationPath $exeloc
30 | }
31 |
32 | Write-HostHunterInformation -MessageData "Prefetch Parser available" -ForegroundColor "Cyan"
33 |
34 | }
--------------------------------------------------------------------------------
/SetupModules/Get-Executeable.psm1:
--------------------------------------------------------------------------------
1 | function Get-Executeable{
2 | <#
3 | .SYNOPSIS
4 | Gets executeable to enable generic IR Forensics to occur
5 | .DESCRIPTION
6 | Downloads core executeable as specified in the manifest
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | [Parameter(Mandatory=$true)]$DownloadURL,
12 | [Parameter(Mandatory=$true)]$OutputLocation,
13 | [Parameter(Mandatory=$true)]$ExeName
14 | )
15 |
16 | # Setup the output dictionary
17 | $output = @{
18 | "Exename" = $ExeName
19 | "DownloadUrl" = $DownloadURL
20 | }
21 |
22 | # Get the current location
23 | $location = (Get-Location).ToString()
24 | # Create the output path
25 | $outputpath = $location + "\" + $OutputLocation + "\" + $ExeName
26 |
27 | # Notify the user
28 | $message = "Downloading " + $ExeName + " to " + $outputpath
29 | Write-HostHunterInformation -MessageData $message
30 |
31 | # Invoke the Web Request to download
32 | $download = Invoke-WebRequest -Uri $DownloadURL -OutFile $outputpath
33 |
34 | # Add the outcome to output
35 | $output.Add("Outcome", $download)
36 |
37 | # Return outcome to user
38 | Write-Output $output
39 |
40 | }
--------------------------------------------------------------------------------
/SetupModules/Get-SetupExecuteables.psm1:
--------------------------------------------------------------------------------
1 | function Get-SetupExecuteables{
2 | <#
3 | .SYNOPSIS
4 | Gets several core executeables to enable generic IR Forensics to occur
5 | .DESCRIPTION
6 | Downloads core executeables
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 |
12 | )
13 |
14 | # Get the list of executeables to be downloaded
15 | $exelist = Get-Content -Path ".\Executeables\executeablemanifest.json" | ConvertFrom-Json
16 |
17 | foreach ($exe in $exelist){
18 | # Check if the executeable already exists
19 | $CurrentPath = (Get-Location).ToString()
20 | $fullpath = $CurrentPath + "\" + $exe.OutputPath + "\" + $exe.ExecutableName
21 | $exists = Test-Path -Path $fullpath
22 | if($exists -ne $true){
23 | Get-Executeable -DownloadURL $exe.DownloadURL -OutputLocation $exe.OutputPath -ExeName $exe.ExecutableName
24 | }else{
25 | $exe = ($exe.ExecutableName).ToString()
26 | $message = "Executeable for HostHunter available: " + $exe
27 | Write-HostHunterInformation -MessageData $message -ForegroundColor "Blue"
28 | }
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/SetupModules/Import-VolatilitySymbols.psm1:
--------------------------------------------------------------------------------
1 | function Import-VolatilitySymbols {
2 | <#
3 | .SYNOPSIS
4 | Imports the required symbol tables for Volatility3 from here: https://github.com/volatilityfoundation/volatility3
5 |
6 | .DESCRIPTION
7 | Imports the required symbol tables for volatility3. Used in this module as this is a large download and a bit different from standard executeable import
8 | #>
9 | [CmdletBinding()]
10 | param (
11 |
12 | )
13 |
14 | # Setup the file path
15 | $location = (Get-Location).ToString()
16 | $location = $location + "\PythonAnalysisList\volatility3\volatility\symbols\"
17 |
18 | #### Windows Symbol table
19 | # Test if windows path already exists
20 | $winloc = $location + "windows.zip"
21 | $windows = Test-Path -Path $winloc
22 |
23 | # If it does not exist, download
24 | if($windows -ne $true){
25 | Write-HostHunterInformation -MessageData "Downloading Windows symbol tables for Volatility 3" -ForegroundColor "Yellow"
26 | $windownload = $location + "windows.zip"
27 | Invoke-WebRequest -Uri "https://downloads.volatilityfoundation.org/volatility3/symbols/windows.zip" -OutFile $windownload
28 | }
29 |
30 | Write-HostHunterInformation -MessageData "Windows Symbol Tables available" -ForegroundColor "Cyan"
31 |
32 | #### Mac Symbol tables
33 | # Test if Mac symbol tables already downloaded
34 | $macloc = $location + "mac.zip"
35 | $mac = Test-Path -Path $macloc
36 |
37 | # If it does not exist, download
38 | if($mac -ne $true){
39 | Write-HostHunterInformation -MessageData "Downloading Mac symbol tables for Volatility 3" -ForegroundColor "Yellow"
40 | $macdownload = $location + "mac.zip"
41 | Invoke-WebRequest -Uri "https://downloads.volatilityfoundation.org/volatility3/symbols/mac.zip" -OutFile $macdownload
42 | }
43 |
44 | Write-HostHunterInformation -MessageData "Mac Symbol Tables available" -ForegroundColor "Cyan"
45 |
46 | #### Linux symbol tables
47 | # Test if Linux symbol tables already downloaded
48 | $linuxloc = $location + "linux.zip"
49 | $linux = Test-Path -Path $linuxloc
50 |
51 | if($linux -ne $true){
52 | Write-HostHunterInformation -MessageData "Downloading Linux symbol tables for Volatility 3" -ForegroundColor "Yellow"
53 | $linuxdownload = $location + "linux.zip"
54 | Invoke-WebRequest -Uri "https://downloads.volatilityfoundation.org/volatility3/symbols/linux.zip" -OutFile $linuxdownload
55 | }
56 |
57 | Write-HostHunterInformation -MessageData "Linux Symbol Tables available" -ForegroundColor "Cyan"
58 |
59 | }
--------------------------------------------------------------------------------
/SetupModules/Set-PythonAnalysisList.psm1:
--------------------------------------------------------------------------------
1 | function Set-PythonAnalysisList {
2 | <#
3 | .SYNOPSIS
4 | Sets the PythonAnalysisFolder up
5 |
6 | .DESCRIPTION
7 | Sets the PythonAnalysisFolder up
8 | #>
9 | param (
10 |
11 | )
12 |
13 | # Get the location
14 | $Location = (Get-Location).ToString()
15 |
16 | # Test the path
17 | $folder = $Location + "\PythonAnalysisList"
18 | $path = Test-Path -Path $folder
19 |
20 | # If it's not there, create it
21 | if($path -ne $true){
22 | New-Item -Path $Location -Name PythonAnalysisList -ItemType Directory
23 | }
24 |
25 | $path = Test-Path -Path $folder
26 |
27 | Write-Output $path
28 |
29 | }
--------------------------------------------------------------------------------
/UnifiedMessaging/New-TooltipNotification.psm1:
--------------------------------------------------------------------------------
1 | function New-TooltipNotification{
2 | <#
3 | .SYNOPSIS
4 | Pops a tooltip notification to a user when a job is completed
5 |
6 | .DESCRIPTION
7 | Pops a tooltip notification to a user when a job is completed. Code from here:
8 | https://github.com/proxb/PowerShell_Scripts/blob/master/Invoke-BalloonTip.ps1
9 | #>
10 |
11 | [CmdletBinding()]
12 | param (
13 | [Parameter(HelpMessage="The message title")]$MessageTitle="HostHunter Update",
14 | [Parameter(HelpMessage="The body of text to be displayed in message")]$MessageData="Powershell job completed"
15 | )
16 |
17 | # Add the assembly name required for use
18 | Add-Type -AssemblyName System.Windows.Forms
19 |
20 | # Create global variable for the balloon
21 | If (-Not $Global:balloon){
22 | $Global:balloon = New-Object System.Windows.Forms.NotifyIcon
23 |
24 | # Set up a double click to dispose
25 | [void](Register-ObjectEvent -InputObject $balloon -EventName MouseDoubleClick -SourceIdentifier IconClicked -Action{
26 | # Clean up the balloon tip
27 | Write-Verbose "Disposing of Balloon"
28 | $Global:balloon.dispose()
29 | Unregister-Event -SourceIdentifier IconClicked
30 | Remove-Job -Name IconClicked
31 | Remove-Variable -Name balloon -Scope Global
32 | })
33 | }
34 |
35 | $SysTrayIconPath='C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'
36 |
37 | # Create Icon for the tray
38 | $balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($SysTrayIconPath)
39 |
40 | $MessageType = "Info"
41 | # Set up tip text and icons
42 | $balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]$MessageType
43 | $balloon.BalloonTipText = $MessageData
44 | $balloon.BalloonTipTitle = $MessageTitle
45 | $balloon.Visible = $true
46 |
47 | # Display the tool tip and specify how many milliseconds it will stay visible for
48 | $balloon.ShowBalloonTip(5000)
49 |
50 | Write-Verbose "Ending Function"
51 |
52 | }
--------------------------------------------------------------------------------
/UnifiedMessaging/Write-HostHunterInformation.psm1:
--------------------------------------------------------------------------------
1 | using namespace System.Management.Automation
2 | function Write-HostHunterInformation{
3 | <#
4 | .SYNOPSIS
5 | Writes messages to the information stream, optionally with
6 | color when written to the host.
7 | .DESCRIPTION
8 | An alternative to Write-Host which will write to the information stream
9 | and the host (optionally in colors specified) but will honor the
10 | $InformationPreference of the calling context.
11 | In PowerShell 5.0+ Write-Host calls through to Write-Information but
12 | will _always_ treats $InformationPreference as 'Continue', so the caller
13 | cannot use other options to the preference variable as intended.
14 |
15 | Full credit here: https://blog.kieranties.com/2018/03/26/write-information-with-colours
16 | #>
17 | [CmdletBinding()]
18 | param(
19 | [Parameter(Mandatory)][Object]$MessageData,
20 | [Parameter()][ConsoleColor]$ForegroundColor = $Host.UI.RawUI.ForegroundColor, # Make sure we use the current colours by default
21 | [Parameter()][ConsoleColor]$BackgroundColor = $Host.UI.RawUI.BackgroundColor,
22 | [Parameter()][Switch]$NoNewline,
23 | [Parameter()][Switch]$ToolTipNotification,
24 | [Parameter()][string]$MessageTitle
25 | )
26 |
27 | if($ToolTipNotification){
28 | New-TooltipNotification -MessageData $MessageData -MessageTitle $MessageTitle
29 | }else {
30 | $msg = [HostInformationMessage]@{
31 | Message = $MessageData
32 | ForegroundColor = $ForegroundColor
33 | BackgroundColor = $BackgroundColor
34 | NoNewline = $NoNewline.IsPresent
35 | }
36 |
37 | Write-Information -InformationAction Continue -MessageData $msg
38 | }
39 |
40 |
41 | }
--------------------------------------------------------------------------------
/loadIRCore.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 7
2 | #Requires -RunAsAdministrator
3 |
4 | # Get a list of modules from the modules file
5 | $modules = Get-Content -Path .\modulemanifest.txt
6 |
7 | foreach ($cmdlet in $modules){
8 | $messagestring = "Importing cmdlet: " + $cmdlet
9 | Write-Information -InformationAction Continue -MessageData $messagestring
10 | # Import the module
11 | Import-Module -Name $cmdlet -Force
12 | }
13 |
14 | # Ensure executables which will help are downloaded
15 | Write-HostHunterInformation -MessageData "Checking core executeables are downloaded"
16 | Get-SetupExecuteables
17 |
18 | # Set up the Python analysis folder
19 | $analysis = Set-PythonAnalysisList
20 | while($analysis -ne $true){
21 | Start-Sleep -Seconds 1
22 | $analysis = Set-PythonAnalysisList
23 | }
24 |
25 | # Copy Volatility into python analysis folder
26 | $volatility = Copy-Volatility
27 |
28 | # Import Volatility3 Symbols tables for all operating systems
29 | Write-HostHunterInformation -MessageData "Ensuring Volatility3 Symbols Tables are available"
30 | Import-VolatilitySymbols
31 |
32 | # Check that ImportExcel module is ready
33 | $module = Get-InstalledModule -Name ImportExcel -ErrorAction SilentlyContinue
34 | if($module -eq $null){
35 | Install-Module ImportExcel -Force
36 | }
37 | Write-HostHunterInformation -MessageData "ImportExcel Powershell Module available" -ForegroundColor "Cyan"
38 |
39 | # Make sure Prefetch Parser is ready
40 | Expand-PrefetchParser
41 |
42 | # Set up the target tracking variable
43 | if((Get-Variable -Name GlobalTargetList -ErrorAction SilentlyContinue) -eq $null){
44 | New-Variable -Name "GlobalTargetList" -Scope global -Visibility Public -Value @{}
45 | }
46 |
47 | Write-HostHunterInformation -MessageData "GlobalTargetList variable set" -ForegroundColor "Blue"
48 |
49 | # Set up the global credential variable
50 | if ($cred -eq $null){
51 | $cred = Get-Credential
52 | Set-Variable -Name "cred" -Scope global -Visibility Public -Value $cred
53 | }
54 |
--------------------------------------------------------------------------------
/modulemanifest.txt:
--------------------------------------------------------------------------------
1 | .\SetupModules\Get-Executeable.psm1
2 | .\SetupModules\Get-SetupExecuteables.psm1
3 | .\CoreEndpointInteraction\New-EndpointSession.psm1
4 | .\CoreEndpointInteraction\Remove-EndpointSession.psm1
5 | .\UnifiedMessaging\Write-HostHunterInformation.psm1
6 | .\CoreEndpointInteraction\Get-TargetList.psm1
7 | .\CoreEndpointInteraction\New-Target.psm1
8 | .\CoreEndpointInteraction\Get-TargetSessions.psm1
9 | .\CoreEndpointInteraction\Invoke-HostCommand.psm1
10 | .\UnifiedMessaging\New-TooltipNotification.psm1
11 | .\CoreEndpointInteraction\Remove-Target.psm1
12 | .\Actions\CreateStagingLocation\New-LocalDataStagingLocation.psm1
13 | .\Actions\CreateStagingLocation\New-RemoteStagingLocation.psm1
14 | .\Actions\WindowsMemoryRetrieval\Move-WinPMEM.psm1
15 | .\Actions\WindowsMemoryRetrieval\Invoke-MemoryDump.psm1
16 | .\Actions\WindowsMemoryRetrieval\Get-MemoryDump.psm1
17 | .\Actions\WindowsEventLogandSRURetrieval\Copy-RemoteEventLogging.psm1
18 | .\Actions\WindowsEventLogandSRURetrieval\Get-RemoteEventLogging.psm1
19 | .\Actions\WindowsSRUProcessing\Format-SRUDBtoXLSX.psm1
20 | .\Actions\WindowsMemoryProcessing\Invoke-VolatilityPSScan.psm1
21 | .\Actions\WindowsMemoryProcessing\Format-VolatilityOutput.psm1
22 | .\Actions\WindowsMemoryProcessing\Invoke-VolatilityPSList.psm1
23 | .\Actions\WindowsMemoryProcessing\Invoke-VolatilityCmdline.psm1
24 | .\Actions\WindowsMemoryRetrieval\Get-RemoteMemoryHash.psm1
25 | .\Actions\WindowsMemoryRetrieval\Get-ExtractedMemoryHash.psm1
26 | .\Actions\WindowsMemoryRetrieval\Compare-MemoryHashes.psm1
27 | .\Actions\RemoveRemoteArtifacts\Remove-RemoteStagingLocation.psm1
28 | .\SetupModules\Import-VolatilitySymbols.psm1
29 | .\SetupModules\Copy-Volatility.psm1
30 | .\SetupModules\Set-PythonAnalysisList.psm1
31 | .\Playbooks\Invoke-CoreForensicArtifactGatheringPlaybook.psm1
32 | .\Actions\WindowsRegistryRetrieval\Copy-WindowsRegistry.psm1
33 | .\Actions\WindowsRegistryRetrieval\New-RegistryFileFolder.psm1
34 | .\Actions\WindowsRegistryRetrieval\Get-WindowsRegistryFiles.psm1
35 | .\Actions\WindowsRegistryRetrieval\Invoke-GetWindowsRegistry.psm1
36 | .\Actions\CreateStagingLocation\New-EndpointForensicStorageLocation.psm1
37 | .\CoreEndpointInteraction\Invoke-HostHunterCommand.psm1
38 | .\Actions\WindowsEventLogandSRURetrieval\Invoke-GetRemoteEventLogsandSRU.psm1
39 | .\Actions\EventCapture\Out-Events.psm1
40 | .\Actions\CreateStagingLocation\New-CurrentStateStagingLocation.psm1
41 | .\Actions\WindowsCurrentStateDetailsRetrieval\Get-CurrentProcesses.psm1
42 | .\Actions\WindowsCurrentStateDetailsRetrieval\Invoke-GetCurrentStateDetails.psm1
43 | .\Playbooks\Invoke-CoreForensicArtifactProcessingPlaybook.psm1
44 | .\Actions\CreateStagingLocation\New-ProcessedArtefactsStagingLocation.psm1
45 | .\Actions\WindowsEventLogProcessing\Export-ProcessStartEvents.psm1
46 | .\Actions\WindowsEventLogProcessing\Invoke-EventLogProcessing.psm1
47 | .\Actions\WindowsPrefetchRetrieval\Copy-WindowsPrefetch.psm1
48 | .\Actions\WindowsPrefetchRetrieval\Get-WindowsPrefetch.psm1
49 | .\Actions\WindowsPrefetchRetrieval\Invoke-GetWindowsPrefetch.psm1
50 | .\SetupModules\Expand-PrefetchParser.psm1
51 | .\Actions\WindowsMemoryProcessing\Invoke-WindowsMemoryImageProcessing.psm1
52 | .\Actions\WindowsSRUProcessing\Format-SrumDumptoJson.psm1
53 | .\Actions\WindowsSRUProcessing\Format-SRUDBtoJSON.psm1
54 | .\Actions\CloudStoragePreparation\Compress-AllForensicArtefacts.psm1
55 | .\Actions\WindowsEventLogProcessing\Export-ProcessStopEvents.psm1
56 | .\CoreEndpointInteraction\Update-Credentials.psm1
57 | .\Actions\WindowsProcessPostProcessing\Join-WindowsProcessStartProcessStopLogs.psm1
58 | .\DockerVolume\Copy-ToDockerVolume.psm1
--------------------------------------------------------------------------------