Compare commits
38 Commits
Conrad-tes
...
2eecc65698
Author | SHA1 | Date | |
---|---|---|---|
2eecc65698 | |||
8e510aaaef | |||
50d2ca9ef9 | |||
ac1a9991fd | |||
9e5979fca2 | |||
e9fc13a57b | |||
7fb41280a2 | |||
41fe88f2e4 | |||
3c8fa15e28 | |||
cd3e304f27 | |||
a99c412a73 | |||
1699dfc5cf | |||
fc670716d6 | |||
ecbc203684 | |||
229010219a | |||
79dd0e6b11 | |||
f35415586d | |||
ce3c408efa | |||
e07e5aa1de | |||
9369182b49 | |||
9e51dd0579 | |||
2fc4fd599f | |||
120448c50e | |||
115b4f30b2 | |||
eebd75d029 | |||
f5b844cb1a | |||
ea97820b79 | |||
cf9411f721 | |||
e3bf84fe51 | |||
45d62cbfbe | |||
350fe3c134 | |||
d7d8d5eb80 | |||
5f2a62cd9c | |||
46fe6b42c5 | |||
2ae82a296f | |||
8b15218ae3 | |||
0c7338dd38 | |||
ddb9e3e0fa |
105
DeepBlue.ps1
105
DeepBlue.ps1
@ -25,7 +25,7 @@ https://github.com/sans-blue-team/DeepBlueCLI
|
|||||||
|
|
||||||
#>
|
#>
|
||||||
|
|
||||||
# DeepBlueCLI 2.01
|
# DeepBlueCLI 3.0
|
||||||
# Eric Conrad, Backshore Communications, LLC
|
# Eric Conrad, Backshore Communications, LLC
|
||||||
# deepblue <at> backshore <dot> net
|
# deepblue <at> backshore <dot> net
|
||||||
# Twitter: @eric_conrad
|
# Twitter: @eric_conrad
|
||||||
@ -45,7 +45,7 @@ function Main {
|
|||||||
$logname=Check-Options $file $log
|
$logname=Check-Options $file $log
|
||||||
#"Processing the " + $logname + " log..."
|
#"Processing the " + $logname + " log..."
|
||||||
$filter=Create-Filter $file $logname
|
$filter=Create-Filter $file $logname
|
||||||
# Passworg guessing/spraying variables:
|
# Password guessing/spraying variables:
|
||||||
$maxfailedlogons=5 # Alert after this many failed logons
|
$maxfailedlogons=5 # Alert after this many failed logons
|
||||||
$failedlogons=@{} # HashTable of failed logons per user
|
$failedlogons=@{} # HashTable of failed logons per user
|
||||||
$totalfailedlogons=0 # Total number of failed logons (for all accounts)
|
$totalfailedlogons=0 # Total number of failed logons (for all accounts)
|
||||||
@ -66,6 +66,7 @@ function Main {
|
|||||||
$passspraytrack = @{}
|
$passspraytrack = @{}
|
||||||
$passsprayuniqusermax = 6
|
$passsprayuniqusermax = 6
|
||||||
$passsprayloginmax = 6
|
$passsprayloginmax = 6
|
||||||
|
$passsprayuniqaccounts = 0
|
||||||
# Sysmon variables:
|
# Sysmon variables:
|
||||||
# Check for unsigned EXEs/DLLs. This can be very chatty, so it's disabled.
|
# Check for unsigned EXEs/DLLs. This can be very chatty, so it's disabled.
|
||||||
# Set $checkunsigned to 1 to enable:
|
# Set $checkunsigned to 1 to enable:
|
||||||
@ -224,7 +225,7 @@ function Main {
|
|||||||
$totalsensprivuse+=1
|
$totalsensprivuse+=1
|
||||||
# use -eq here to avoid multiple log notices
|
# use -eq here to avoid multiple log notices
|
||||||
if ($totalsensprivuse -eq $maxtotalsensprivuse) {
|
if ($totalsensprivuse -eq $maxtotalsensprivuse) {
|
||||||
$obj.Message = "Sensititive Privilege Use Exceeds Threshold"
|
$obj.Message = "Sensitive Privilege Use Exceeds Threshold"
|
||||||
$obj.Results = "Potentially indicative of Mimikatz, multiple sensitive privilege calls have been made.`n"
|
$obj.Results = "Potentially indicative of Mimikatz, multiple sensitive privilege calls have been made.`n"
|
||||||
|
|
||||||
$username=$eventXML.Event.EventData.Data[1]."#text"
|
$username=$eventXML.Event.EventData.Data[1]."#text"
|
||||||
@ -311,11 +312,13 @@ function Main {
|
|||||||
foreach($key in $passspraytrack.keys) {
|
foreach($key in $passspraytrack.keys) {
|
||||||
$usernames += $key
|
$usernames += $key
|
||||||
$usernames += " "
|
$usernames += " "
|
||||||
|
$passsprayuniqaccounts += 1
|
||||||
}
|
}
|
||||||
$obj.Message = "Distributed Account Explicit Credential Use (Password Spray Attack)"
|
$obj.Message = "Distributed Account Explicit Credential Use (Password Spray Attack)"
|
||||||
$obj.Results = "The use of multiple user account access attempts with explicit credentials is "
|
$obj.Results = "The use of multiple user account access attempts with explicit credentials is "
|
||||||
$obj.Results += "an indicator of a password spray attack.`n"
|
$obj.Results += "an indicator of a password spray attack.`n"
|
||||||
$obj.Results += "Target Usernames: $usernames`n"
|
$obj.Results += "Target Usernames: $usernames`n"
|
||||||
|
$obj.results += "Unique accounts sprayed: $passsprayuniqaccounts`n"
|
||||||
$obj.Results += "Accessing Username: $username`n"
|
$obj.Results += "Accessing Username: $username`n"
|
||||||
$obj.Results += "Accessing Host Name: $hostname`n"
|
$obj.Results += "Accessing Host Name: $hostname`n"
|
||||||
Write-Output $obj
|
Write-Output $obj
|
||||||
@ -388,7 +391,7 @@ function Main {
|
|||||||
ElseIf ($event.id -eq 7040){
|
ElseIf ($event.id -eq 7040){
|
||||||
# The start type of the Windows Event Log service was changed from auto start to disabled.
|
# The start type of the Windows Event Log service was changed from auto start to disabled.
|
||||||
$servicename=$eventXML.Event.EventData.Data[0]."#text"
|
$servicename=$eventXML.Event.EventData.Data[0]."#text"
|
||||||
$action = $eventXML.Event.EventData.Data[1]."#text"
|
$action = $eventXML.Event.EventData.Data[2]."#text"
|
||||||
if ($servicename -ccontains "Windows Event Log") {
|
if ($servicename -ccontains "Windows Event Log") {
|
||||||
$obj.Results = "Service name: $servicename`n"
|
$obj.Results = "Service name: $servicename`n"
|
||||||
$obj.Results += $text
|
$obj.Results += $text
|
||||||
@ -514,8 +517,14 @@ function Main {
|
|||||||
ElseIf ($logname -eq "Sysmon"){
|
ElseIf ($logname -eq "Sysmon"){
|
||||||
# Check command lines
|
# Check command lines
|
||||||
if ($event.id -eq 1){
|
if ($event.id -eq 1){
|
||||||
$creator=$eventXML.Event.EventData.Data[14]."#text"
|
if ($eventXML.Event.EventData.Data.Count -le 16){
|
||||||
$commandline=$eventXML.Event.EventData.Data[4]."#text"
|
$creator=$eventXML.Event.EventData.Data[14]."#text"
|
||||||
|
$commandline=$eventXML.Event.EventData.Data[10]."#text"
|
||||||
|
}
|
||||||
|
Else {
|
||||||
|
$creator=$eventXML.Event.EventData.Data[20]."#text"
|
||||||
|
$commandline=$eventXML.Event.EventData.Data[10]."#text"
|
||||||
|
}
|
||||||
if ($commandline){
|
if ($commandline){
|
||||||
Check-Command -EventID 1
|
Check-Command -EventID 1
|
||||||
}
|
}
|
||||||
@ -525,17 +534,66 @@ function Main {
|
|||||||
# This can be very chatty, so it's disabled.
|
# This can be very chatty, so it's disabled.
|
||||||
# Set $checkunsigned to 1 (global variable section) to enable:
|
# Set $checkunsigned to 1 (global variable section) to enable:
|
||||||
if ($checkunsigned){
|
if ($checkunsigned){
|
||||||
if ($eventXML.Event.EventData.Data[6]."#text" -eq "false"){
|
if ($event.Properties.Count -lt 14){
|
||||||
$obj.Message="Unsigned Image (DLL)"
|
if ($eventXML.Event.EventData.Data[6]."#text" -eq "false"){
|
||||||
$image=$eventXML.Event.EventData.Data[3]."#text"
|
$obj.Message="Unsigned Image (DLL)"
|
||||||
$imageload=$eventXML.Event.EventData.Data[4]."#text"
|
$image=$eventXML.Event.EventData.Data[3]."#text"
|
||||||
# $hash=$eventXML.Event.EventData.Data[5]."#text"
|
$imageload=$eventXML.Event.EventData.Data[4]."#text"
|
||||||
$obj.Command=$imageload
|
# $hash=$eventXML.Event.EventData.Data[5]."#text"
|
||||||
$obj.Results= "Loaded by: $image"
|
$obj.Command=$imageload
|
||||||
Write-Output $obj
|
$obj.Results= "Loaded by: $image"
|
||||||
}
|
Write-Output $obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Else{
|
||||||
|
if ($eventXML.Event.EventData.Data[11]."#text" -eq "false"){
|
||||||
|
$obj.Message="Unsigned Image (DLL)"
|
||||||
|
$image=$eventXML.Event.EventData.Data[4]."#text"
|
||||||
|
$imageload=$eventXML.Event.EventData.Data[5]."#text"
|
||||||
|
# $hash=$eventXML.Event.EventData.Data[10]."#text"
|
||||||
|
$obj.Command=$imageload
|
||||||
|
$obj.Results= "Loaded by: $image"
|
||||||
|
Write-Output $obj
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ElseIf ($event.id -eq 8){
|
||||||
|
#Check remote thread (lsass activity, process migration, etc)
|
||||||
|
$image=$eventXML.Event.EventData.Data[7]."#text"
|
||||||
|
$user=$eventXML.Event.EventData.Data[12]."#text"
|
||||||
|
$sourceimage=$eventXML.Event.EventData.Data[4]."#text"
|
||||||
|
If ($image -Match "lsass.exe"){
|
||||||
|
$creatortext += "Remote thread to $image`n"
|
||||||
|
$obj.Message="Suspicious remote thread"
|
||||||
|
$imageload=$eventXML.Event.EventData.Data[7]."#text"
|
||||||
|
$obj.Command=$imageload
|
||||||
|
$obj.Results= "Remote thread created to: $image from: $sourceimage by $user"
|
||||||
|
Write-Output $obj
|
||||||
|
}
|
||||||
|
ElseIf ($user -notmatch "SYSTEM"){
|
||||||
|
$creatortext += "Remote thread to $image`n"
|
||||||
|
$obj.Message="Suspicious remote thread"
|
||||||
|
$imageload=$eventXML.Event.EventData.Data[7]."#text"
|
||||||
|
$obj.Command=$imageload
|
||||||
|
$obj.Results= "Remote thread created to: $image from: $sourceimage by $user"
|
||||||
|
Write-Output $obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ElseIf ($logname -eq "WMI-Activity"){
|
||||||
|
# Check commandlines for suspicious commands
|
||||||
|
if ($event.id -eq 5861){
|
||||||
|
if($event.Message -match ".*CommandLineTemplate\s=\s(.*?);"){
|
||||||
|
$command = $event.message
|
||||||
|
$obj.Message = "Suspicous WMI Event Filter"
|
||||||
|
$obj.Results += "Event Triggered Execution: WMI - T1546.003`n"
|
||||||
|
$obj.Results += $event.message
|
||||||
|
$obj.Command=$matches[0].Split("=")[1]
|
||||||
|
Write-Output $obj
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# Iterate through admin logons hashtable (key is $username)
|
# Iterate through admin logons hashtable (key is $username)
|
||||||
@ -618,6 +676,7 @@ function Check-Options($file, $log)
|
|||||||
"Microsoft-Windows-AppLocker/EXE and DLL" {$logname="Applocker"}
|
"Microsoft-Windows-AppLocker/EXE and DLL" {$logname="Applocker"}
|
||||||
"Microsoft-Windows-PowerShell/Operational" {$logname="Powershell"}
|
"Microsoft-Windows-PowerShell/Operational" {$logname="Powershell"}
|
||||||
"Microsoft-Windows-Sysmon/Operational" {$logname="Sysmon"}
|
"Microsoft-Windows-Sysmon/Operational" {$logname="Sysmon"}
|
||||||
|
"Microsoft-Windows-WMI-Activity/Operational" {$logname="WMI-Activity"}
|
||||||
default {"Logic error 3, should not reach here...";Exit 1}
|
default {"Logic error 3, should not reach here...";Exit 1}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -638,7 +697,8 @@ function Create-Filter($file, $logname)
|
|||||||
$app_events="2"
|
$app_events="2"
|
||||||
$applocker_events="8003,8004,8006,8007"
|
$applocker_events="8003,8004,8006,8007"
|
||||||
$powershell_events="4103,4104"
|
$powershell_events="4103,4104"
|
||||||
$sysmon_events="1,7"
|
$sysmon_events="1,7,8"
|
||||||
|
$wmi_events="5861"
|
||||||
if ($file -ne ""){
|
if ($file -ne ""){
|
||||||
switch ($logname){
|
switch ($logname){
|
||||||
"Security" {$filter="@{path=""$file"";ID=$sec_events}"}
|
"Security" {$filter="@{path=""$file"";ID=$sec_events}"}
|
||||||
@ -647,6 +707,7 @@ function Create-Filter($file, $logname)
|
|||||||
"Applocker" {$filter="@{path=""$file"";ID=$applocker_events}"}
|
"Applocker" {$filter="@{path=""$file"";ID=$applocker_events}"}
|
||||||
"Powershell" {$filter="@{path=""$file"";ID=$powershell_events}"}
|
"Powershell" {$filter="@{path=""$file"";ID=$powershell_events}"}
|
||||||
"Sysmon" {$filter="@{path=""$file"";ID=$sysmon_events}"}
|
"Sysmon" {$filter="@{path=""$file"";ID=$sysmon_events}"}
|
||||||
|
"WMI-Activity"{$filter="@{path=""$file"";ID=$wmi_events}"}
|
||||||
default {"Logic error 1, should not reach here...";Exit 1}
|
default {"Logic error 1, should not reach here...";Exit 1}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -658,6 +719,7 @@ function Create-Filter($file, $logname)
|
|||||||
"Applocker" {$filter="@{logname=""Microsoft-Windows-AppLocker/EXE and DLL"";ID=$applocker_events}"}
|
"Applocker" {$filter="@{logname=""Microsoft-Windows-AppLocker/EXE and DLL"";ID=$applocker_events}"}
|
||||||
"Powershell" {$filter="@{logname=""Microsoft-Windows-PowerShell/Operational"";ID=$powershell_events}"}
|
"Powershell" {$filter="@{logname=""Microsoft-Windows-PowerShell/Operational"";ID=$powershell_events}"}
|
||||||
"Sysmon" {$filter="@{logname=""Microsoft-Windows-Sysmon/Operational"";ID=$sysmon_events}"}
|
"Sysmon" {$filter="@{logname=""Microsoft-Windows-Sysmon/Operational"";ID=$sysmon_events}"}
|
||||||
|
"WMI-Activity"{$filter="@{logname=""Microsoft-Windows-WMI-Activity/Operational"";ID=$wmi_events}"}
|
||||||
default {"Logic error 2, should not reach here...";Exit 1}
|
default {"Logic error 2, should not reach here...";Exit 1}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -689,6 +751,9 @@ function Check-Command(){
|
|||||||
if ($commandline -Match "\-enc.*[A-Za-z0-9/+=]{100}"){
|
if ($commandline -Match "\-enc.*[A-Za-z0-9/+=]{100}"){
|
||||||
$base64= $commandline -Replace "^.* \-Enc(odedCommand)? ",""
|
$base64= $commandline -Replace "^.* \-Enc(odedCommand)? ",""
|
||||||
}
|
}
|
||||||
|
ElseIf ($commandline -Match "\-En.*[A-Za-z0-9/+=]{100}"){
|
||||||
|
$base64= $commandline -Replace "^.* \-En",""
|
||||||
|
}
|
||||||
ElseIf ($commandline -Match ":FromBase64String\("){
|
ElseIf ($commandline -Match ":FromBase64String\("){
|
||||||
$base64 = $commandline -Replace "^.*:FromBase64String\(\'*",""
|
$base64 = $commandline -Replace "^.*:FromBase64String\(\'*",""
|
||||||
$base64 = $base64 -Replace "\'.*$",""
|
$base64 = $base64 -Replace "\'.*$",""
|
||||||
@ -782,6 +847,14 @@ function Check-Creator($command,$creator){
|
|||||||
$creatortext += "PowerShell launched via WMI: $creator`n"
|
$creatortext += "PowerShell launched via WMI: $creator`n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ElseIf ($command -Match "cmd.exe"){
|
||||||
|
if ($creator -Match "PSEXESVC"){
|
||||||
|
$creatortext += "cmd.exe launched via PsExec: $creator`n"
|
||||||
|
}
|
||||||
|
ElseIf($creator -Match "WmiPrvSE"){
|
||||||
|
$creatortext += "cmd.exe launched via WMI: $creator`n"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $creatortext
|
return $creatortext
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
# Requires Posh-VirusTotal: https://github.com/darkoperator/Posh-VirusTotal
|
# Requires VirusTotalAnalyzer: https://github.com/EvotecIT/VirusTotalAnalyzer
|
||||||
#
|
#
|
||||||
# Plus a (free) VirusTotal API Key: https://www.virustotal.com/en/documentation/public-api/
|
# Plus a (free) VirusTotal API Key: https://www.virustotal.com/en/documentation/public-api/
|
||||||
#
|
#
|
||||||
|
Import-Module VirusTotalAnalyzer -Force
|
||||||
|
|
||||||
|
# API KEY can be found once you register to Virus Total service (it's free)
|
||||||
|
$VTApi = '<Your API Key>'
|
||||||
|
|
||||||
$hashdirectory = ".\hashes"
|
$hashdirectory = ".\hashes"
|
||||||
$safelistfile=".\file-safelist.csv"
|
$safelistfile=".\safelists\win10-x64.csv"
|
||||||
# Load the safelist into a hash table
|
# Load the safelist into a hash table
|
||||||
if (Test-Path $safelistfile){
|
if (Test-Path $safelistfile){
|
||||||
$safelist = Get-Content $safelistfile | Select-String '^[^#]' | ConvertFrom-Csv
|
$safelist = Get-Content $safelistfile | Select-String '^[^#]' | ConvertFrom-Csv
|
||||||
@ -21,32 +26,30 @@ Get-ChildItem $hashdirectory | Foreach-Object{
|
|||||||
}
|
}
|
||||||
Else{
|
Else{
|
||||||
try{
|
try{
|
||||||
$VTreport = Get-VTFileReport $SHA256
|
$VTreport = Get-VirusReport -ApiKey $VTApi -Hash "$SHA256"
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Write-Host "`r`nAttempted to run: Get-VTFileReport $SHA256`r`r"
|
Write-Host "`r`nAttempted to run: Get-Virusreport $SHA256`r`r"
|
||||||
Write-Host "Error: " $_.Exception.Message "`n"
|
Write-Host "Error: " $_.Exception.Message "`n"
|
||||||
Write-Host "Have you installed Posh-VirusTotal and set the VirusTotal API key?"
|
Write-Host "Have you installed VirusTotalAnalyzer and set the VirusTotal API key?"
|
||||||
Write-Host " - See: https://github.com/darkoperator/Posh-VirusTotal`r`n"
|
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 <API Key>`r`n"
|
|
||||||
Write-Host "Exiting...`n"
|
Write-Host "Exiting...`n"
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
if ($VTreport.positives -eq 0){
|
$positives=$VTreport.Data.attributes.last_analysis_stats.malicious
|
||||||
|
if ($positives -eq 0){
|
||||||
# File is clean
|
# File is clean
|
||||||
Rename-Item -Path "$hashdirectory\$SHA256" -NewName "$SHA256.clean"
|
Rename-Item -Path "$hashdirectory\$SHA256" -NewName "$SHA256.clean"
|
||||||
}
|
}
|
||||||
ElseIf ($VTreport.positives -gt 0){
|
ElseIf ($positives -gt 0){
|
||||||
# File is flagged by Virustotal
|
# File is flagged by Virustotal
|
||||||
$positives=$VTreport.positives
|
|
||||||
Write-Host " - Hash was detected by $positives Virustotal scanners"
|
Write-Host " - Hash was detected by $positives Virustotal scanners"
|
||||||
if ($positives -eq 1){
|
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 " - 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 " - Check the VirusTotal report for more information."
|
||||||
}
|
}
|
||||||
Write-Host " - See $hashdirectory\$SHA256.Virustotal for the full report`r`n"
|
Write-Host " - See $hashdirectory\$SHA256.Virustotal for the full report`r`n"
|
||||||
$VTreport | Set-Content "$hashdirectory\$SHA256.Virustotal"
|
$VTreport.Data.attributes | Set-Content "$hashdirectory\$SHA256.Virustotal"
|
||||||
# Rename original hash file, add the Virustotal positive count as a numbered extension
|
# Rename original hash file, add the Virustotal positive count as a numbered extension
|
||||||
# $SHA256.$positives
|
# $SHA256.$positives
|
||||||
Rename-Item -Path "$hashdirectory\$SHA256" -NewName "$SHA256.$positives"
|
Rename-Item -Path "$hashdirectory\$SHA256" -NewName "$SHA256.$positives"
|
||||||
|
@ -1,20 +1,51 @@
|
|||||||
$hashdirectory=".\hashes\"
|
$hashdirectory=".\hashes\"
|
||||||
$events = get-winevent @{logname="Microsoft-Windows-Sysmon/Operational";id=1,6,7}
|
$events = get-winevent @{logname="Microsoft-Windows-Sysmon/Operational";id=1,6,7,29}
|
||||||
ForEach ($event in $events) {
|
ForEach ($event in $events) {
|
||||||
if ($event.id -eq 1){ # Process creation
|
if ($event.id -eq 1){ # Process creation
|
||||||
$path=$event.Properties[3].Value # Full path of the file
|
if ($event.Properties.Count -le 16){
|
||||||
$hash=$event.Properties[11].Value # Hashes
|
$path=$event.Properties[3].Value # Full path of the file
|
||||||
|
$hash=$event.Properties[11].Value # Hashes
|
||||||
|
}
|
||||||
|
ElseIf ($event.Properties.Count -le 17){
|
||||||
|
$path=$event.Properties[4].Value # Full path of the file
|
||||||
|
$hash=$event.Properties[16].Value # Hashes
|
||||||
|
}
|
||||||
|
Else {
|
||||||
|
$path=$event.Properties[4].Value # Full path of the file
|
||||||
|
$hash=$event.Properties[17].Value # Hashes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ElseIf ($event.id -eq 29){ # FileExecutableDetected
|
||||||
|
$path=$event.Properties[6].Value # Full path of the file
|
||||||
|
$hash=$event.Properties[7].Value # Hashes
|
||||||
}
|
}
|
||||||
Else{
|
Else{
|
||||||
# Hash and path are part of the message field in Sysmon events 6 and 7. Need to parse the XML
|
# Hash and path are part of the message field in Sysmon events 6 and 7. Need to parse the XML
|
||||||
$eventXML = [xml]$event.ToXml()
|
$eventXML = [xml]$event.ToXml()
|
||||||
If ($event.id -eq 6){ # Driver (.sys) load
|
If ($event.id -eq 6){ # Driver (.sys) load
|
||||||
$path=$eventxml.Event.EventData.Data[1]."#text" # Full path of the file
|
if ($event.Properties.Count -le 6){
|
||||||
$hash=$eventXML.Event.EventData.Data[2]."#text" # Hashes
|
$path=$eventXML.Event.EventData.Data[1]."#text" # Full path of the file
|
||||||
|
$hash=$eventXML.Event.EventData.Data[2]."#text" # Hashes
|
||||||
|
$hash
|
||||||
|
}
|
||||||
|
Else{
|
||||||
|
$path=$eventXML.Event.EventData.Data[2]."#text" # Full path of the file
|
||||||
|
$hash=$eventXML.Event.EventData.Data[3]."#text" # Hashes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ElseIf ($event.id -eq 7){ # Image (.dll) load
|
ElseIf ($event.id -eq 7){ # Image (.dll) load
|
||||||
$path=$eventxml.Event.EventData.Data[4]."#text" # Full path of the file
|
if ($event.Properties.Count -lt 14){
|
||||||
$hash=$eventXML.Event.EventData.Data[5]."#text" # Hashes
|
$path=$eventXML.Event.EventData.Data[4]."#text" # Full path of the file
|
||||||
|
$hash=$eventXML.Event.EventData.Data[5]."#text" # Hashes
|
||||||
|
}
|
||||||
|
Elseif ($event.Properties.Count -lt 15){
|
||||||
|
$path=$eventXML.Event.EventData.Data[5]."#text" # Full path of the file
|
||||||
|
$hash=$eventXML.Event.EventData.Data[10]."#text" # Hashes
|
||||||
|
}
|
||||||
|
Else{
|
||||||
|
$path=$eventXML.Event.EventData.Data[5]."#text" # Full path of the file
|
||||||
|
$hash=$eventXML.Event.EventData.Data[11]."#text" # Hashes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Else{
|
Else{
|
||||||
Out-Host "Logic error 1, should not reach here..."
|
Out-Host "Logic error 1, should not reach here..."
|
||||||
|
@ -10,7 +10,9 @@ Twitter: [@eric_conrad](https://twitter.com/eric_conrad)
|
|||||||
|
|
||||||
http://ericconrad.com
|
http://ericconrad.com
|
||||||
|
|
||||||
Sample evtx files are in the .\evtx directory
|
Sample EVTX files are in the .\evtx directory
|
||||||
|
|
||||||
|
**Note** If your antivirus freaks out after downloading DeepBlueCLI: it's likely reacting to the included EVTX files in the .\evtx directory (which contain command-line logs of malicious attacks, among other artifacts). EVTX files are not harmful. You may need to configure your antivirus to ignore the DeepBlueCLI directory.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
@ -157,5 +159,5 @@ Install Sysmon from Sysinternals: https://docs.microsoft.com/en-us/sysinternals/
|
|||||||
|
|
||||||
DeepBlue and DeepBlueHash currently use Sysmon events, 1, 6 and 7.
|
DeepBlue and DeepBlueHash currently use Sysmon events, 1, 6 and 7.
|
||||||
|
|
||||||
Log SHA256 hashes. Others are fine; DeepBlueCLI will use SHA256.
|
Log SHA256 hashes. Others are fine; DeepBlueHash will use SHA256.
|
||||||
|
|
||||||
|
@ -6,20 +6,27 @@ Parses the Sysmon event logs, grabbing the SHA256 hashes from process creation (
|
|||||||
|
|
||||||
## VirusTotal and Safelisting setup
|
## VirusTotal and Safelisting setup
|
||||||
|
|
||||||
|
**Note**: Virustotal has changed their free API for some users. My old account has this limitation:
|
||||||
|
|
||||||
|
- Daily quota 1 lookups / day
|
||||||
|
- Monthly quota 31 lookups / month
|
||||||
|
|
||||||
|
New accounts get this:
|
||||||
|
|
||||||
|
- Request rate 4 lookups / min
|
||||||
|
- Daily quota 500 lookups / day
|
||||||
|
- Monthly quota 15.5 K lookups / month
|
||||||
|
|
||||||
|
Not sure why that is, so FYI.
|
||||||
|
|
||||||
Setting up VirusTotal hash submissions and safelisting:
|
Setting up VirusTotal hash submissions and safelisting:
|
||||||
|
|
||||||
The hash checker requires Post-VirusTotal:
|
The hash checker requires VirusTotalAnalyzer: https://github.com/EvotecIT/VirusTotalAnalyzer
|
||||||
|
|
||||||
- https://github.com/darkoperator/Posh-VirusTotal
|
|
||||||
|
|
||||||
It also requires a VirusTotal API key:
|
It also requires a VirusTotal API key:
|
||||||
|
|
||||||
- https://www.virustotal.com/en/documentation/public-api/
|
- https://www.virustotal.com/en/documentation/public-api/
|
||||||
|
|
||||||
Then configure your VirusTotal API key:
|
|
||||||
```powershell
|
|
||||||
set-VTAPIKey -APIKey <API Key>
|
|
||||||
```
|
|
||||||
The script assumes a personal API key, and waits 15 seconds between submissions.
|
The script assumes a personal API key, and waits 15 seconds between submissions.
|
||||||
|
|
||||||
## Sysmon setup
|
## Sysmon setup
|
||||||
|
BIN
evtx/metasploit-sysmon.evtx
Normal file
BIN
evtx/metasploit-sysmon.evtx
Normal file
Binary file not shown.
BIN
evtx/sliver-security.evtx
Normal file
BIN
evtx/sliver-security.evtx
Normal file
Binary file not shown.
BIN
evtx/sliver-sysmon.evtx
Normal file
BIN
evtx/sliver-sysmon.evtx
Normal file
Binary file not shown.
BIN
evtx/wmi-event-filter-persistance.evtx
Normal file
BIN
evtx/wmi-event-filter-persistance.evtx
Normal file
Binary file not shown.
4
regexes.txt
Normal file → Executable file
4
regexes.txt
Normal file → Executable file
@ -23,5 +23,9 @@ Type,regex,string
|
|||||||
# Generic cvtres.exe alert, comment out if experiencing false positives
|
# Generic cvtres.exe alert, comment out if experiencing false positives
|
||||||
0,\\cvtres\.exe.*,Resource File To COFF Object Conversion Utility cvtres.exe
|
0,\\cvtres\.exe.*,Resource File To COFF Object Conversion Utility cvtres.exe
|
||||||
0,\\cvtres\.exe.*\\AppData\\Local\\Temp\\[A-Z0-9]{7}\.tmp,PSAttack-style command via cvtres.exe
|
0,\\cvtres\.exe.*\\AppData\\Local\\Temp\\[A-Z0-9]{7}\.tmp,PSAttack-style command via cvtres.exe
|
||||||
|
0,Register-ScheduledTask,Command referencing Register-ScheduledTask (possible ASEP)
|
||||||
|
0,Software\\Microsoft\\Windows\\CurrentVersion\\Run,Reference to registry run key (possible ASEP)
|
||||||
|
0,reg *add,Registry addition (possible ASEP)
|
||||||
|
0,cmd.exe.*\\ADMIN\$\\,cmd.exe accessing the ADMIN$ share
|
||||||
1,^[a-zA-Z]{22}$,Metasploit-style service name: 22 characters, [A-Za-z]
|
1,^[a-zA-Z]{22}$,Metasploit-style service name: 22 characters, [A-Za-z]
|
||||||
1,^[a-zA-Z]{16}$,Metasploit-style service name: 16 characters, [A-Za-z]
|
1,^[a-zA-Z]{16}$,Metasploit-style service name: 16 characters, [A-Za-z]
|
||||||
|
2
safelist.txt
Normal file → Executable file
2
safelist.txt
Normal file → Executable file
@ -7,3 +7,5 @@
|
|||||||
regex
|
regex
|
||||||
^"C:\\Program Files\\Google\\Chrome\\Application\\chrome\.exe"
|
^"C:\\Program Files\\Google\\Chrome\\Application\\chrome\.exe"
|
||||||
^"C:\\Program Files\\Google\\Update\\GoogleUpdate\.exe"
|
^"C:\\Program Files\\Google\\Update\\GoogleUpdate\.exe"
|
||||||
|
^"C:\\Program Files \(x86\)\\Google\\Update\\GoogleUpdate\.exe"
|
||||||
|
"\\AppData\\Local\\Microsoft\\EdgeUpdate\\MicrosoftEdgeUpdate\.exe"
|
||||||
|
Reference in New Issue
Block a user