diff --git a/DeepBlue.ps1 b/DeepBlue.ps1 index be734c4..21beff2 100644 --- a/DeepBlue.ps1 +++ b/DeepBlue.ps1 @@ -40,8 +40,8 @@ function Main { $minlength=1000 # Minimum length of command line to alert # Load cmd match regexes from csv file, ignore comments $regexes = Get-Content ".\regexes.txt" | Select-String '^[^#]' | ConvertFrom-Csv - # Load cmd whitelist regexes from csv file, ignore comments - $whitelist = Get-Content ".\whitelist.txt" | Select-String '^[^#]' | ConvertFrom-Csv + # Load cmd safelist regexes from csv file, ignore comments + $safelist = Get-Content ".\safelist.txt" | Select-String '^[^#]' | ConvertFrom-Csv $logname=Check-Options $file $log #"Processing the " + $logname + " log..." $filter=Create-Filter $file $logname @@ -671,10 +671,10 @@ function Check-Command(){ $text="" $base64="" - # Check to see if command is whitelisted - foreach ($entry in $whitelist) { + # Check to see if command is safelisted + foreach ($entry in $safelist) { if ($commandline -Match $entry.regex) { - # Command is whitelisted, return nothing + # Command is safelisted, return nothing return } } diff --git a/DeepWhite-checker.ps1 b/DeepWhite-checker.ps1 index 60b5404..548b484 100644 --- a/DeepWhite-checker.ps1 +++ b/DeepWhite-checker.ps1 @@ -1,58 +1,58 @@ -# Requires Posh-VirusTotal: https://github.com/darkoperator/Posh-VirusTotal -# -# Plus a (free) VirusTotal API Key: https://www.virustotal.com/en/documentation/public-api/ -# -$hashdirectory = ".\hashes" -$whitelistfile=".\file-whitelist.csv" -# Load the whitelist into a hash table -if (Test-Path $whitelistfile){ - $whitelist = Get-Content $whitelistfile | Select-String '^[^#]' | ConvertFrom-Csv - $hashes=@{} - foreach($entry in $whitelist){ - $hashes[$entry.sha256]=$entry.path - } -} - -Get-ChildItem $hashdirectory | Foreach-Object{ - if ($_.Name -Match '^[0-9A-F]{64}$'){ # SHA256 hashes are 64 character hex strings - $SHA256=$_.Name - if ($hashes.containsKey($SHA256)){ - Rename-Item -Path "$hashdirectory\$SHA256" -NewName "$SHA256.whitelisted" - } - Else{ - try{ - $VTreport = Get-VTFileReport $SHA256 - } - catch { - Write-Host "`r`nAttempted to run: Get-VTFileReport $SHA256`r`r" - Write-Host "Error: " $_.Exception.Message "`n" - Write-Host "Have you installed Posh-VirusTotal and set the VirusTotal API key?" - Write-Host " - See: https://github.com/darkoperator/Posh-VirusTotal`r`n" - Write-Host "Once you have installed Posh-VirusTotal and have a VirusTotal API key, run the following command:`r`n" - Write-Host "Set-VTAPIKey -APIKey `r`n" - Write-Host "Exiting...`n" - exit - } - if ($VTreport.positives -eq 0){ - # File is clean - Rename-Item -Path "$hashdirectory\$SHA256" -NewName "$SHA256.clean" - } - ElseIf ($VTreport.positives -gt 0){ - # File is flagged by Virustotal - $positives=$VTreport.positives - Write-Host " - Hash was detected by $positives Virustotal scanners" - if ($positives -eq 1){ - Write-Host " - Don't Panic (yet)! There is only one positive, which may be a sign of a false positive." - Write-Host " - Check the VirusTotal report for more information." - } - Write-Host " - See $hashdirectory\$SHA256.Virustotal for the full report`r`n" - $VTreport | Set-Content "$hashdirectory\$SHA256.Virustotal" - # Rename original hash file, add the Virustotal positive count as a numbered extension - # $SHA256.$positives - Rename-Item -Path "$hashdirectory\$SHA256" -NewName "$SHA256.$positives" - } - # Wait 15 seconds between submissions, for public Virustotal API keys - Start-Sleep -s 15 - } - } +# Requires Posh-VirusTotal: https://github.com/darkoperator/Posh-VirusTotal +# +# Plus a (free) VirusTotal API Key: https://www.virustotal.com/en/documentation/public-api/ +# +$hashdirectory = ".\hashes" +$safelistfile=".\file-safelist.csv" +# Load the safelist into a hash table +if (Test-Path $safelistfile){ + $safelist = Get-Content $safelistfile | Select-String '^[^#]' | ConvertFrom-Csv + $hashes=@{} + foreach($entry in $safelist){ + $hashes[$entry.sha256]=$entry.path + } +} + +Get-ChildItem $hashdirectory | Foreach-Object{ + if ($_.Name -Match '^[0-9A-F]{64}$'){ # SHA256 hashes are 64 character hex strings + $SHA256=$_.Name + if ($hashes.containsKey($SHA256)){ + Rename-Item -Path "$hashdirectory\$SHA256" -NewName "$SHA256.safelisted" + } + Else{ + try{ + $VTreport = Get-VTFileReport $SHA256 + } + catch { + Write-Host "`r`nAttempted to run: Get-VTFileReport $SHA256`r`r" + Write-Host "Error: " $_.Exception.Message "`n" + Write-Host "Have you installed Posh-VirusTotal and set the VirusTotal API key?" + Write-Host " - See: https://github.com/darkoperator/Posh-VirusTotal`r`n" + Write-Host "Once you have installed Posh-VirusTotal and have a VirusTotal API key, run the following command:`r`n" + Write-Host "Set-VTAPIKey -APIKey `r`n" + Write-Host "Exiting...`n" + exit + } + if ($VTreport.positives -eq 0){ + # File is clean + Rename-Item -Path "$hashdirectory\$SHA256" -NewName "$SHA256.clean" + } + ElseIf ($VTreport.positives -gt 0){ + # File is flagged by Virustotal + $positives=$VTreport.positives + Write-Host " - Hash was detected by $positives Virustotal scanners" + if ($positives -eq 1){ + Write-Host " - Don't Panic (yet)! There is only one positive, which may be a sign of a false positive." + Write-Host " - Check the VirusTotal report for more information." + } + Write-Host " - See $hashdirectory\$SHA256.Virustotal for the full report`r`n" + $VTreport | Set-Content "$hashdirectory\$SHA256.Virustotal" + # Rename original hash file, add the Virustotal positive count as a numbered extension + # $SHA256.$positives + Rename-Item -Path "$hashdirectory\$SHA256" -NewName "$SHA256.$positives" + } + # Wait 15 seconds between submissions, for public Virustotal API keys + Start-Sleep -s 15 + } + } } \ No newline at end of file diff --git a/DeepWhite-collector.ps1 b/DeepWhite-collector.ps1 index 9fd6102..6581184 100644 --- a/DeepWhite-collector.ps1 +++ b/DeepWhite-collector.ps1 @@ -1,38 +1,38 @@ -$hashdirectory=".\hashes\" -$events = get-winevent @{logname="Microsoft-Windows-Sysmon/Operational";id=1,6,7} -ForEach ($event in $events) { - if ($event.id -eq 1){ # Process creation - $path=$event.Properties[3].Value # Full path of the file - $hash=$event.Properties[11].Value # Hashes - } - Else{ - # Hash and path are part of the message field in Sysmon events 6 and 7. Need to parse the XML - $eventXML = [xml]$event.ToXml() - If ($event.id -eq 6){ # Driver (.sys) load - $path=$eventxml.Event.EventData.Data[1]."#text" # Full path of the file - $hash=$eventXML.Event.EventData.Data[2]."#text" # Hashes - } - ElseIf ($event.id -eq 7){ # Image (.dll) load - $path=$eventxml.Event.EventData.Data[4]."#text" # Full path of the file - $hash=$eventXML.Event.EventData.Data[5]."#text" # Hashes - } - Else{ - Out-Host "Logic error 1, should not reach here..." - Exit 1 - } - } - # Multiple hashes may be logged, we want SHA256. Remove everything through "SHA256=" - $SHA256= $hash -Replace "^.*SHA256=","" - # Split the string on commas, grab field 0 - $SHA256=$SHA256.Split(",")[0] - if ($SHA256 -Match '^[0-9A-F]{64}$'){ # SHA256 hashes are 64 character hex strings - $hashfile="$hashdirectory\$SHA256" - if (-not (Test-Path "$hashfile*")){ - # Hash file doesn't exist (or any variants with extensions), create it - $path | Set-Content $hashfile - } - } - Else{ - Out-Host "No SHA256 hash found. Ensure Sysmon is creating SHA256 hashes" - } +$hashdirectory=".\hashes\" +$events = get-winevent @{logname="Microsoft-Windows-Sysmon/Operational";id=1,6,7} +ForEach ($event in $events) { + if ($event.id -eq 1){ # Process creation + $path=$event.Properties[3].Value # Full path of the file + $hash=$event.Properties[11].Value # Hashes + } + Else{ + # Hash and path are part of the message field in Sysmon events 6 and 7. Need to parse the XML + $eventXML = [xml]$event.ToXml() + If ($event.id -eq 6){ # Driver (.sys) load + $path=$eventxml.Event.EventData.Data[1]."#text" # Full path of the file + $hash=$eventXML.Event.EventData.Data[2]."#text" # Hashes + } + ElseIf ($event.id -eq 7){ # Image (.dll) load + $path=$eventxml.Event.EventData.Data[4]."#text" # Full path of the file + $hash=$eventXML.Event.EventData.Data[5]."#text" # Hashes + } + Else{ + Out-Host "Logic error 1, should not reach here..." + Exit 1 + } + } + # Multiple hashes may be logged, we want SHA256. Remove everything through "SHA256=" + $SHA256= $hash -Replace "^.*SHA256=","" + # Split the string on commas, grab field 0 + $SHA256=$SHA256.Split(",")[0] + if ($SHA256 -Match '^[0-9A-F]{64}$'){ # SHA256 hashes are 64 character hex strings + $hashfile="$hashdirectory\$SHA256" + if (-not (Test-Path "$hashfile*")){ + # Hash file doesn't exist (or any variants with extensions), create it + $path | Set-Content $hashfile + } + } + Else{ + Out-Host "No SHA256 hash found. Ensure Sysmon is creating SHA256 hashes" + } } \ No newline at end of file diff --git a/README.md b/README.md index dec5591..1f5f732 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Sample evtx files are in the .\evtx directory - [Output](#output) - [Logging setup](#logging-setup) - See the [DeepBlue.py Readme](READMEs/README-DeepBlue.py.md) for information on DeepBlue.py -- See the [DeepWhite Readme](READMEs/README-DeepWhite.md) for information on DeepWhite (detective whitelisting using Sysmon event logs) +- See the [DeepWhite Readme](READMEs/README-DeepWhite.md) for information on DeepWhite (detective safelisting using Sysmon event logs) ## Usage: diff --git a/READMEs/README-DeepWhite.md b/READMEs/README-DeepWhite.md index 3d4e618..d5ae412 100644 --- a/READMEs/README-DeepWhite.md +++ b/READMEs/README-DeepWhite.md @@ -1,12 +1,12 @@ # DeepWhite -Detective whitelisting using Sysmon event logs. +Detective safelisting using Sysmon event logs. Parses the Sysmon event logs, grabbing the SHA256 hashes from process creation (event 1), driver load (event 6, sys), and image load (event 7, DLL) events. -## VirusTotal and Whitelisting setup +## VirusTotal and Safelisting setup -Setting up VirusTotal hash submissions and whitelisting: +Setting up VirusTotal hash submissions and safelisting: The hash checker requires Post-VirusTotal: @@ -59,11 +59,11 @@ You can go *much* further than this with Sysmon. The Sysinternals Sysmon page ha Also see @swiftonsecurity's awesome Sysmon config here: https://github.com/SwiftOnSecurity/sysmon-config -## Generating a Whitelist +## Generating a Safelist -Generate a custom whitelist on Windows (note: this is optional): +Generate a custom safelist on Windows (note: this is optional): ``` -PS C:\> Get-ChildItem c:\windows\system32 -Include '*.exe','*.dll','*.sys','*.com' -Recurse | Get-FileHash| Export-Csv -Path whitelist.csv +PS C:\> Get-ChildItem c:\windows\system32 -Include '*.exe','*.dll','*.sys','*.com' -Recurse | Get-FileHash| Export-Csv -Path safelist.csv ``` Note: this will generate (harmless) 'PermissionDenied' warnings for locked files, etc. They may be ignored. diff --git a/whitelist.txt b/safelist.txt similarity index 100% rename from whitelist.txt rename to safelist.txt diff --git a/safelists/readme.md b/safelists/readme.md new file mode 100644 index 0000000..cab4008 --- /dev/null +++ b/safelists/readme.md @@ -0,0 +1 @@ +Placeholder for safelists directory diff --git a/whitelists/win10-x64.csv b/safelists/win10-x64.csv similarity index 100% rename from whitelists/win10-x64.csv rename to safelists/win10-x64.csv diff --git a/whitelists/readme.md b/whitelists/readme.md deleted file mode 100644 index e3cfeb4..0000000 --- a/whitelists/readme.md +++ /dev/null @@ -1 +0,0 @@ -Placeholder for whitelists directory