Public/malquery.ps1
function Get-FalconMalQuery { <# .SYNOPSIS Verify the status and results of an asynchronous Falcon MalQuery request, such as a hunt or exact-search .DESCRIPTION Requires 'MalQuery: Read'. .PARAMETER Id Request identifier .LINK https://github.com/crowdstrike/psfalcon/wiki/Get-FalconMalQuery #> [CmdletBinding(DefaultParameterSetName='/malquery/entities/requests/v1:get',SupportsShouldProcess)] param( [Parameter(ParameterSetName='/malquery/entities/requests/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')] [Alias('Ids')] [string]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name Endpoint = $PSCmdlet.ParameterSetName Format = @{ Query = @('ids') } } } process { Invoke-Falcon @Param -Inputs $PSBoundParameters } } function Get-FalconMalQueryQuota { <# .SYNOPSIS Retrieve Falcon MalQuery search and download quotas .DESCRIPTION Requires 'MalQuery: Read'. .LINK https://github.com/crowdstrike/psfalcon/wiki/Get-FalconMalQueryQuota #> [CmdletBinding(DefaultParameterSetName='/malquery/aggregates/quotas/v1:get',SupportsShouldProcess)] param() process { $Request = Invoke-Falcon -Endpoint $PSCmdlet.ParameterSetName -RawOutput -EA 0 if ($Request.Result.Content) { (ConvertFrom-Json ($Request.Result.Content).ReadAsStringAsync().Result).meta } elseif ($Request) { throw "Unable to retrieve MalQuery quota. Check client permissions." } } } function Get-FalconMalQuerySample { <# .SYNOPSIS Retrieve Falcon MalQuery indexed file metadata .DESCRIPTION Requires 'MalQuery: Read'. .PARAMETER Id Sha256 hash value .LINK https://github.com/crowdstrike/psfalcon/wiki/Get-FalconMalQuerySample #> [CmdletBinding(DefaultParameterSetName='/malquery/entities/metadata/v1:get',SupportsShouldProcess)] param( [Parameter(ParameterSetName='/malquery/entities/metadata/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline,Position=1)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] [Alias('Ids')] [string[]]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name Endpoint = $PSCmdlet.ParameterSetName Format = @{ Query = @('ids') } } [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) Invoke-Falcon @Param -Inputs $PSBoundParameters } } } function Group-FalconMalQuerySample { <# .SYNOPSIS Schedule MalQuery samples for download .DESCRIPTION Requires 'MalQuery: Write'. .PARAMETER Id Sha256 hash value .LINK https://github.com/crowdstrike/psfalcon/wiki/Group-FalconMalQuerySample #> [CmdletBinding(DefaultParameterSetName='/malquery/entities/samples-multidownload/v1:post', SupportsShouldProcess)] param( [Parameter(ParameterSetName='/malquery/entities/samples-multidownload/v1:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] [Alias('samples','sample','ids')] [string[]]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name Endpoint = $PSCmdlet.ParameterSetName Format = @{ Body = @{ root = @('samples') }} } [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) Invoke-Falcon @Param -Inputs $PSBoundParameters } } } function Invoke-FalconMalQuery { <# .SYNOPSIS Initiate a Falcon MalQuery YARA hunt, exact search or fuzzy search .DESCRIPTION Requires 'MalQuery: Write'. .PARAMETER YaraRule Schedule a YARA-based search .PARAMETER Type Search pattern type .PARAMETER Value Search pattern value .PARAMETER FilterFiletype File type to include with the result .PARAMETER FilterMeta Subset of metadata fields to include in the result .PARAMETER MinSize Minimum file size specified in bytes or multiples of KB/MB/GB .PARAMETER MaxSize Maximum file size specified in bytes or multiples of KB/MB/GB .PARAMETER MinDate Limit results to files first seen after this date .PARAMETER MaxDate Limit results to files first seen before this date .PARAMETER Limit Maximum number of results per request .PARAMETER Fuzzy Search MalQuery quickly but with more potential for false positives .LINK https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconMalQuery #> [CmdletBinding(DefaultParameterSetName='/malquery/queries/exact-search/v1:post',SupportsShouldProcess)] param( [Parameter(ParameterSetName='/malquery/queries/hunt/v1:post',Mandatory,Position=1)] [Alias('yara_rule')] [string]$YaraRule, [Parameter(ParameterSetName='/malquery/queries/exact-search/v1:post',Mandatory,Position=1)] [Parameter(ParameterSetName='/malquery/combined/fuzzy-search/v1:post',Mandatory,Position=1)] [ValidateSet('hex','ascii','wide',IgnoreCase=$false)] [string]$Type, [Parameter(ParameterSetName='/malquery/queries/exact-search/v1:post',Mandatory,Position=2)] [Parameter(ParameterSetName='/malquery/combined/fuzzy-search/v1:post',Mandatory,Position=2)] [string]$Value, [Parameter(ParameterSetName='/malquery/queries/hunt/v1:post',Position=2)] [Parameter(ParameterSetName='/malquery/queries/exact-search/v1:post',Position=3)] [ValidateSet('cdf','cdfv2','cjava','dalvik','doc','docx','elf32','elf64','email','html','hwp', 'java.arc','lnk','macho','pcap','pdf','pe32','pe64','perl','ppt','pptx','python','pythonc', 'rtf','swf','text','xls','xlsx',IgnoreCase=$false)] [Alias('filter_filetypes','FilterFileTypes')] [string[]]$FilterFiletype, [Parameter(ParameterSetName='/malquery/queries/hunt/v1:post',Position=3)] [Parameter(ParameterSetName='/malquery/queries/exact-search/v1:post',Position=4)] [Parameter(ParameterSetName='/malquery/combined/fuzzy-search/v1:post',Position=3)] [ValidateSet('sha256','md5','type','size','first_seen','label','family',IgnoreCase=$false)] [Alias('filter_meta')] [string[]]$FilterMeta, [Parameter(ParameterSetName='/malquery/queries/hunt/v1:post',Position=4)] [Parameter(ParameterSetName='/malquery/queries/exact-search/v1:post',Position=5)] [Alias('min_size')] [string]$MinSize, [Parameter(ParameterSetName='/malquery/queries/hunt/v1:post',Position=5)] [Parameter(ParameterSetName='/malquery/queries/exact-search/v1:post',Position=6)] [Alias('max_size')] [string]$MaxSize, [Parameter(ParameterSetName='/malquery/queries/hunt/v1:post',Position=6)] [Parameter(ParameterSetName='/malquery/queries/exact-search/v1:post',Position=7)] [ValidatePattern('^\d{4}/\d{2}/\d{2}$')] [Alias('min_date')] [string]$MinDate, [Parameter(ParameterSetName='/malquery/queries/hunt/v1:post',Position=7)] [Parameter(ParameterSetName='/malquery/queries/exact-search/v1:post',Position=8)] [ValidatePattern('^\d{4}/\d{2}/\d{2}$')] [Alias('max_date')] [string]$MaxDate, [Parameter(ParameterSetName='/malquery/queries/hunt/v1:post',Position=8)] [Parameter(ParameterSetName='/malquery/queries/exact-search/v1:post',Position=9)] [Parameter(ParameterSetName='/malquery/combined/fuzzy-search/v1:post',Position=4)] [int32]$Limit, [Parameter(ParameterSetName='/malquery/combined/fuzzy-search/v1:post',Mandatory)] [switch]$Fuzzy ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name Endpoint = $PSCmdlet.ParameterSetName Format = @{ Body = @{ root = @('yara_rule','options') patterns = @('type','value') } } } $Aliases = (Get-Command $MyInvocation.MyCommand.Name).Parameters.GetEnumerator().Where({ $_.Value.Attributes.ParameterSetName -eq $PSCmdlet.ParameterSetName }) $Options = @{} foreach ($Opt in @('FilterFiletype','FilterMeta','Limit','MaxDate','MaxSize','MinDate','MinSize')) { if ($PSBoundParameters.$Opt) { $Alias = $Aliases.Where({ $_.Key -eq $Opt }).Value.Aliases[0] $Key = if ($Alias) { $Alias } else { $Opt.ToLower() } $Options[$Key] = $PSBoundParameters.$Opt [void]$PSBoundParameters.Remove($Opt) } } if ($Options) { $PSBoundParameters['options'] = $Options } } process { Invoke-Falcon @Param -Inputs $PSBoundParameters } } function Receive-FalconMalQuerySample { <# .SYNOPSIS Download a sample or sample archive from Falcon MalQuery [password: 'infected'] .DESCRIPTION Requires 'MalQuery: Read'. .PARAMETER Path Destination path .PARAMETER Id Sha256 hash value or MalQuery sample archive identifier .PARAMETER Force Overwrite an existing file when present .LINK https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconMalQuerySample #> [CmdletBinding(DefaultParameterSetName='/malquery/entities/download-files/v1:get',SupportsShouldProcess)] param( [Parameter(ParameterSetName='/malquery/entities/download-files/v1:get',Mandatory,Position=1)] [string]$Path, [Parameter(ParameterSetName='/malquery/entities/download-files/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^([A-Fa-f0-9]{64}|\w{8}-\w{4}-\w{4}-\w{4}-\w{12})$')] [Alias('Ids')] [string]$Id, [Parameter(ParameterSetName='/malquery/entities/download-files/v1:get')] [switch]$Force ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name Endpoint = if ($PSBoundParameters.Id -match '^[A-Fa-f0-9]{64}$') { '/malquery/entities/download-files/v1:get' } else { '/malquery/entities/samples-fetch/v1:get' } Headers = if ($PSBoundParameters.Id -match '^[A-Fa-f0-9]{64}$') { @{ Accept = 'application/octet-stream' } } else { @{ Accept = 'application/zip' } } Format = @{ Query = @('ids') } } } process { if ($Param.Headers.Accept -match 'zip$') { $PSBoundParameters.Path = Assert-Extension $PSBoundParameters.Path 'zip' } $OutPath = Test-OutFile $PSBoundParameters.Path if ($OutPath.Category -eq 'ObjectNotFound') { Write-Error @OutPath } elseif ($PSBoundParameters.Path) { if ($OutPath.Category -eq 'WriteError' -and !$Force) { Write-Error @OutPath } else { Invoke-Falcon @Param -Inputs $PSBoundParameters } } } } function Search-FalconMalQueryHash { <# .SYNOPSIS Perform a simple Falcon MalQuery YARA Hunt for a Sha256 hash .DESCRIPTION Performs a YARA Hunt for the given hash, then checks every 5 seconds--for up to 60 seconds--for a result. Requires 'MalQuery: Write'. .PARAMETER Sha256 Sha256 hash value .LINK https://github.com/crowdstrike/psfalcon/wiki/Search-FalconMalQueryHash #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] [string]$Sha256 ) process { try { $Param = @{ YaraRule = 'import "hash" rule SearchHash { condition: hash.sha256(0,filesize) == "' + $PSBoundParameters.Sha256 + '" }' FilterMeta = @('sha256','type','label','family') } $Request = Invoke-FalconMalQuery @Param if ($Request.reqid) { $Result = Get-FalconMalQuery -Id $Request.reqid if ($Result.status -eq 'inprogress') { do { Start-Sleep -Seconds 5 $i += 5 $Result = Get-FalconMalQuery -Id $Request.reqid } until ( ($Result.status -ne 'inprogress') -or ($i -ge 60) ) } $Result } } catch { $_ } } } |