commands.ps1
function Add-MitreCheckboxes { <# .SYNOPSIS Populates all the MITRE ATT&CK checkboxes. .DESCRIPTION Populates all the MITRE ATT&CK checkboxes in the EventList GUI. Used for initial creation of the checkboxes and the CheckedListBoxes .EXAMPLE Add-MitreCheckboxes Populates all the MITRE ATT&CK checkboxes. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param () $query = "select id, area_name from mitre_areas;" $Script:areas = Invoke-SqliteQuery -Query $Query -DataSource $Database $Script:CheckBox = [ordered]@{} $Script:CheckBoxArea = [ordered]@{} $i=1 $j = 0 $width = 350 $height = 200 $x = 10 $y = 20 + 60 foreach ($area in $areas) { $x = $x +2 $CheckBoxArea[$area.area_name] = New-Object system.Windows.Forms.CheckBox $CheckBoxArea[$area.area_name].text = $area.area_name $CheckBoxArea[$area.area_name].AutoSize = $false $CheckBoxArea[$area.area_name].width = 300 $CheckBoxArea[$area.area_name].height = 20 $CheckBoxArea[$area.area_name].location = New-Object System.Drawing.Point($x,$y) $CheckBoxArea[$area.area_name].Font = 'Microsoft Sans Serif,12' $CheckBoxArea[$area.area_name].Tag = @{AreaName = $area.area_name} $CheckBoxArea[$area.area_name].Add_Click({ param($Senderinfo) & Select-AllCheckboxesFromOneArea -AreaName $($Senderinfo.Tag.AreaName) }) $x = $x -2 $y = $y + 25 $Form.controls.AddRange(@($CheckBoxArea[$area.area_name])) $tmp = New-Object system.Windows.Forms.CheckedListBox $tmp.AutoSize = $false $tmp.width = $width $tmp.height = $height $tmp.CheckOnClick = $true $tmp.location = New-Object System.Drawing.Point($x,$y) $tmp.Font = 'Microsoft Sans Serif,10' $query = "select distinct ma.area_name, mt.technique_id, mt.technique_name from mitre_events me, events_main em, mitre_techniques mt, mitre_areas ma where me.technique_id = mt.id and me.event_id = em.id and me.area_id = ma.id and ma.id = '" + $area.id + "' order by technique_name;" $techniques = Invoke-SqliteQuery -Query $query -DataSource $Database foreach ($technique in $techniques) { $tmp.Items.Add($technique.technique_id + " " + $technique.technique_name,$false) | Out-Null } $y = $y - 25 $i++ if ($x -gt 750){ $x = 10 $y = $y + 225 $i = 1 } $CheckBox.add( $area.area_name, $tmp ) if ($i -ne 1) { $x = $x + 380 } $j = $j + 1 } foreach ($key in $CheckBox.keys) { $Form.controls.AddRange($CheckBox[$key]) } } function Close-Form { <# .SYNOPSIS Closes the Form. .DESCRIPTION Closes the Form, that was passed by the -Form Parameter. Nothing to see here, move on! ;-) .PARAMETER Form A Windows form that should be closed: [system.Windows.Forms.Form] .EXAMPLE Close-Form -Form $Form Closes the Form. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [object]$Form ) $Form.close() } function ConvertFrom-PSSQLString { <# .SYNOPSIS Converts a text string from a database into output text. .DESCRIPTION Converts a text string from a database into output text, which was earlier parsed by the ConvertTo-PSSQLString function. .PARAMETER Text The String to parse for Output. .EXAMPLE ConvertFrom-PSSQLString -Text $queryString Converts a text string from a database into output text. #> [CmdletBinding()] [OutputType([String])] param ( [string]$Text ) $Text = $Text.Replace(""", '"') $Text = $Text.Replace("'", "'") $Text = $Text.Replace("&x00;", "\x00") $Text = $Text.Replace("&n;", "\n") $Text = $Text.Replace("&r;", "\r") $Text = $Text.Replace("\", "\") $Text = $Text.Replace("&x1a;", "\x1a") $Text = $Text.Replace(";", ";") return $Text } function ConvertFrom-PSSQLStringArray { <# .SYNOPSIS Converts a text string from a database into output text. .DESCRIPTION Converts a text string from a database into output text, which was earlier parsed by the ConvertTo-PSSQLString function. .PARAMETER Text The String to parse for Output. .EXAMPLE ConvertFrom-PSSQLStringArray -Text $queryString Converts a text string from a database into output text. #> [CmdletBinding()] [OutputType([String])] param ( [string[]]$Text ) $Text = $Text.Replace(""", '"') $Text = $Text.Replace("'", "'") $Text = $Text.Replace("&x00;", "\x00") $Text = $Text.Replace("&n;", "\n") $Text = $Text.Replace("&r;", "\r") $Text = $Text.Replace("\", "\") $Text = $Text.Replace("&x1a;", "\x1a") $Text = $Text.Replace(";", ";") return $Text } function ConvertTo-PSSQLString { <# .SYNOPSIS Converts a string into a format that can be inserted into a PSSQL database. .DESCRIPTION Converts a string into a format that can be inserted into a PSSQL database without the risk of common SQL injections. .PARAMETER Text The String to parse for the database. .EXAMPLE ConvertTo-PSSQLString -Text $queryString Converts a string into a format that can be inserted into a PSSQL database. #> [CmdletBinding()] [OutputType([String])] param ( [string]$Text ) $Text = $Text.Replace('"', """) $Text = $Text.Replace("'", "'") $Text = $Text.Replace("\x00", "&x00;") $Text = $Text.Replace("\n", "&n;") $Text = $Text.Replace("\r", "&r;") $Text = $Text.Replace("\", "\") $Text = $Text.Replace("\x1a", "&x1a;") $Text = $Text.Replace(";", ";") return $Text } function ConvertTo-PSSQLStringArray { <# .SYNOPSIS Converts a string into a format that can be inserted into a PSSQL database. .DESCRIPTION Converts a string into a format that can be inserted into a PSSQL database without the risk of common SQL injections. .PARAMETER Text The String to parse for the database. .EXAMPLE ConvertTo-PSSQLStringArray -Text $queryString Converts a string into a format that can be inserted into a PSSQL database. #> [CmdletBinding()] [OutputType([String])] param ( [string[]]$Text ) $Text = $Text.Replace('"', """) $Text = $Text.Replace("'", "'") $Text = $Text.Replace("\x00", "&x00;") $Text = $Text.Replace("\n", "&n;") $Text = $Text.Replace("\r", "&r;") $Text = $Text.Replace("\", "\") $Text = $Text.Replace("\x1a", "&x1a;") $Text = $Text.Replace(";", ";") return $Text } function Get-AgentConfigSelect { <# .SYNOPSIS Displays the form to select and display the Agent config of your choice. .DESCRIPTION Displays the form to select and display the Agent config of your choice. All Agent Forwarders are pulled out of the database and are being supported by Sigma. .EXAMPLE Get-AgentConfigSelect Displays the form to select and display the Agent config of your choice. #> [CmdletBinding()] param () [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") $Form = New-Object System.Windows.Forms.Form $Form.width = 700 $Form.height = 550 $Form.Text = "Generate Agent Config" $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10) $Form.Font = $Font $MyGroupBox = New-Object System.Windows.Forms.GroupBox $MyGroupBox.Location = '40,40' $MyGroupBox.size = '600,350' $MyGroupBox.text = "For which forwarder agent would you like to generate a configuration snippet?" $ComboBox2 = New-Object system.Windows.Forms.ComboBox $query = "select name from agent_forwarder_syntax order by name;" $agentFwdNames = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty name if ([string]::IsNullOrEmpty($agentFwdNames)) { $ComboBox2.text = "No Agent Forwarder implemented" } else { $ComboBox2.text = "Select an option..." } $ComboBox2.width = 580 $ComboBox2.height = 40 $agentFwdNames | ForEach-Object {[void] $ComboBox2.Items.Add($_)} $ComboBox2.location = New-Object System.Drawing.Point(50,85) $ComboBox2.Font = 'Microsoft Sans Serif,11' $ComboBox2.Add_SelectedValueChanged({ If ((!([string]::IsNullOrEmpty($ComboBox2.Text))) -and ($ComboBox2.Text -in $agentFwdNames)) { Get-AgentConfigString -ForwarderName $ComboBox2.Text } }) $Script:agentSnippetBox = New-Object System.Windows.Forms.TextBox $agentSnippetBox.Multiline = $True; $agentSnippetBox.Location = New-Object System.Drawing.Size(50,130) $agentSnippetBox.Size = New-Object System.Drawing.Size(580,250) $agentSnippetBox.Scrollbars = "Vertical" $form.Controls.Add($agentSnippetBox) $OKButton = new-object System.Windows.Forms.Button $OKButton.Location = '230,425' $OKButton.Size = '100,40' $OKButton.Text = 'OK' $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK $CancelButton = new-object System.Windows.Forms.Button $CancelButton.Location = '355,425' $CancelButton.Size = '100,40' $CancelButton.Text = "Cancel" $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel $Form.controls.AddRange(@($ComboBox2)) $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton)) $form.AcceptButton = $OKButton $form.CancelButton = $CancelButton $form.Add_Shown({$form.Activate()}) $form.ShowDialog() } function Get-CheckedMitreAreas { <# .SYNOPSIS Gets all Mitre Areas that were checked. .DESCRIPTION Gets all Mitre Areas that were checked. .EXAMPLE Get-CheckedMitreAreas Gets all Mitre Areas that were checked. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param () foreach ($key in $CheckBoxArea.keys) { if (![string]::IsNullOrEmpty($CheckBoxArea[$key].checkedItems)) { foreach ($item in ($CheckBoxArea[$key].checkedItems.Split(" "))) { if (![string]::IsNullOrEmpty($item)) { if ([string]::IsNullOrEmpty($tmpStr)) { $tmpStr = "'$item'" } else { $tmpStr = "$tmpStr, '$item'" } } } } } return $tmpStr } function Get-CheckedMitreTechniques { <# .SYNOPSIS Gets all Mitre Techniques that were checked. .DESCRIPTION Gets all Mitre Techniques that were checked. .EXAMPLE Get-CheckedMitreTechniques Gets all Mitre Techniques that were checked. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param () foreach ($key in $CheckBox.keys) { if (![string]::IsNullOrEmpty($CheckBox[$key].checkedItems)) { foreach ($item in ($CheckBox[$key].checkedItems.Split(" ") | Select-String -Pattern 'T[0-9][0-9][0-9][0-9]' -CaseSensitive)) { if (![string]::IsNullOrEmpty($item)) { if ([string]::IsNullOrEmpty($tmpStr)) { $tmpStr = "'$item'" } else { $tmpStr = "$tmpStr, '$item'" } } } } } return $tmpStr } function Get-DeleteBaselineSelect { <# .SYNOPSIS Shows a pop-up in which the deletion options are being displayed. .DESCRIPTION Shows a pop-up in which the deletion options are being displayed: Delete the selected baseline or Delete all baselines .EXAMPLE Get-DeleteBaselineSelect Shows a pop-up in which the deletion options are being displayed. #> [CmdletBinding()] param () [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") $Form = New-Object System.Windows.Forms.Form $Form.width = 700 $Form.height = 350 $Form.Text = "Delete Baseline" $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10) $Form.Font = $Font $MyGroupBox = New-Object System.Windows.Forms.GroupBox $MyGroupBox.Location = '40,40' $MyGroupBox.size = '600,150' $MyGroupBox.text = "Would you prefer to..." $RadioButton1 = New-Object System.Windows.Forms.RadioButton $RadioButton1.Location = '20,50' $RadioButton1.size = '450,30' $RadioButton1.Checked = $true $RadioButton1.Text = "Delete the selected baseline" $RadioButton2 = New-Object System.Windows.Forms.RadioButton $RadioButton2.Location = '20,85' $RadioButton2.size = '450,30' $RadioButton2.Checked = $false $RadioButton2.Text = "Delete all baselines" $OKButton = new-object System.Windows.Forms.Button $OKButton.Location = '230,200' $OKButton.Size = '100,40' $OKButton.Text = 'OK' $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK $CancelButton = new-object System.Windows.Forms.Button $CancelButton.Location = '355,200' $CancelButton.Size = '100,40' $CancelButton.Text = "Cancel" $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton)) $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2,$RadioButton3)) $form.AcceptButton = $OKButton $form.CancelButton = $CancelButton $form.Add_Shown({$form.Activate()}) $dialogResult = $form.ShowDialog() if ($dialogResult -eq "OK"){ if ($RadioButton1.Checked){ Remove-OneBaseline -BaselineName $ComboBox1Value Reset-MitreCheckboxes $baselineNames = Get-BaselineNameFromDB Sync-ComboBox -ComboBox $ComboBox1 -Items $baselineNames } elseif ($RadioButton2.Checked){ Remove-AllBaselines Reset-MitreCheckboxes $baselineNames = Get-BaselineNameFromDB Sync-ComboBox -ComboBox $ComboBox1 -Items $baselineNames } } } function Get-EventListConfigSelect { <# .SYNOPSIS Shows a pop-up in which the EventList configuration options are being displayed. .DESCRIPTION Shows a pop-up in which the EventList configuration options are being displayed. .EXAMPLE Get-EventListConfigSelect Shows a pop-up in which the EventList configuration options are being displayed. #> [CmdletBinding()] param () [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") $Form = New-Object System.Windows.Forms.Form $Form.width = 700 $Form.height = 400 $Form.Text = "Configure EventList" $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10) $Form.Font = $Font $MyGroupBox = New-Object System.Windows.Forms.GroupBox $MyGroupBox.Location = '40,40' $MyGroupBox.size = '600,200' $MyGroupBox.text = "Configure EventList" $Checkbox1 = New-Object System.Windows.Forms.Checkbox $Checkbox1.Location = '20,50' $Checkbox1.size = '500,90' $sigmaPath = Get-SigmaPath if ($sigmaPath) { $Checkbox1.Checked = $true $Checkbox1.Text = "Sigma Path configured: $sigmaPath" } else { $Checkbox1.Checked = $false $Checkbox1.Text = "Configure Sigma Path" } $Checkbox1.Add_Click({ if ($Checkbox1.checked) { $sigmaPath = Start-FilePicker -description "Please select where the sigmac file is located" if ($sigmaPath) { Add-EventListConfiguration -sigmaPath $sigmaPath $Checkbox1.Text = "Sigma Path configured: $sigmaPath" } } else { Remove-EventListConfiguration -sigmaPath $Checkbox1.Text = "Configure Sigma Path" } }) $OKButton = new-object System.Windows.Forms.Button $OKButton.Location = '230,250' $OKButton.Size = '100,40' $OKButton.Text = 'OK' $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK $CancelButton = new-object System.Windows.Forms.Button $CancelButton.Location = '355,250' $CancelButton.Size = '100,40' $CancelButton.Text = "Cancel" $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton)) $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2,$Checkbox1,$Checkbox2)) $form.AcceptButton = $OKButton $form.CancelButton = $CancelButton $form.Add_Shown({$form.Activate()}) $form.ShowDialog() } function Get-EventListSelect { <# .SYNOPSIS Shows a pop-up in which the EventList generation options are being displayed. .DESCRIPTION Shows a pop-up in which the EventList generation options are being displayed. .EXAMPLE Get-EventListSelect Shows a pop-up in which the EventList generation options are being displayed. #> [CmdletBinding()] param () [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") $Form = New-Object System.Windows.Forms.Form $Form.width = 700 $Form.height = 400 $Form.Text = "EventList" $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10) $Form.Font = $Font $MyGroupBox = New-Object System.Windows.Forms.GroupBox $MyGroupBox.Location = '40,40' $MyGroupBox.size = '600,200' $MyGroupBox.text = "Which Events would you like to process?" $RadioButton1 = New-Object System.Windows.Forms.RadioButton $RadioButton1.Location = '20,50' $RadioButton1.size = '450,30' $RadioButton1.Checked = $true $RadioButton1.Text = "Baseline Events only" $RadioButton2 = New-Object System.Windows.Forms.RadioButton $RadioButton2.Location = '20,85' $RadioButton2.size = '450,30' $RadioButton2.Checked = $false $RadioButton2.Text = "All MITRE ATT&&CK Events" $Checkbox1 = New-Object System.Windows.Forms.Checkbox $Checkbox1.Location = '50,130' $Checkbox1.size = '350,30' $Checkbox1.Checked = $false $Checkbox1.Text = "Export as CSV" $Checkbox1.Add_Click({ $Script:ExportFolder = Start-FilePicker -description "Please select where to store your Excel file" }) $OKButton = new-object System.Windows.Forms.Button $OKButton.Location = '230,250' $OKButton.Size = '100,40' $OKButton.Text = 'OK' $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK $CancelButton = new-object System.Windows.Forms.Button $CancelButton.Location = '355,250' $CancelButton.Size = '100,40' $CancelButton.Text = "Cancel" $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton)) $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2,$Checkbox1)) $form.AcceptButton = $OKButton $form.CancelButton = $CancelButton $form.Add_Shown({$form.Activate()}) $dialogResult = $form.ShowDialog() if ($dialogResult -eq "OK"){ if ($RadioButton1.Checked){ Get-BaselineEventList -generateExcelYsn $Checkbox1.Checked } elseif ($RadioButton2.Checked){ Get-MitreEventList -generateExcelYsn $Checkbox1.Checked } } } function Get-ImportSelect { <# .SYNOPSIS Shows a pop-up in which the baseline import options are being displayed. .DESCRIPTION Shows a pop-up in which the baseline import options are being displayed. .EXAMPLE Get-ImportSelect Shows a pop-up in which the baseline import options are being displayed. #> [CmdletBinding()] param () [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") $Form = New-Object System.Windows.Forms.Form $Form.width = 700 $Form.height = 350 $Form.Text = "Import Baseline" $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10) $Form.Font = $Font $MyGroupBox = New-Object System.Windows.Forms.GroupBox $MyGroupBox.Location = '40,40' $MyGroupBox.size = '600,150' $MyGroupBox.text = "What kind of baseline would you like to import?" $RadioButton1 = New-Object System.Windows.Forms.RadioButton $RadioButton1.Location = '20,50' $RadioButton1.size = '450,30' $RadioButton1.Checked = $true $RadioButton1.Text = "Import a Microsoft Security Baseline or a backed-up GPO" $OKButton = new-object System.Windows.Forms.Button $OKButton.Location = '230,200' $OKButton.Size = '100,40' $OKButton.Text = 'OK' $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK $CancelButton = new-object System.Windows.Forms.Button $CancelButton.Location = '355,200' $CancelButton.Size = '100,40' $CancelButton.Text = "Cancel" $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton)) $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2)) $form.AcceptButton = $OKButton $form.CancelButton = $CancelButton $form.Add_Shown({$form.Activate()}) $dialogResult = $form.ShowDialog() if ($dialogResult -eq "OK"){ if ($RadioButton1.Checked){ $baselineFolder = Start-FilePicker -description "Select a file or directory where the Baselines are located" if (![string]::IsNullOrEmpty($baselineFolder)) { Import-BaselineFromFolder -Path "$baselineFolder" $baselineNames = Get-BaselineNameFromDB Sync-ComboBox -ComboBox $ComboBox1 -Items $baselineNames } else { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup("No Baseline was selected.",0,"Done",0x1) } } } } function Get-IsMitreAreaYsn { <# .SYNOPSIS Returns if a string is a MitreArea. .DESCRIPTION Returns if a string is a MitreArea. .PARAMETER AreaName Prompts you for the Area Name which should be checked. .EXAMPLE Get-IsMitreAreaYsn -BaselineName "MSFT Windows Server 2019 - Domain Controller" Returns all Mitre Techniques that would be covered by the specified baseline. #> [CmdletBinding()] [OutputType([Bool])] param ( [Parameter(Mandatory = $true)] [string]$AreaName ) $query = "select area_name from mitre_areas where area_name = ' + $AreaName + ';" if (Invoke-SqliteQuery -Query $query -DataSource $database) { return $true } else { return $false } } function Get-MitreEvents { <# .SYNOPSIS Returns all events for the selected Mitre techniques. .DESCRIPTION Returns all events for the selected Mitre techniques. .PARAMETER MitreTechniques Lets you specify the Mitre ATT&CK techniques that should be used. .PARAMETER AdvancedAudit If set, only events which will be set from the Advanced Audit options will be taken into account. .PARAMETER EventIds If set, only Event Ids will be returned from this function. .EXAMPLE Get-MitreEvents Returns all events for the selected Mitre techniques. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param ( [Parameter(Mandatory=$True)] [string]$MitreTechniques, [switch]$AdvancedAudit, [switch]$EventIds ) if (![string]::IsNullOrEmpty($MitreTechniques)) { if ($AdvancedAudit){ # if success_failure_id >= 3 it's always s+f / 1 = s / 2 = f $query = "select subcategory_name, guid, sum(success_failure_id) as sf_sum from ( select distinct eaas.subcategory_name, eaas.guid, m.success_failure_id from mitre_techniques t, mitre_events e left join events_main m on e.event_id = m.id left join events_source so on m.so_id = so.id left join events_audit_subcategory eas on m.id = eas.event_id left join events_advanced_audit_subcategories eaas on eas.audit_subc_id = eaas.id where t.technique_id in ($MitreTechniques) and t.id = e.technique_id and e.event_id is not null and so.source_name = 'Advanced Audit Logs' and e.event_id <> '-1' ) group by subcategory_name, guid order by subcategory_name" } elseif ($EventIds) { $query = "select distinct e.event_id from mitre_techniques t, mitre_events e left join events_main m on e.event_id = m.id left join events_source so on m.so_id = so.id left join events_security_recommendation sr on m.sr_id = sr.id where t.technique_id in ($MitreTechniques) and t.id = e.technique_id and e.event_id is not null order by e.event_id" } else { $query = "select t.technique_id, t.technique_name, e.event_id, m.event_name, m.link_text, so.source_name, sr.sec_rec_name from mitre_techniques t, mitre_events e left join events_main m on e.event_id = m.id left join events_source so on m.so_id = so.id left join events_security_recommendation sr on m.sr_id = sr.id where t.technique_id in ($MitreTechniques) and t.id = e.technique_id and e.event_id is not null order by e.event_id" } $resultStr = Invoke-SqliteQuery -Query $query -DataSource $database } return $resultStr } function Get-MitreTechniquesFromBaseline { <# .SYNOPSIS Returns a list of MitreTechniques that would be covered by a specific baseline. .DESCRIPTION Returns a list of MitreTechniques that would be covered by a specific baseline. .PARAMETER BaselineName Prompts you for the Baseline Name that should be used to generate the Mitre Techniques list from. .EXAMPLE Get-MitreTechniquesFromBaseline -BaselineName "MSFT Windows Server 2019 - Domain Controller" Returns all Mitre Techniques that would be covered by the specified baseline. #> [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [string]$BaselineName ) $query = "select distinct a.technique_id as technique_id from ( select * from v_mitre_matches_baseline ) a left join ( select * from v_mitre_matches_baseline where baseline_name = '$BaselineName' ) b on a.technique_id = b.technique_id where b.baseline_name is not null order by a.area_id, a.technique_name;" $MitreTechniques = "'" + ((Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty technique_id) -join "', '") + "'" return $MitreTechniques } function Get-Queries { <# .SYNOPSIS Returns queries for the selected MITRE ATT&CK Techniques & areas. .DESCRIPTION Returns queries for the selected MITRE ATT&CK Techniques & areas. .PARAMETER TechniqueIds Prompts you for the TechniqueIds which should be used to generate the queries. .PARAMETER AreaNames Prompts you for the Area Names which should be used to generate the queries. .EXAMPLE Get-Queries -TechniqueIds "'T1086', 'T1039', 'T1090'" -AreaNames "" Returns queries for the selected MITRE ATT&CK Techniques & areas. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param ( [Parameter(Mandatory=$True)] [string]$TechniqueIds, [string]$AreaNames ) $query = "select distinct ma.area_name, mt.technique_id, mt.technique_name, qm.title, qm.description, qm.status, qm.date, qm.author, qm.raw_yaml, qm.level, qm.filename from mitre_events me, mitre_techniques mt, mitre_areas ma, queries_data_yaml_tags qt, queries_data_yaml_main qm where me.technique_id = mt.id and qt.mitre_technique_id = mt.id and qt.m_id = qm.id and me.area_id = ma.id and ( (mt.technique_id in ($TechniqueIds) ) or (ma.area_name in ($AreaNames)) ) order by area_id, technique_name;" $result = Invoke-SqliteQuery -Query $query -DataSource $database return $result } function Get-QueriesSelect { <# .SYNOPSIS Shows a pop-up in which the query creation options are being displayed. .DESCRIPTION Shows a pop-up in which the query creation options are being displayed. .EXAMPLE Get-QueriesSelect Shows a pop-up in which the query creation options are being displayed. #> [CmdletBinding()] param () [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") $Form = New-Object System.Windows.Forms.Form $Form.width = 700 $Form.height = 400 $Form.Text = "Generate Queries" $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10) $Form.Font = $Font $MyGroupBox = New-Object System.Windows.Forms.GroupBox $MyGroupBox.Location = '40,40' $MyGroupBox.size = '600,200' $MyGroupBox.text = "How would you like to create your queries?" $RadioButton1 = New-Object System.Windows.Forms.RadioButton $RadioButton1.Location = '20,50' $RadioButton1.size = '450,30' $RadioButton1.Checked = $true $RadioButton1.Text = "Please generate SIGMA queries for:" $ComboSiemBox = New-Object system.Windows.Forms.ComboBox $supportedSiem = Get-SigmaSupportedSiemFromDb if ([string]::IsNullOrEmpty($supportedSiem)) { $ComboSiemBox.text = "No supported Siem solution imported" } else { $ComboSiemBox.text = "Select Siem solution" } $ComboSiemBox.width = 200 $ComboSiemBox.height = 40 $supportedSiem | ForEach-Object {[void] $ComboSiemBox.Items.Add($_)} $ComboSiemBox.location = New-Object System.Drawing.Point(76,120) $ComboSiemBox.Font = 'Microsoft Sans Serif,11' $ComboSiemBox.Add_SelectedValueChanged({ $Script:SelectedComboSiemBox = $ComboSiemBox.Text }) $Form.controls.AddRange(@($ComboSiemBox)) $RadioButton2 = New-Object System.Windows.Forms.RadioButton $RadioButton2.Location = '20,115' $RadioButton2.size = '450,30' $RadioButton2.Checked = $false $RadioButton2.Text = "Generate Queries in YAML format" $OKButton = new-object System.Windows.Forms.Button $OKButton.Location = '230,250' $OKButton.Size = '100,40' $OKButton.Text = 'OK' $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK $CancelButton = new-object System.Windows.Forms.Button $CancelButton.Location = '355,250' $CancelButton.Size = '100,40' $CancelButton.Text = "Cancel" $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton)) $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2,$Checkbox1)) $form.AcceptButton = $OKButton $form.CancelButton = $CancelButton $form.Add_Shown({$form.Activate()}) $dialogResult = $form.ShowDialog() if ($dialogResult -eq "OK"){ if ($ExportFolder = Start-FilePicker -description "Where do you want to save your Queries?") { if ($RadioButton1.Checked){ Get-SigmaQueries -Path $ExportFolder -siemName $SelectedComboSiemBox } elseif ($RadioButton2.Checked){ Get-SigmaQueries -Path $ExportFolder -siemName $SelectedComboSiemBox -yamlOnly } } } } function Get-YamlAdminSelect { <# .SYNOPSIS Shows a pop-up in which the YAML admin options are being displayed. .DESCRIPTION Shows a pop-up in which the YAML admin options are being displayed. .EXAMPLE Get-YamlAdminSelect Shows a pop-up in which the YAML admin options are being displayed. #> [CmdletBinding()] param () [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") $Form = New-Object System.Windows.Forms.Form $Form.width = 700 $Form.height = 350 $Form.Text = "Delete Baseline" $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10) $Form.Font = $Font $MyGroupBox = New-Object System.Windows.Forms.GroupBox $MyGroupBox.Location = '40,40' $MyGroupBox.size = '600,150' $MyGroupBox.text = "Would you prefer to..." $RadioButton1 = New-Object System.Windows.Forms.RadioButton $RadioButton1.Location = '20,50' $RadioButton1.size = '450,30' $RadioButton1.Checked = $true $RadioButton1.Text = "Import YAML Configuration Files" $RadioButton2 = New-Object System.Windows.Forms.RadioButton $RadioButton2.Location = '20,85' $RadioButton2.size = '450,30' $RadioButton2.Checked = $false $RadioButton2.Text = "Remove existing YAML Configuration" $OKButton = new-object System.Windows.Forms.Button $OKButton.Location = '230,200' $OKButton.Size = '100,40' $OKButton.Text = 'OK' $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK $CancelButton = new-object System.Windows.Forms.Button $CancelButton.Location = '355,200' $CancelButton.Size = '100,40' $CancelButton.Text = "Cancel" $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton)) $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2,$RadioButton3)) $form.AcceptButton = $OKButton $form.CancelButton = $CancelButton $form.Add_Shown({$form.Activate()}) $dialogResult = $form.ShowDialog() if ($dialogResult -eq "OK"){ if ($RadioButton1.Checked){ Import-YamlCofigurationFiles } elseif ($RadioButton2.Checked){ Remove-AllYamlConfigurations } } } function Import-BaselineIntoDb { <# .SYNOPSIS Imports one policy into the database, if not existant yet. .DESCRIPTION Imports one policy into the database, if not existant yet. .PARAMETER Path Defines the path where the baseline is located. .PARAMETER PolicyName Name of the baseline which should be imported. .EXAMPLE Import-BaselineIntoDb -Path $item.FullName -PolicyName $auditPolicyNameStr Imports one policy into the database, if not existant yet. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] [cmdletbinding()] param ( [Parameter(Mandatory = $true)] [string]$Path, [Parameter(Mandatory = $true)] [string]$PolicyName ) $PolicyName = ConvertTo-PSSQLString($PolicyName) $Query = "select name from baseline_main where name = '$PolicyName';" if (!(Invoke-SqliteQuery -Query $Query -DataSource $Database)){ $settings = Import-Csv -Path $Path if ($settings) { $Query = "insert into baseline_main (name) values ('$PolicyName');SELECT last_insert_rowid();" $b_id = Invoke-SqliteQuery -Query $Query -DataSource $Database | Select-Object -ExpandProperty "last_insert_rowid()" ForEach ($setting in $settings){ $policy_target = $PolicyName = ConvertTo-PSSQLString($($setting."Policy Target")) $subcategory = ConvertTo-PSSQLString($($setting."Subcategory")) $subcategory_guid = ConvertTo-PSSQLString($($setting."Subcategory GUID")) $inclusion_setting = ConvertTo-PSSQLString($($setting."Inclusion Setting")) $exclusion_setting = ConvertTo-PSSQLString($($setting."Exclusion Setting")) $setting_value = ConvertTo-PSSQLString($($setting."Setting Value")) $Query = "insert into baseline_data (policy_target,subcategory,subcategory_guid,inclusion_setting,exclusion_setting,setting_value,b_id) values ('$policy_target','$subcategory','$subcategory_guid','$inclusion_setting','$exclusion_setting','$setting_value','$b_id');" Invoke-SqliteQuery -Query $Query -DataSource $Database } } } else { $PolicyName = ConvertFrom-PSSQLString($PolicyName) $resultStr = "Baseline $PolicyName was already imported" if ($Script:openFromGui) { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup($resultStr,0,"Done",0x1) } else { write-host $resultStr } } } function Import-YamlCofigurationFiles { <# .SYNOPSIS Imports one or more YAML configuration file(s) from a folder into the database. .DESCRIPTION Imports one or more YAML configuration file(s) from a folder into the database. YAML configurations can be found in the sigma GitHub repository. .EXAMPLE Import-YamlCofigurationFiles Imports one or more YAML configuration file(s) from a folder into the database. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param () $configFolder = Start-FilePicker -description "Select the directory where the YAML configuration files are located" if (![string]::IsNullOrEmpty($configFolder)) { Import-YamlCofigurationFromFolder -Path $configFolder } else { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup("No Folder was selected.",0,"Done",0x1) } } function Remove-OneBaseline { <# .SYNOPSIS Removes one imported baseline from the database. .DESCRIPTION Removes one imported baseline from the database. .PARAMETER BaselineName Defines the name of the baseline. .PARAMETER Confirm Prompts you for confirmation before executing the command. .PARAMETER WhatIf Displays a message that describes the effect of the command, instead of executing the command. .EXAMPLE Remove-OneBaseline -BaselineName "SCM Windows 10 - Computer" Removes one imported baseline from the database. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] [CmdletBinding(SupportsShouldProcess)] Param ( [Parameter(Mandatory = $True, ValueFromPipeline = $True)] [string]$BaselineName ) process { $valuesFromDb = Get-BaselineNameFromDB if (($BaselineName -eq "No Baselines imported") -or ($BaselineName -eq "Select Baseline") -or [string]::IsNullOrEmpty($BaselineName)) { $returnStr = "No Baseline was selected." if ($Script:openFromGui) { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup($returnStr, 0, "Delete selected baseline", 0x1) } Write-Host $returnStr } else { If ($BaselineName -in $valuesFromDb) { $query = "select id from baseline_main where name like '$BaselineName' ;" $id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty id $query = "delete from baseline_data where b_id = $id ; delete from baseline_main where id = $id ;" Invoke-SqliteQuery -Query $query -DataSource $database $returnStr = "Baseline $BaselineName was deleted successfully." if ($Script:openFromGui) { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup($returnStr, 0, "Delete selected baseline", 0x1) } } } } } function Reset-MitreCheckboxes { <# .SYNOPSIS Unchecks all checked MITRE ATT&CK technique & area checkboxes. .DESCRIPTION Unchecks all checked MITRE ATT&CK technique & area checkboxes. Also resets the baseline combobox selection. .PARAMETER Confirm Prompts you for confirmation before executing the command. .PARAMETER WhatIf Displays a message that describes the effect of the command, instead of executing the command. .EXAMPLE Reset-MitreCheckboxes Unchecks all checked MITRE ATT&CK technique & area checkboxes. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")] [CmdletBinding(SupportsShouldProcess)] param () foreach ($key in $CheckBox.keys) { for ($i=0; $i -lt $CheckBox[$key].Items.count; $i++) { $CheckBox[$key].SetItemChecked($i, $false) } } foreach ($key in $CheckBoxArea.keys) { $($CheckBoxArea[$key]).checked = $false } $ComboBox1Value = "" $ComboBox1.text = "Select Baseline" } function Select-AllCheckboxesFromOneArea { <# .SYNOPSIS Selects all Checkboxes of the techniques mapped to an area. .DESCRIPTION Selects all Checkboxes of the techniques mapped to an area. .PARAMETER AreaName The name of the area. .EXAMPLE Select-AllCheckboxesFromOneArea -AreaName "Initial Access" Selects all Checkboxes of the techniques mapped to an area. #> [CmdletBinding()] param ( [string]$AreaName ) if ($CheckBoxArea[$AreaName].checked) { $isChecked = $true } else { $isChecked = $false } for ($i=0; $i -lt $CheckBox[$AreaName].Items.count; $i++) { $CheckBox[$AreaName].SetItemChecked($i, $isChecked) } } Function Start-FilePicker{ <# .SYNOPSIS Lets the user select a folder and returns the path. .DESCRIPTION Lets the user select a folder and returns the path. .PARAMETER description Specifies the description dialog which is shown to the user .PARAMETER Confirm Prompts you for confirmation before executing the command. .PARAMETER WhatIf Displays a message that describes the effect of the command, instead of executing the command. .EXAMPLE Start-FilePicker -description "Select a file or directory" Lets the user select a folder and returns the path. and displays the description "Select a file or directory" #> [CmdletBinding(SupportsShouldProcess)] param( [string]$description = "Select a file or directory" ) $browse = New-Object System.Windows.Forms.FolderBrowserDialog $browse.SelectedPath = "$ENV:UserProfile\Downloads" $browse.Description = $description $show = $browse.ShowDialog() if ($show -eq "OK") { $test = $browse.SelectedPath | Out-String $test = $test -replace "`n|`r" return $test } } function Sync-ComboBox { <# .SYNOPSIS This functions helps you load baselines into a ComboBox. .DESCRIPTION Use this function to dynamically load baselines into the ComboBox control. .PARAMETER ComboBox The ComboBox control you want to add items to. .PARAMETER Items The object or objects you wish to load into the ComboBox's Items collection. .PARAMETER DisplayMember Indicates the property to display for the items in this control. .PARAMETER Append Adds the item(s) to the ComboBox without clearing the Items collection. .EXAMPLE Sync-ComboBox -ComboBox $ComboBox1 -Items $baselineNames Loads baselines into a ComboBox. #> [CmdletBinding()] Param ( [ValidateNotNull()] [Parameter(Mandatory=$true)] [System.Windows.Forms.ComboBox]$ComboBox, $Items, [string]$DisplayMember, [switch]$Append ) if(-not$Append) { $ComboBox.Items.Clear() $ComboBox.text = "No Baselines imported" } if($Items-is [Object[]]) { $ComboBox.Items.AddRange($Items) $ComboBox.text = "Select Baseline" } elseif ($Items-is [Array]) { $ComboBox.BeginUpdate() foreach($obj in $Items) { $ComboBox.Items.Add($obj) $ComboBox.text = "Select Baseline" } $ComboBox.EndUpdate() } elseif (![string]::IsNullOrEmpty($Items)) { $ComboBox.Items.Add($Items) $ComboBox.text = "Select Baseline" } $ComboBox.DisplayMember =$DisplayMember } function Sync-MitreCheckboxes { <# .SYNOPSIS Syncs all Mitre Checkboxes according to the selected baseline. .DESCRIPTION Syncs all Mitre Checkboxes according to the selected baseline. .PARAMETER BaselineName Defines the baseline for which the MITRE ATT&CK Checkboxes should be synced. .EXAMPLE Sync-MitreCheckboxes -BaselineName "SCM Windows 10 - Computer" Syncs all Mitre Checkboxes according to the selected baseline. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param ( [string]$BaselineName ) if (![string]::IsNullOrEmpty($BaselineName)) { $query = "select distinct a.area_name as area_name, a.area_id as area_id, a.technique_name as technique_name, a.technique_id as technique_id, b.baseline_name as baseline_name from ( select * from v_mitre_matches_baseline ) a left join ( select * from v_mitre_matches_baseline where baseline_name = '" + $BaselineName + "' ) b on a.technique_id = b.technique_id order by a.area_id, a.technique_name;" $results = Invoke-SqliteQuery -Query $Query -DataSource $Database $i=0 foreach ($result in $results) { if (($old_area_name) -and ($old_area_name -ne $result.area_name)) { if ($i -eq $cntChecked) { $CheckBoxArea[$old_area_name].checked = $true } else { $CheckBoxArea[$old_area_name].checked = $false } $i = 0 $cntChecked = 0 } if (![string]::IsNullOrEmpty($result.baseline_name)) { $CheckBox[$result.area_name].SetItemChecked($i, $true) $cntChecked = $cntChecked + 1 } else { $CheckBox[$result.area_name].SetItemChecked($i, $false) } $old_area_name = $result.area_name $i = $i + 1 } } } function Add-EventListConfiguration { <# .SYNOPSIS Writes an EventList configuration to the database. .DESCRIPTION Writes an EventList configuration to the database. Important: Specify the sigma\tools folder! Configurable options: - Path where Sigma is located to automatically parse the desired queries. - Default Output Path: Avoid clicking 1000 times to specify a default output location. .PARAMETER sigmaPath Path where Sigma is located to automatically parse the desired queries. .PARAMETER defaultOutputPath Default Output Path: Avoid clicking 1000 times to specify a default output location. .EXAMPLE Add-EventListConfiguration -sigmaPath "C:\tmp\sigma\tools" Writes the configuration for the Sigma Path to the database. #> [CmdletBinding()] param( [string]$sigmaPath ) if ($sigmaPath) { $query = "Update EventList_configuration set sigma_path='" + $sigmaPath + "' where id=1;" } if ($query) { Invoke-SqliteQuery -Query $query -DataSource $database } } function Get-AgentConfigString { <# .SYNOPSIS Gets all the event ids that you need to monitor the selected MITRE Techniques & areas. .DESCRIPTION Gets all the event ids that you need to monitor the selected MITRE Techniques & areas and matches it to the selected event forwarder syntax. .PARAMETER Identity Prompts you for the Identity that should be used to generate an Agent Configuration from. You can either use a baseline name or one or multiple Mitre Technique IDs. .PARAMETER ForwarderName Specifies the name of the Agent Forwarder for which the config should be queried: - splunk - xpath - mdatp .EXAMPLE Get-AgentConfigString -ForwarderName splunk Gets all the event ids for the Splunk Universal Forwarder that you need to monitor the selected MITRE Techniques & areas. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BaselineName', 'TechniqueId')] [string]$Identity, [Parameter(Mandatory=$True)] [string]$ForwarderName ) process { if ($Script:openFromGui) { $MitreTechniques = $(Get-CheckedMitreTechniques) } else { if ($identity) { if (Get-BaselineNameFromDB -BaselineName $Identity){ $MitreTechniques = Get-MitreTechniquesFromBaseline -BaselineName $Identity } elseif ($Identity -match "^T\d{4}$") { $MitreTechniques = $("'" + $Identity + "'") } elseif ( ($Identity -match "^['T\d{4}$]") -or ($Identity -match "^T\d{4}$") ) { $MitreTechniques = $Identity } } } if ($MitreTechniques) { if ($Script:openFromGui) { $query = "select * from agent_forwarder_syntax where name = '" + (ConvertTo-PSSQLString($ForwarderName)) + "';" } else { $query = "select * from agent_forwarder_syntax where short_name = '" + (ConvertTo-PSSQLString($ForwarderName)) + "';" } $results = Invoke-SqliteQuery -Query $query -DataSource $database foreach ($result in $results) { $eventStr = Get-MitreEvents -MitreTechniques $MitreTechniques -EventIds | Select-Object -ExpandProperty event_id -Unique | foreach-Object { $result.single_event_syntax -replace ("{{SINGLE_EVENTID}}", $_) } $eventStr = [string]$eventStr -replace(" ", ($result.event_separator + " ")) $eventStr = [string]$eventStr -replace(($result.event_separator + " -1"), "") if ($result.single_event_syntax -eq "{{SINGLE_EVENTID}}") { $eventStr = [string]$eventStr -replace("-1", "") } else { $SingleEventSyntaxReplaced = $result.single_event_syntax -replace ("{{SINGLE_EVENTID}}", "") $eventStr = [string]$eventStr -replace(($SingleEventSyntaxReplaced + "-1" + $result.event_separator), "") } $syntaxStr = $result.syntax -replace ("{{EVENTIDS}}", $eventStr) -replace "`n", "`r`n" $syntaxStr = $syntaxStr -replace(("= " + $result.event_separator), "=") if ($Script:openFromGui) { $agentSnippetBox.Text = $syntaxStr } else { write-host $syntaxStr } } } else { write-host "No MITRE ATT&CK techniques were selected." } } } function Get-BaselineEventList { <# .SYNOPSIS Gets an EventList for the selected Baseline. .DESCRIPTION Gets an EventList for the Baseline which was selected from the Combobox in the GUI. .PARAMETER BaselineName Prompts you for the Baseline Name that should be used to generate an EventList from. .PARAMETER generateExcelYsn Defines if an Excel document will be generated. When checked, one can define where the document should be stored. .EXAMPLE Get-BaselineEventList -generateExcelYsn $true Gets an EventList for the selected Baseline. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] [CmdletBinding()] param ( [Parameter(ValueFromPipeline=$True)] [string]$BaselineName, [boolean]$generateExcelYsn = $false ) process { if ($Script:openFromGui) { $BaselineName = $ComboBox1Value } if (($BaselineName -eq "No Baselines imported") -or ($BaselineName -eq "Select Baseline") -or [string]::IsNullOrEmpty($BaselineName)){ $returnStr = "No Baseline was selected." if ($Script:openFromGui) { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup($returnStr,0,"Generate EventList",0x1) } else { Write-Host $returnStr } } else { $BaselineName = ConvertTo-PSSQLString($BaselineName) $query = "select eaac.category_name as Category, d.subcategory as Subcategory, em.id as 'Event ID', em.event_name as 'Event Description', em.link_text as 'Event Link', d.inclusion_setting as 'Audit Recommendation', d.setting_value 'Audit Recommendation Number', sf.success_failure_name as 'Event S/F', d.policy_target as 'Policy Target', sr.sec_rec_name as Recommendation from baseline_main m, baseline_data d, events_main em, events_source so, events_success_failure sf, events_security_recommendation sr, events_audit_subcategory eas, events_advanced_audit_categories eaac, events_advanced_audit_subcategories eaas where m.id = d.b_id and d.subcategory = eaas.subcategory_name and em.so_id = so.id and em.success_failure_id = sf.id and em.sr_id = sr.id and em.id = eas.event_id and eas.audit_subc_id = eaas.id and eaas.c_id = eaac.id and m.name = '$BaselineName';" $results = Invoke-SqliteQuery -Query $query -DataSource $database if ($generateExcelYsn) { $tmp = get-date -f yyyyMMddHHmmss $results | Export-Csv -Path $ExportFolder\$tmp"EventList.csv" } else { if ($Script:openFromGui) { $BaselineName = ConvertFrom-PSSQLString($BaselineName) $results | Out-GridView -Title "EventList for: $BaselineName" } else { return $results } } } } } function Get-BaselineNameFromDB { <# .SYNOPSIS Gets all the names of the baselines, stored in the database. .DESCRIPTION Gets all the names of the baselines, stored in the database. .PARAMETER BaselineName Prompts you for the Baseline Name that should be checked against the database. .EXAMPLE Get-BaselineNameFromDB Gets all the names of the baselines, stored in the database. #> [CmdletBinding()] param ( [string]$BaselineName ) if ($BaselineName){ $tmpStr = " where name = '" + (ConvertTo-PSSQLStringArray($BaselineName)) + "'" } $query = "select name from baseline_main" + $tmpStr + ";" $baselineNames = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty name if ($baselineNames) { $baselineNames = ConvertFrom-PSSQLStringArray -Text $baselineNames } return $baselineNames } function Get-GroupPolicyFromMitreTechniques { <# .SYNOPSIS Creates a group policy out of the selected events. .DESCRIPTION Creates a group policy out of the selected events which are mapped to the MITRE ATT&CK Techniques. .PARAMETER Identity Prompts you for the Identity that should be used to generate an Group Policy from. You can either use a baseline name or one or multiple Mitre Technique IDs. .PARAMETER Path Lets you specify the destination output path: where should the GPO be stored? .EXAMPLE Get-GroupPolicyFromMitreTechniques Creates a group policy out of the selected events. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseOutputTypeCorrectly", "")] [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BaselineName', 'TechniqueId')] [string]$Identity, [string]$Path ) process { if ($Path) { $destFolder = $Path } else { if ($Script:openFromGui) { $destFolder = Start-FilePicker -description "Select a directory where the GPO should be saved" } else { write-host "Provide the path where the GPO should be saved: Get-GroupPolicyFromMitreTechniques -Path 'C:\tmp' -Identity 'T1039'" } } if ($destFolder) { $GpoTmpl = "$ModuleRoot\internal\data\GPO\*" if ($Script:openFromGui) { $MitreTechniques = Get-CheckedMitreTechniques } else { if ($identity) { if (Get-BaselineNameFromDB -BaselineName $Identity) { $MitreTechniques = Get-MitreTechniquesFromBaseline -BaselineName $Identity } elseif ($Identity -match "^T\d{4}$") { $MitreTechniques = $("'" + $Identity + "'") } elseif ( ($Identity -match "^['T\d{4}$]") -or ($Identity -match "^T\d{4}$") ) { $MitreTechniques = $Identity } } } $tmp = Get-MitreEvents -MitreTechniques $MitreTechniques -advancedAudit if ($tmp) { $auditCsvString = "Machine Name,Policy Target,Subcategory,Subcategory GUID,Inclusion Setting,Exclusion Setting,Setting Value" foreach ($item in $tmp) { $subcategory_name = $item | Select-Object -ExpandProperty subcategory_name $guid = $item | Select-Object -ExpandProperty guid $sf_sum = $item | Select-Object -ExpandProperty sf_sum switch ($sf_sum) { # if success_failure_id >= 3 it's always s+f / 1 = s / 2 = f 0 { "" } 1 { $sf_string = "Success" $sf_number = $sf_sum } 2 { $sf_string = "Failure" $sf_number = $sf_sum } default { $sf_string = "Success and Failure" $sf_number = 3 } } $auditCsvString = $auditCsvString + "`r`n,System,$subcategory_name,$guid,$sf_string,,$sf_number" } $GPOFolder = $("{$(New-Guid)}").ToUpper() New-Item -ItemType directory -Path "$destFolder\$GPOFolder" Copy-Item "$GpoTmpl" -Destination "$destFolder\$GPOFolder" -Recurse New-Item -ItemType directory -Path "$destFolder\$GPOFolder\Machine\Microsoft\Windows NT\Audit\" New-Item -ItemType directory -Path "$destFolder\$GPOFolder\Machine\Scripts\Shutdown\" New-Item -ItemType directory -Path "$destFolder\$GPOFolder\Machine\Scripts\Startup\" New-Item -ItemType directory -Path "$destFolder\$GPOFolder\User\" Set-Content -Path "$destFolder\$GPOFolder\Machine\Microsoft\Windows NT\Audit\audit.csv" -Value $auditCsvString } } } } function Get-MitreEventList { <# .SYNOPSIS Gets an EventList for the selected MITRE ATT&CK techniques. .DESCRIPTION Gets an EventList for the MITRE ATT&CK techniques which were selected from the checkboxes in the GUI. .PARAMETER Identity Defines which MITRE ATT&CK Techniques or which Microsoft Security Baseline should be used as Input to generate a Mitre EventList. .PARAMETER generateExcelYsn Defines if an Excel document will be generated. When checked, one can define where the document should be stored. .EXAMPLE Get-MitreEventList -generateExcelYsn $true Gets an EventList for the selected MITRE ATT&CK techniques. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BaselineName', 'TechniqueId')] [string] $Identity, [boolean]$generateExcelYsn = $false ) process { if ($Script:openFromGui) { $results = Get-MitreEvents -MitreTechniques $(Get-CheckedMitreTechniques) } else { if ($identity) { if (Get-BaselineNameFromDB -BaselineName $Identity) { $tmpStr = Get-MitreTechniquesFromBaseline -BaselineName $Identity if ($tmpStr) { $results = Get-MitreEvents -MitreTechniques $tmpStr } } elseif ($Identity -match "^T\d{4}$") { $results = Get-MitreEvents -MitreTechniques $("'" + $Identity + "'") } elseif ( ($Identity -match "^['T\d{4}$]") -or ($Identity -match "^T\d{4}$") ) { $results = Get-MitreEvents -MitreTechniques $Identity } } } if (![string]::IsNullOrEmpty($results)) { if ($generateExcelYsn) { $tmp = get-date -f yyyyMMddHHmmss $results | Export-Csv -Path $ExportFolder\$tmp"EventList.csv" } else { if ($Script:openFromGui) { $results | Out-GridView -Title "EventList for: $ComboBox1Value" } else { $results } } } else { $returnStr = "No MITRE ATT&CK techniques were selected." if ($Script:openFromGui) { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup($returnStr, 0, "Done", 0x1) } else { Write-Host $returnStr } } } } function Get-SigmaPath { <# .SYNOPSIS Returns the path to the location where sigmac is located. .DESCRIPTION Returns the path to the location where sigmac is located. The path is configured by the user. .EXAMPLE Get-SigmaPath Returns the path to the location where sigmac is located. #> [CmdletBinding()] [OutputType([String])] param () $query = "select sigma_path from EventList_configuration;" $sigmaPath = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty sigma_path $sigmaPath = $sigmaPath if (!(Test-Path -Path "$sigmaPath\sigmac" -PathType Leaf)) { return "" } else { return "$sigmaPath\sigmac" } } function Get-SigmaQueries { <# .SYNOPSIS Returns the queries for the desired target system. .DESCRIPTION Returns the queries for the desired target system. Either as YAML, sigma command or already converted by sigma. .PARAMETER Identity Prompts you for the Identity that should be used to generate the Sigma queries from. You can either use a baseline name or one or multiple Mitre Technique IDs. .PARAMETER Path Defines where the Output should be stored. .PARAMETER siemName Defines the target SIEM system. Must be supported by Sigma. .PARAMETER yamlOnly If set, the configuration will be generated in YAML only .EXAMPLE Get-SigmaQueries -Path $ExportFolder -siemName $SelectedComboSiemBox Returns the queries for the desired target system. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('TechniqueId', 'BaselineName')] [string]$Identity, [Parameter(Mandatory = $True)] [string]$Path, [Parameter(Mandatory = $True)] [string]$siemName, [switch]$yamlOnly ) process { $query = "select target from sigma_supportedSiem where name = '" + $siemName + "' COLLATE NOCASE;" $target = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty target if ($Script:openFromGui) { $MitreTechniques = Get-CheckedMitreTechniques $MitreAreas = Get-CheckedMitreAreas } else { if ($identity) { if (Get-BaselineNameFromDB -BaselineName $Identity) { $MitreTechniques = Get-MitreTechniquesFromBaseline -BaselineName $Identity } elseif ($Identity -match "^T\d{4}$") { $MitreTechniques = $("'" + $Identity + "'") } elseif ( ($Identity -match "^['T\d{4}$]") -or ($Identity -match "^T\d{4}$") ) { $MitreTechniques = $Identity } } if ($MitreTechniques) { $tmpStr = $tmpStr + " -TechniqueIds $MitreTechniques" } if ($MitreAreas) { $tmpStr = $tmpStr + " -AreaNames $MitreAreas" } } if ($MitreTechniques) { $queryObj = Get-Queries -TechniqueIds $MitreTechniques } elseif ($MitreAreas) { $queryObj = Get-Queries -AreaNames $MitreAreas } elseif (($MitreTechniques) -and ($MitreAreas)) { $queryObj = Get-Queries -TechniqueIds $MitreTechniques -AreaNames $MitreAreas } if ($queryObj) { $tmp = get-date -f yyyyMMddHHmmss $yamlPath = $Path + "\" + $tmp + "_EventList-Queries\yaml\" New-Item -ItemType directory -Path $Path\$tmp"_EventList-Queries" New-Item -ItemType directory -Path $yamlPath foreach ($item in $queryObj) { $addQuery = $false $tmpStr = "" $sigmaLocation = Get-SigmaPath if ($sigmaLocation) { $sigmaIsInstalled = $true } else { $sigmaIsInstalled = $false } $area_name = ConvertFrom-PSSQLString -Text $item.area_name $technique_id = ConvertFrom-PSSQLString -Text $item.technique_id $technique_name = ConvertFrom-PSSQLString -Text $item.technique_name $title = ConvertFrom-PSSQLString -Text $item.title $description = ConvertFrom-PSSQLString -Text $item.description $status = ConvertFrom-PSSQLString -Text $item.status $date = ConvertFrom-PSSQLString -Text $item.date $author = ConvertFrom-PSSQLString -Text $item.author $raw_yaml = ConvertFrom-PSSQLString -Text $item.raw_yaml $level = ConvertFrom-PSSQLString -Text $item.level $filename = ConvertFrom-PSSQLString -Text $item.filename $yamlFile = ".\yaml\" + $filename Set-Content -Path ($yamlPath + $filename) -Value $raw_yaml if ($old_areaName -ne $area_name) { if ($old_areaName) { $tmpStr = $tmpStr + "`r`n" } $tmpStr = $tmpStr + "# " + $area_name + "`r`n" } if ($old_techniqueName -ne $technique_name) { $tmpStr = $tmpStr + "`r`n" $tmpStr = $tmpStr + "## " + $technique_id + " " + $technique_name + "`r`n" } $tmpStr = $tmpStr + "`r`n" $tmpStr = $tmpStr + "### " + $title + "`r`n" if ($sigmaIsInstalled) { "Processing " + $title + "`r`n" >> $Path\$tmp"_EventList-Queries\SigmaLog.txt" } $tmpStr = $tmpStr + "* Author: " + $author + "`r`n" $tmpStr = $tmpStr + "* Date: " + $date + "`r`n" $tmpStr = $tmpStr + "* Query Status: " + $status + "`r`n" $tmpStr = $tmpStr + "* Level: " + $level + "`r`n" $tmpStr = $tmpStr + "*" + $description + "*`r`n" if ($yamlOnly) { $tmpStr = $tmpStr + "#### Yaml:`r`n" $tmpStr = $tmpStr + $raw_yaml $addQuery = $true } else { if ($sigmaIsInstalled) { $sigmaConfigPath = Join-Path -Path $sigmaLocation -ChildPath "..\config\generic\windows-audit.yml" -Resolve $sigmaquery = python.exe $sigmaLocation -t $target ($yamlPath + $filename) -c $sigmaConfigPath 2>>$Path\$tmp"_EventList-Queries\SigmaLog.txt" if ($sigmaquery) { $addQuery = $true } $tmpStr = $tmpStr + " " + $sigmaquery + "`r`n" if ($addQuery) { $scriptStr = $scriptStr + $sigmaquery + "`r`n`r`n" } } else { $tmpStr = $tmpStr + " python.exe tools/sigmac -t $target $yamlFile -c config\generic\windows-audit.yml `r`n" $addQuery = $true $scriptStr = $scriptStr + "python.exe tools/sigmac -t $target $yamlFile -c config\generic\windows-audit.yml `r`n`r`n" } } if ($addQuery) { $outputStr = $outputStr + $tmpStr } $old_areaName = $area_name $old_techniqueName = $technique_name } Set-Content -Path $Path\$tmp"_EventList-Queries\EventList-Queries.md" -Value $outputStr if ($scriptStr) { Set-Content -Path $Path\$tmp"_EventList-Queries\EventList-Queries.txt" -Value $scriptStr } } } } function Get-SigmaSupportedSiemFromDb { <# .SYNOPSIS Returns all SIEM systems which are supported by sigma. .DESCRIPTION Returns all SIEM systems which are supported by sigma. .EXAMPLE Get-SigmaSupportedSiemFromDb Returns all SIEM systems which are supported by sigma. #> [CmdletBinding()] param () $query = "select name from sigma_supportedSiem order by name;" $siemNames = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty name return $siemNames } function Import-BaselineFromFolder { <# .SYNOPSIS Imports one or multiple baselines from a folder into the database. .DESCRIPTION Imports one or multiple baselines from a folder into the database. .PARAMETER Path Path where the baseline(s) is/are located. .EXAMPLE Import-BaselineFromFolder -Path "C:\tmp\" Imports one or multiple baselines from "C:\tmp" into the database. #> [cmdletbinding()] param ( [Parameter(Mandatory = $true)] [string]$Path ) $test = Get-ChildItem -LiteralPath $Path -Filter audit.csv -Recurse -ErrorAction SilentlyContinue -Force | Group-Object path foreach ($item in $test.Group) { if (![string]::IsNullOrEmpty($item.FullName)) { if ($item.Directory -match "GPO") { $gpReportXmlPathStr = $item.Directory -Replace("DomainSysvol\\GPO\\Machine\\microsoft\\windows nt\\Audit", "gpreport.xml") [xml]$xml = Get-Content -Path $gpReportXmlPathStr $auditPolicyNameStr = $xml.GPO.Name Import-BaselineIntoDb -Path $item.FullName -PolicyName $auditPolicyNameStr } } } } function Import-YamlCofigurationFromFolder { <# .SYNOPSIS Imports one or more YAML configuration file(s) into the database. .DESCRIPTION Imports one or more YAML configuration file(s) into the database. YAML configurations can be found in the sigma GitHub repository. .PARAMETER Path Defines the path where the YAML configuration files are located. .PARAMETER Force If set, overwrites queries, that were already imported in the database. .EXAMPLE Import-YamlCofigurationFromFolder -Path "C:\tmp" Imports one or more YAML configuration file(s) from "C:\tmp" into the database. #> [cmdletbinding()] param ( [Parameter(Mandatory = $true)] [string]$Path, [switch]$Force ) $YamlConfigFiles = Get-ChildItem -LiteralPath $Path -Recurse -ErrorAction SilentlyContinue -Force | Group-Object path foreach ($item in $YamlConfigFiles.Group) { if (![string]::IsNullOrEmpty($item.FullName)) { if ($item.Extension -match ".yml") { $rawYaml = get-content -raw $item.FullName $yamlObj = [pscustomobject](convertfrom-yaml $rawYaml) $delQuery = "" $tmpStr = "" $sqlStr = "" $query = "select * from queries_data_yaml_main where title = '" + (ConvertTo-PSSQLString -Text $yamlObj.title) + "';" if ($Force) { $m_id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty "id" if ($m_id -gt 0) { $delQuery = "delete from queries_data_yaml_tags where m_id = '$m_id'; " } $delQuery = $delQuery + "delete from queries_data_yaml_main where title = '" + (ConvertTo-PSSQLString -Text $yamlObj.title) + "';" Invoke-SqliteQuery -Query $delQuery -DataSource $database } if (!(Invoke-SqliteQuery -Query $query -DataSource $database)) { $sqlStr = "insert into queries_data_yaml_main (title, description, status, date, author, raw_yaml, level, filename) values ('" + (ConvertTo-PSSQLString -Text $yamlObj.title) + "', '" + (ConvertTo-PSSQLString -Text $yamlObj.description) + "', '" + (ConvertTo-PSSQLString -Text $yamlObj.status) + "', '" + (ConvertTo-PSSQLString -Text $yamlObj.date) + "', '" + (ConvertTo-PSSQLString -Text $yamlObj.author) + "', '" + (ConvertTo-PSSQLString -Text $rawYaml) + "', '" + (ConvertTo-PSSQLString -Text $yamlObj.level) + "', '" + (ConvertTo-PSSQLString -Text $item.name) + "'); select last_insert_rowid();" $m_id = Invoke-SqliteQuery -Query $sqlStr -DataSource $database | Select-Object -ExpandProperty "last_insert_rowid()" foreach ($item in $yamlObj.tags) { $technique_id = 0 $area_id = 0 $tag_category = ($item.split("."))[0] $tag_name = ($item.split("."))[1] -replace "_", " " if ($tag_category -eq "attack") { if ($tag_name.SubString(0,1) -eq "t") { $query = "SELECT * FROM mitre_techniques WHERE technique_id = '$tag_name' COLLATE NOCASE;" $technique_id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty "id" } else { $query = "SELECT * FROM mitre_areas WHERE area_name = '$tag_name' COLLATE NOCASE;" $area_id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty "id" if (!($technique_id) -or ($technique_id -eq 0)) { $query = "SELECT * FROM mitre_techniques WHERE technique_name = '$tag_name' COLLATE NOCASE;" $technique_id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty "id" } } } if (!$technique_id) { $technique_id = 0 } if (!$area_id) { $area_id = 0 } $tmpStr = "insert into queries_data_yaml_tags (tag_name, m_id, full_tag_name, category, mitre_area_id, mitre_technique_id) values ('$tag_name', '$m_id', '$item', '$tag_category', '$area_id', '$technique_id');" if (![string]::IsNullOrEmpty(($tmpStr))) { Invoke-SqliteQuery -Query $tmpStr -DataSource $database } } } } } } } function Open-EventListGUI { <# .SYNOPSIS Opens the EventList GUI. .DESCRIPTION Opens the EventList GUI. .EXAMPLE Open-EventListGUI Opens the EventList GUI. #> $Script:openFromGui = $true $GuiWidth = 1535 $GuiHeight = 1000 $ButtonWidth = 200 $ButtonHeight = 30 $ButtonXDistance = 215 $ButtonYDistance = 40 $ButtonPanelDistance = 1305 $ComboboxWidth = 420 $x = 10 $y = 20 + 60 Add-Type -AssemblyName System.Windows.Forms [System.Windows.Forms.Application]::EnableVisualStyles() $Form = New-Object system.Windows.Forms.Form $Form.ClientSize = "$GuiWidth,$GuiHeight" $Form.text = "EventList" $Form.TopMost = $false #Panel oben mit Baseline Auswahl $Panel1 = New-Object system.Windows.Forms.Panel $Panel1.height = 50 $Panel1.width = 2000 $Panel1.BackColor = "#9b9b9b" $Panel1.location = New-Object System.Drawing.Point(0,0) #Panel an der Seite mit Buttons $Panel2 = New-Object system.Windows.Forms.Panel $Panel2.height = 2000 $Panel2.width = 235 $Panel2.BackColor = "#9b9b9b" $Panel2.location = New-Object System.Drawing.Point($ButtonPanelDistance,0) Add-MitreCheckboxes $x = $ButtonPanelDistance + 10 $y = 60 $ButtonShowEvts = New-Object system.Windows.Forms.Button $ButtonShowEvts.BackColor = "#d5d8d7" $ButtonShowEvts.text = "Generate Event List" $ButtonShowEvts.width = $ButtonWidth $ButtonShowEvts.height = $ButtonHeight $ButtonShowEvts.location = New-Object System.Drawing.Point($x,$y) $ButtonShowEvts.Font = 'Microsoft Sans Serif,11' $Form.controls.AddRange(@($ButtonShowEvts)) $ButtonShowEvts.Add_Click({ Get-EventListSelect }) $y = $y + $ButtonYDistance $ButtonAgentCfg = New-Object system.Windows.Forms.Button $ButtonAgentCfg.BackColor = "#d5d8d7" $ButtonAgentCfg.text = "Generate Agent Config" $ButtonAgentCfg.width = $ButtonWidth $ButtonAgentCfg.height = $ButtonHeight $ButtonAgentCfg.location = New-Object System.Drawing.Point($x,$y) $ButtonAgentCfg.Font = 'Microsoft Sans Serif,11' $Form.controls.AddRange(@($ButtonAgentCfg)) $ButtonAgentCfg.Add_Click({ Get-AgentConfigSelect }) $y = $y + $ButtonYDistance $ButtonExportQueries = New-Object system.Windows.Forms.Button $ButtonExportQueries.BackColor = "#d5d8d7" $ButtonExportQueries.text = "Generate Queries" $ButtonExportQueries.width = $ButtonWidth $ButtonExportQueries.height = $ButtonHeight $ButtonExportQueries.location = New-Object System.Drawing.Point($x,$y) $ButtonExportQueries.Font = 'Microsoft Sans Serif,11' $Form.controls.AddRange(@($ButtonExportQueries)) $ButtonExportQueries.Add_Click({ Get-QueriesSelect }) $y = $y + $ButtonYDistance $ButtonExportGPO = New-Object system.Windows.Forms.Button $ButtonExportGPO.BackColor = "#d5d8d7" $ButtonExportGPO.text = "Generate GPO" $ButtonExportGPO.width = $ButtonWidth $ButtonExportGPO.height = $ButtonHeight $ButtonExportGPO.location = New-Object System.Drawing.Point($x,$y) $ButtonExportGPO.Font = 'Microsoft Sans Serif,11' $Form.controls.AddRange(@($ButtonExportGPO)) $ButtonExportGPO.Add_Click({ Get-GroupPolicyFromMitreTechniques }) $y = $GuiHeight - 50 $ButtonExit = New-Object system.Windows.Forms.Button $ButtonExit.BackColor = "#C0C0C0" $ButtonExit.text = "Close" $ButtonExit.width = $ButtonWidth $ButtonExit.height = $ButtonHeight $ButtonExit.location = New-Object System.Drawing.Point($x,$y) $ButtonExit.Font = [System.Drawing.Font]::new("Microsoft Sans Serif", 11, [System.Drawing.FontStyle]::Bold) $Form.controls.AddRange(@($ButtonExit)) $ButtonExit.Add_Click({ Close-Form -Form $Form }) $Script:ComboBox1 = New-Object system.Windows.Forms.ComboBox $baselineNames = Get-BaselineNameFromDB if ([string]::IsNullOrEmpty($baselineNames)) { $ComboBox1.text = "No Baselines imported" } else { $ComboBox1.text = "Select Baseline" } $ComboBox1.width = $ComboboxWidth $ComboBox1.height = 40 $x = 20 $y = 10 Get-BaselineNameFromDB | ForEach-Object {[void] $ComboBox1.Items.Add($_)} $ComboBox1.location = New-Object System.Drawing.Point($x,($y+2)) $ComboBox1.Font = 'Microsoft Sans Serif,11' $ComboBox1.Add_SelectedValueChanged({ $Script:ComboBox1Value = $ComboBox1.Text Sync-MitreCheckboxes -BaselineName $ComboBox1Value }) $Form.controls.AddRange(@($ComboBox1)) $x = $x + $ComboboxWidth + 15 $ButtonImportBsl = New-Object system.Windows.Forms.Button $ButtonImportBsl.BackColor = "#d5d8d7" $ButtonImportBsl.text = "Import Baseline(s)" $ButtonImportBsl.width = $ButtonWidth $ButtonImportBsl.height = $ButtonHeight $ButtonImportBsl.location = New-Object System.Drawing.Point($x,$y) $ButtonImportBsl.Font = 'Microsoft Sans Serif,11' $Form.controls.AddRange(@($ButtonImportBsl)) $ButtonImportBsl.Add_Click({ Get-ImportSelect }) $x = $x + $ButtonXDistance $ButtonDelOneBaseline = New-Object system.Windows.Forms.Button $ButtonDelOneBaseline.BackColor = "#d5d8d7" $ButtonDelOneBaseline.text = "Delete baseline(s)" $ButtonDelOneBaseline.width = $ButtonWidth $ButtonDelOneBaseline.height = $ButtonHeight $ButtonDelOneBaseline.location = New-Object System.Drawing.Point($x,$y) $ButtonDelOneBaseline.Font = 'Microsoft Sans Serif,11' $Form.controls.AddRange(@($ButtonDelOneBaseline)) $ButtonDelOneBaseline.Add_Click({ Get-DeleteBaselineSelect }) $x = $x + $ButtonXDistance $ButtonResetCheckboxes = New-Object system.Windows.Forms.Button $ButtonResetCheckboxes.BackColor = "#d5d8d7" $ButtonResetCheckboxes.text = "Reset Checkboxes" $ButtonResetCheckboxes.width = $ButtonWidth $ButtonResetCheckboxes.height = $ButtonHeight $ButtonResetCheckboxes.location = New-Object System.Drawing.Point($x,$y) $ButtonResetCheckboxes.Font = 'Microsoft Sans Serif,11' $Form.controls.AddRange(@($ButtonResetCheckboxes)) $ButtonResetCheckboxes.Add_Click({ Reset-MitreCheckboxes }) $x = $x + $ButtonXDistance $ButtonImportYaml = New-Object system.Windows.Forms.Button $ButtonImportYaml.BackColor = "#d5d8d7" $ButtonImportYaml.text = "YAML Admin" $ButtonImportYaml.width = $ButtonWidth $ButtonImportYaml.height = $ButtonHeight $ButtonImportYaml.location = New-Object System.Drawing.Point($x,$y) $ButtonImportYaml.Font = 'Microsoft Sans Serif,11' $Form.controls.AddRange(@($ButtonImportYaml)) $ButtonImportYaml.Add_Click({ Get-YamlAdminSelect }) $x = $x + $ButtonXDistance $ButtonConfig = New-Object system.Windows.Forms.Button $ButtonConfig.BackColor = "#C0C0C0" $ButtonConfig.text = "Configure EventList" $ButtonConfig.width = $ButtonWidth $ButtonConfig.height = $ButtonHeight $ButtonConfig.location = New-Object System.Drawing.Point($x,$y) $ButtonConfig.Font = [System.Drawing.Font]::new("Microsoft Sans Serif", 11, [System.Drawing.FontStyle]::Bold) $Form.controls.AddRange(@($ButtonConfig)) $ButtonConfig.Add_Click({ Get-EventListConfigSelect }) Sync-ComboBox -ComboBox $ComboBox1 -Items $baselineNames $Form.controls.AddRange(@($Panel1,$Panel2)) [void]$Form.ShowDialog() } function Remove-AllBaselines { <# .SYNOPSIS Deletes all imported baselines from the database. .DESCRIPTION Deletes all imported baselines from the database. .PARAMETER Confirm Prompts you for confirmation before executing the command. .PARAMETER WhatIf Displays a message that describes the effect of the command, instead of executing the command. .EXAMPLE Remove-AllBaselines Deletes all imported baselines from the database. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding(SupportsShouldProcess)] param () $Query = "delete from baseline_data; delete from baseline_main;" Invoke-SqliteQuery -Query $Query -DataSource $Database $returnStr = "All baselines were successfully deleted." if ($Script:openFromGui) { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup($returnStr,0,"Done",0x1) } } function Remove-AllYamlConfigurations { <# .SYNOPSIS Deletes all imported YAML configuration files from the database. .DESCRIPTION Deletes all imported YAML configuration files from the database. .PARAMETER Confirm Prompts you for confirmation before executing the command. .PARAMETER WhatIf Displays a message that describes the effect of the command, instead of executing the command. .EXAMPLE Remove-AllYamlConfigurations Deletes all imported YAML configuration files from the database. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding(SupportsShouldProcess)] param () $Query = "delete from queries_data_yaml_main; delete from queries_data_yaml_tags;" Invoke-SqliteQuery -Query $Query -DataSource $Database if ($Script:openFromGui) { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup("All YAML configurations were successfully deleted.",0,"Done",0x1) } } function Remove-EventListConfiguration { <# .SYNOPSIS Deletes all existent EventList configurations from the database. .DESCRIPTION Deletes all existent EventList configurations from the database. .PARAMETER sigmaPath Defines the path where sigmac is located. .PARAMETER Confirm Prompts you for confirmation before executing the command. .PARAMETER WhatIf Displays a message that describes the effect of the command, instead of executing the command. .EXAMPLE Remove-EventListConfiguration -sigmaPath Deletes all existent EventList configurations from the database. #> [CmdletBinding(SupportsShouldProcess)] param( [switch]$sigmaPath ) if ($sigmaPath) { $query = "Update EventList_configuration set sigma_path='' where id=1;" } if ($query) { Invoke-SqliteQuery -Query $query -DataSource $database } } function Remove-OneBaseline { <# .SYNOPSIS Removes one imported baseline from the database. .DESCRIPTION Removes one imported baseline from the database. .PARAMETER BaselineName Defines the name of the baseline. .PARAMETER Confirm Prompts you for confirmation before executing the command. .PARAMETER WhatIf Displays a message that describes the effect of the command, instead of executing the command. .EXAMPLE Remove-OneBaseline -BaselineName "SCM Windows 10 - Computer" Removes one imported baseline from the database. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] [CmdletBinding(SupportsShouldProcess)] Param ( [Parameter(Mandatory = $True, ValueFromPipeline = $True)] [string]$BaselineName ) process { $valuesFromDb = Get-BaselineNameFromDB if (($BaselineName -eq "No Baselines imported") -or ($BaselineName -eq "Select Baseline") -or [string]::IsNullOrEmpty($BaselineName)) { $returnStr = "No Baseline was selected." if ($Script:openFromGui) { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup($returnStr, 0, "Delete selected baseline", 0x1) } Write-Host $returnStr } else { If ($BaselineName -in $valuesFromDb) { $query = "select id from baseline_main where name like '$BaselineName' ;" $id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty id $query = "delete from baseline_data where b_id = $id ; delete from baseline_main where id = $id ;" Invoke-SqliteQuery -Query $query -DataSource $database $returnStr = "Baseline $BaselineName was deleted successfully." if ($Script:openFromGui) { $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup($returnStr, 0, "Delete selected baseline", 0x1) } } } } } |