From d5f93acfd0f914902190cba1051e6c45e912212e Mon Sep 17 00:00:00 2001 From: bk-cs <54042976+bk-cs@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:47:00 -0800 Subject: [PATCH] v2.1.7 Removed 'Library' commands, due to the release of support for 'Custom Scripts' in Falcon Fusion workflows. The existing library scripts are going to be re-formatted to be compatible with workflows, so that saving the scripts in your local Falcon instance will be used as the delivery mechanism, instead of requiring PSFalcon for it to work. --- PSFalcon.psd1 | 41 +++------- Private/Private.ps1 | 90 --------------------- Public/psf-humio.ps1 | 2 +- Public/psf-library.ps1 | 176 ----------------------------------------- 4 files changed, 14 insertions(+), 295 deletions(-) delete mode 100644 Public/psf-library.ps1 diff --git a/PSFalcon.psd1 b/PSFalcon.psd1 index 6651599f..d130cf9f 100644 --- a/PSFalcon.psd1 +++ b/PSFalcon.psd1 @@ -270,10 +270,6 @@ 'Show-FalconEventCollector', 'Unregister-FalconEventCollector', - # psf-library.ps1 - 'Get-FalconLibrary', - 'Invoke-FalconLibrary', - # psf-output.ps1 'Export-FalconReport', 'Send-FalconWebhook', @@ -442,31 +438,20 @@ 'Show-FalconEventCollector' 'Unregister-FalconEventCollector' - * psf-library.ps1 - 'Get-FalconLibrary' - 'Invoke-FalconLibrary' - New Functionality - * Created a GitHub-based Real-time Response library (https://github.com/bk-cs/rtr). The list of available - scripts can be retrieved using 'Get-FalconLibrary'. Including a specific script name will output basic help - information about the script. Scripts can be run on one or more devices using 'Invoke-FalconLibrary'. - - * Added the ability to cache a Humio Event Collector (using the relevant 'humio-structured' endpoint) to send - PSFalcon content to a Humio instance. A specific parser is not required because the content sent by PSFalcon - uses the documented Humio event structure. - - * 'Register-FalconEventCollector' is used to define your Humio Event Collector, ingest token and the events - to log, 'Show-FalconEventCollector' can be used for confirmation, and 'Remove-FalconEventCollector' can - be used to disable logging. - - * The 'Enable' parameter for 'Register-FalconEventCollector' defines the data that will be sent to Humio. Using - 'requests' sends the full content of PSFalcon requests, 'responses' sends API responses, and 'library' sends - results from a Real-time Response library script directly from the host(s) to Humio, with #cid, #aid, #host - and #script tags appended. - - * Added 'Send-FalconEvent' to use the results of a PSFalcon command to create Humio events. This allows - PSFalcon to work as a mechanism to ingest data from the CrowdStrike APIs directly into Humio on demand and does - not require a specific 'Enable' value under 'Register-FalconEventCollector'. + * Added the ability to PSFalcon content to a Humio instance. A specific parser is not required because the + content sent by PSFalcon uses the documented Humio event structure. + + * 'Register-FalconEventCollector' is used to define your Humio cloud, ingest token and the events to log, + 'Show-FalconEventCollector' can be used for confirmation, and 'Remove-FalconEventCollector' can be used to + disable logging. + + * The 'Enable' parameter for 'Register-FalconEventCollector' defines the data that will be sent to Humio. The + value 'requests' sends PSFalcon requests while 'responses' sends API responses. + + * Added 'Send-FalconEvent' to generate Humio events using the output of a PSFalcon command. This allows + PSFalcon to work as a mechanism to ingest data from the CrowdStrike APIs directly into Humio and does not + require a specific 'Enable' value under 'Register-FalconEventCollector'. Command Changes * Added 'group_names' as an 'Include' option for 'Get-FalconHost'. Requires 'host-group:read' permission. diff --git a/Private/Private.ps1 b/Private/Private.ps1 index c2e6e78c..7688eecd 100644 --- a/Private/Private.ps1 +++ b/Private/Private.ps1 @@ -301,96 +301,6 @@ function Convert-Rfc3339 { (Get-Date).AddHours($Hours),[Xml.XmlDateTimeSerializationMode]::Utc) -replace '\.\d+Z$','Z')" } } -function Get-LibraryScript { - [CmdletBinding()] - [OutputType([string])] - param( - [Parameter(Mandatory = $true, Position = 1)] - [string] $Name, - - [Parameter(Mandatory = $true, Position = 2)] - [string] $Platform - ) - begin { - $Authorization = if ($Script:Falcon.Api.Client.DefaultRequestHeaders.Authorization) { - # Capture current bearer token, then remove it before request to library - $Script:Falcon.Api.Client.DefaultRequestHeaders.Authorization.ToString() - [void] $Script:Falcon.Api.Client.DefaultRequestHeaders.Remove('Authorization') - } - $SHumio = @{ - # 'shumio' function for sending data to Humio - Linux = $null - Mac = $null - Windows = 'function shumio($O,$C,$A){$B=$O|%{$I=@{};$_.PSObject.Properties|%{$I[$_.Name]=$_.Value};@' + - '{timestamp=(Get-Date -Format o);attributes=$I}};$Req=@{Uri=null;Method="post";Headers=@{Authori' + - 'zation=null;ContentType="application/json"};Body=ConvertTo-Json @(@{tags=@{cid=$C;aid=$A;script' + - '=null};events=@($B)}) -Depth 8 -Compress};[void](iwr @Req -UseBasicParsing)}' - } - $Handling = @{ - # Content for handling output after script - Linux = $null - Mac = $null - Windows = 'function anp($O,$N,$V){$O|%{$_.PSObject.Properties.Add((New-Object PSNoteProperty($N,$V))' + - ')}}if(!$Obj){$Obj=@{error=null}};$R="HKEY_LOCAL_MACHINE\SYSTEM\CrowdStrike\{9b03c1d9-3138-44ed-' + - '9fae-d9f4c034b88d}\{16e0423f-7058-48c9-a204-725362b67639}\Default";if(Test-Path "REGISTRY::\$R"' + - '){$K=reg query "$R";$C=(($K -match "CU") -split "REG_BINARY")[-1].Trim().ToLower();$A=(($K -mat' + - 'ch "AG") -split "REG_BINARY")[-1].Trim().ToLower()};if (gcm shumio -EA 0){shumio $Obj $C $A};@(' + - '@("cid",$C),@("aid",$A)).foreach{anp $Obj $_[0] $_[1]};$Obj|ConvertTo-Json -Compress' - } - } - process { - if ($PSBoundParameters.Name -notmatch '\.(sh|ps1)$') { - # Set file extension, when not provided - $Extension = switch -Regex ($PSBoundParameters.Platform) { - '^(Linux|Mac)$' { 'sh' } - '^Windows$' { 'ps1' } - } - $PSBoundParameters.Name = @($PSBoundParameters.Name, $Extension) -join '.' - } - $FileString = "$(@($PSBoundParameters.Platform, $PSBoundParameters.Name) -join '/')" - if ($FileString) { - try { - # Make request and output result - $Request = $Script:Falcon.Api.Invoke(@{ - Path = "https://raw.githubusercontent.com/bk-cs/library/main/$FileString" - Method = 'get' - Headers = @{ Accept = 'text/plain' } - }) - if ($Request.Result.EnsureSuccessStatusCode() -and $Request.Result.Content) { - $Result = Write-Result -Request $Request - if ($Result -and $PSBoundParameters.Platform -eq 'Windows') { - $Output = if ($Result -match '\$Obj\s?=\s?Start-Process') { - '$Obj|ConvertTo-Json -Compress' - } else { - $Handling.($PSBoundParameters.Platform).Replace('error=null', - ('error="no_' + (($PSBoundParameters.Name).Split('_',2)[-1] -replace '\.ps1', - $null) + '"')) | ForEach-Object { - if ($Script:Falcon.Api.Collector -and - $Script:Falcon.Api.Collector.Enable -contains 'library') { - @($SHumio.($PSBoundParameters.Platform).Replace('Uri=null',"Uri=`"$( - $Script:Falcon.Api.Collector.Uri)`"").Replace('Authorization=null', - "Authorization=`"Bearer $($Script:Falcon.Api.Collector.Token)`"").Replace( - 'script=null',"script=`"$($PSBoundParameters.Name)`""),$_) -join ';' - } else { - $_ - } - } - } - @($Result,$Output) -join "`n" - } else { - $Result - } - } - } catch {} - } - } - end { - if ($Authorization) { - # Re-add existing bearer token - $Script:Falcon.Api.Client.DefaultRequestHeaders.Add('Authorization',$Authorization) - } - } -} function Get-ParamSet { [CmdletBinding()] param( diff --git a/Public/psf-humio.ps1 b/Public/psf-humio.ps1 index 2d7263a4..65872dba 100644 --- a/Public/psf-humio.ps1 +++ b/Public/psf-humio.ps1 @@ -11,7 +11,7 @@ function Register-FalconEventCollector { [string] $Token, [Parameter(ValueFromPipeLineByPropertyName = $true, Position = 3)] - [ValidateSet('library','responses','requests')] + [ValidateSet('responses','requests')] [array] $Enable ) process { diff --git a/Public/psf-library.ps1 b/Public/psf-library.ps1 deleted file mode 100644 index e7575484..00000000 --- a/Public/psf-library.ps1 +++ /dev/null @@ -1,176 +0,0 @@ -function Get-FalconLibrary { - [CmdletBinding()] - param( - [Parameter(Position = 1)] - [string] $Name - ) - begin { - $CurrentProgress = $ProgressPreference - $ProgressPreference = 'SilentlyContinue' - } - process { - $Output = if ($PSBoundParameters.Name) { - if ($PSBoundParameters.Name -match '\.(sh|ps1)$') { - $PSBoundParameters.Name = $PSBoundParameters.Name -replace '\.(sh|ps1)$','.md' - } elseif ($PSBoundParameters.Name -notmatch '\.(sh|ps1)$') { - $PSBoundParameters.Name += '.md' - } - try { - (Invoke-WebRequest -Uri "https://raw.githubusercontent.com/bk-cs/library/main/help/$( - $PSBoundParameters.Name.ToLower())" -UseBasicParsing).Content - } catch {} - } else { - (@('mac','linux','windows').foreach{ - try { - ((Invoke-WebRequest -Uri "https://github.com/bk-cs/library/tree/main/$_" -UseBasicParsing - ).Links | Where-Object { $_.title -match '\.(sh|ps1)$' }).Title -replace '\.(ps1|sh)$',$null - } catch {} - }) | Sort-Object -Unique - } - if ($Output) { - $Output - } elseif ($PSBoundParameters.Name) { - Write-Error "No help file available for '$($PSBoundParameters.Name.ToLower() -replace '\.md',$null)'." - } else { - Write-Error "Unable to retrieve script list for '$($PSBoundParameters.Platform.ToLower())'." - } - } - end { - $ProgressPreference = $CurrentProgress - } -} -function Invoke-FalconLibrary { - [CmdletBinding(DefaultParameterSetName = 'HostId')] - param( - [Parameter(ParameterSetName = 'HostId', Mandatory = $true, Position = 1)] - [Parameter(ParameterSetName = 'HostIds', Mandatory = $true, Position = 1)] - [string] $Name, - - [Parameter(ParameterSetName = 'HostId', Position = 2)] - [Parameter(ParameterSetName = 'HostIds', Position = 2)] - [string] $Arguments, - - [Parameter(ParameterSetName = 'HostIds', Position = 3)] - [ValidateRange(30,600)] - [int] $Timeout, - - [Parameter(ParameterSetName = 'HostId')] - [Parameter(ParameterSetName = 'HostIds')] - [boolean] $QueueOffline, - - [Parameter(ParameterSetName = 'HostId', Mandatory = $true, ValueFromPipeline = $true)] - [ValidatePattern('^\w{32}$')] - [Alias('device_id')] - [string] $HostId, - - [Parameter(ParameterSetName = 'HostIds', Mandatory = $true)] - [ValidatePattern('^\w{32}$')] - [array] $HostIds - ) - begin { - if ($PSBoundParameters.Timeout -and $PSBoundParameters.Arguments -notmatch '-Timeout=\d+') { - $PSBoundParameters.Arguments += " -Timeout=$($PSBoundParameters.Timeout)" - } - $PSBoundParameters.Name = $PSBoundParameters.Name.ToLower() - } - process { - try { - if ($PSCmdlet.ParameterSetName -eq 'HostId') { - $HostInfo = Get-FalconHost -Ids $PSBoundParameters.HostId | Select-Object device_id, platform_name - if (-not($HostInfo.device_id -and $HostInfo.platform_name)) { - throw "No host found matching '$($PSBoundParameters.HostId)'." - } - if ($HostInfo.platform_name -ne 'Windows' -and $Script:Falcon.Api.Collector.Enable -contains - 'library') { - Write-Warning "Unable to send '$($HostInfo.platform_name.ToLower())' script output to Humio." - } - $Script = @{ - Platform = $HostInfo.platform_name.ToLower() - Name = $PSBoundParameters.Name - } - $RawScript = Get-LibraryScript @Script - if (-not $RawScript) { - throw "No script matching '$($Script.Name)' for '$($Script.Platform)'." - } - $InvokeParam = @{ - HostId = $HostInfo.device_id - Command = 'runscript' - Arguments = '-Raw=```' + $RawScript + '```' - } - if ($PSBoundParameters.Arguments) { - $InvokeParam.Arguments += " $($PSBoundParameters.Arguments)" - } - if ($PSBoundParameters.QueueOffline) { - $InvokeParam['QueueOffline'] = $PSBoundParameters.QueueOffline - } - foreach ($Result in (Invoke-FalconRtr @InvokeParam)) { - if ($Result.stdout) { - $Result.stdout = try { - @($Result.stdout -split '\n').foreach{ - if (-not [string]::IsNullOrEmpty($_)) { - $_ | ConvertFrom-Json - } - } - } catch { - $Result.stdout - } - } - $Result - } - } else { - $HostInfo = Get-FalconHost -Ids $PSBoundParameters.HostIds | Select-Object device_id, platform_name - if (-not($HostInfo.device_id -and $HostInfo.platform_name)) { - throw "No host(s) found matching $( - (@($PSBoundParameters.HostIds).foreach{ "'$_'" }) -join ', ')." - } - foreach ($Platform in ($HostInfo.platform_name | Group-Object).Name.ToLower()) { - if ($Platform -ne 'Windows' -and $Script:Falcon.Api.Collector.Enable -contains - 'library') { - Write-Warning "Unable to send '$Platform' script output to Humio." - } - $Script = @{ - Platform = $Platform - Name = $PSBoundParameters.Name - } - $RawScript = Get-LibraryScript @Script - if ($RawScript) { - $InvokeParam = @{ - Command = 'runscript' - Arguments = '-Raw=```' + $RawScript + '```' - HostIds = ($HostInfo | Where-Object { $_.platform_name -eq $Platform }).device_id - } - if ($PSBoundParameters.Arguments) { - $InvokeParam.Arguments += " $($PSBoundParameters.Arguments)" - } - @('Timeout','QueueOffline').foreach{ - if ($PSBoundParameters.Keys -contains $_) { - $InvokeParam[$_] = $PSBoundParameters.$_ - } - } - foreach ($Result in (Invoke-FalconRtr @InvokeParam)) { - if ($Result.stdout) { - $Result.stdout = try { - @($Result.stdout -split '\n').foreach{ - if (-not [string]::IsNullOrEmpty($_)) { - $_ | ConvertFrom-Json - } - } - } catch { - $Result.stdout - } - } - $Result - } - } else { - Write-Error "No script matching '$($Script.Name)' for '$($Script.Platform)'." - } - } - } - } catch { - throw $_ - } - } -} -@('Get-FalconLibrary', 'Invoke-FalconLibrary').foreach{ - Register-ArgumentCompleter -CommandName $_ -ParameterName Name -ScriptBlock { Get-FalconLibrary } -} \ No newline at end of file