Worklet - Crowdstrike Containment, Disable Cache Logon, Clear Kerberose, Logon Banners

  • 21 January 2022
  • 1 reply
  • 642 views

Userlevel 5
Badge +1

This worklet Accomplishes a few tasks

  • ONE > Network contain device using CrowdStrike API
  • TWO > Disable Cached Credential Logon and logoff current user
  • THREE> Clear all Kerberos tickets
  • FOUR > Set Logon Banners

 

The biggest challenge with this Worklet is that once the host is network contained, there will be NO response for Automox to receive in the Activity Log because the system will at this point ONLY communicate with CrowdStrike. Highly recommend validating in CrowdStrike post this worklet.

 

STEP ONE > Network contain device using CrowdStrike API

1. Log into https://falcon.crowdstrike.com/support/api-clients-and-keys and generate a Client ID and Token scoped with both read and write for Hosts

2. Use steps from the following article linked below to create three files with these names:

  • id.key - is the Client ID created when following step 1
  • pass.key - is the Secret created when following step 1 which only is visible when creating the API token. This can be re-generated in Crowdstrike as needed.
  • key.txt - contains they key file (my preference is to use a certificate on the machine already)
$Key = (Get-ChildItem Cert:\LocalMachine\Root\<<thumbprint-of-script-in-root-store>>).RawData[0..31]

Article on how to create these files:

3. Insert the following code in the # Remediation section of the code. (Pay attention to what method you are choosing to use for the $key)

Function Get-Token{
[CmdletBinding()]
$creds = @{
client_id = $client_id
client_secret = $client_secret}
$response = Invoke-RestMethod "$application/oauth2/token" -Method Post -Body $creds
$token = $response.access_token
return $token
}
Function Get-Secret ($file,$keyfile){
############# PICK ONLY ONE OF THESE LINE ITEMS ###################
$key = Get-Content $keyfile
$Key = (Get-ChildItem Cert:\LocalMachine\Root\<<thumbprint-of-Certificate>>).RawData[0..31]
###################################################################
$ans = (Get-Content $file | ConvertTo-SecureString -Key $key)
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ans)
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
}

$target_host = $env:COMPUTERNAME
$application = 'https://api.crowdstrike.com'
###### IF YOU USE A KEY FILE ADD -keyfile filename to the end of both commands
$client_id = Get-Secret -file id.key
$client_secret = Get-Secret -file pass.key
$token=Get-Token

Function Get-CSaid {
$Header =@{Authorization='Bearer '+$token}
$uri = "$application/devices/queries/devices/v1?filter=hostname:`'$target_host`'"
$response = Invoke-RestMethod $uri -Method Get -Headers $Header
$aid= $response.resources
return $aid
}

$aids=Get-Csaid

Function Push-CSContain{
foreach ($aid in $aids){
$headers = @{
"accept" = "application/json"
"authorization" = "Bearer $token"}
$request = [System.UriBuilder] "$application/devices/entities/devices-actions/v2"
$params = [System.Web.HttpUtility]::ParseQueryString([String]::Empty)
$params['action_name'] = 'contain'
$request.Query = $params.ToString()
$uri = "$application/devices/entities/devices/v1?ids=$aid"
$body = '{"ids": ["'+$aid+'"]}'
$resp = ( Invoke-WebRequest -Uri $request.Uri -Method "POST" -Headers $headers -ContentType "application/json" -Body $body -ErrorAction SilentlyContinue) | ConvertFrom-Json
Start-Sleep -Seconds 5
$response = ( Invoke-WebRequest -Uri $uri -Method "Get" -Headers $headers -ContentType "application/json" -ErrorAction SilentlyContinue) | ConvertFrom-Json
}
Return $response
}
$response = Push-CSContain
Write-Output "Status of containment for host $target_host`: $($response.resources.status). "

 

STEP TWO > Disable Cached Credential Logon and log current user off

 

Insert this code that will disable the cache

$scriptBlock = {
# Require domain controller to log in
Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\" -Name CachedLogonsCount -Value 0

# Remote Logoff
$user = (quser | select -Skip 1 | foreach { ($_ -split " ")[0] }).replace(">","")
$userid = quser | select -Skip 1 | foreach { ($_ -split "\s+")[-6] }
logoff $userid
return $user
}
# Execution of $scriptBlock
$exitCode = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock
write-output "Logging off $exitCode. "

Add this code to schedule a task that runs at every logon

$start = Get-Date
Write-Output "Execution time set at $($start). "
$workdir = "C:\Windows\Temp"
$path = 'C:\windows\temp\Disable-CachedLogons.ps1'

# Cleanup Prior Scheduled tasks if they exist
Unregister-ScheduledTask -TaskName 'Disable-CachedLogons*' -Confirm:$false | Out-Null

# Build payload to disable Cached Logons
$script = @"
`$date = Get-Date
`$start = Get-Date "$start"

IF(`$date -ge `$start){
# Disconnect VPN
`$ras = rasdial
foreach (`$r in `$ras)
{
try { rasdial `$r /disconnect } catch {}
}

# Require domain controller to log in
Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\" -Name CachedLogonsCount -Value 0

# Log off any user logged in
query user /server:`$env:COMPUTERNAME 2>&1 | select -Skip 1 | foreach { logoff (`$_ -split "\s+")[-6] /server:`$env:COMPUTERNAME }

}
"@
New-Item -Path "$workdir" -Name "Disable-CachedLogons.ps1" -ItemType "file" -Value $script -force | Out-Null

Function Schedule-Payload{
# This will create a scheduled task for payload at LogOn
$TaskStartTime = $start #[datetime]::Now.AddMinutes(0) # Not needed
$SchedService = New-Object -ComObject Schedule.Service
$SchedService.Connect()
$Task = $SchedService.NewTask(0)
$Task.RegistrationInfo.Description = 'This script will disconnect active VPN connections, Disable Windows Cached Logons and log off active user.'
$Task.Settings.Enabled = $true
$Task.Settings.AllowDemandStart = $true
$trigger = $Task.triggers.Create(9) # TASK_TRIGGER_LOGON - https://docs.microsoft.com/en-us/windows/win32/taskschd/triggercollection-create
$trigger.StartBoundary = $TaskStartTime.ToString("yyyy-MM-dd'T'HH:mm:ss")
$trigger.Enabled = $true
$action = $Task.Actions.Create(0)
$action.Path = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$action.Arguments = "-NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -File $path -Force"
$taskFolder = $SchedService.GetFolder('\')
$taskFolder.RegisterTaskDefinition("Disable-CachedLogonsAtLogOn", $Task , 6, 'SYSTEM', $null, 4) | out-null

# This will create a scheduled task for payload at Unlock
$stateChangeTrigger = Get-CimClass -Namespace ROOT\Microsoft\Windows\TaskScheduler -ClassName MSFT_TaskSessionStateChangeTrigger
$onUnlockTrigger = New-CimInstance -CimClass $stateChangeTrigger -Property @{StateChange = 8 } -ClientOnly # TASK_SESSION_STATE_CHANGE_TYPE.TASK_SESSION_UNLOCK (taskschd.h)
$user = "NT AUTHORITY\SYSTEM"
$action = New-ScheduledTaskAction -Execute "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Argument "-NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -File $path -Force"
Register-ScheduledTask -TaskName "Disable-CachedLogonsAtUnlock" -Trigger $onUnlockTrigger -User $user -Action $action | out-null

$trigger = New-ScheduledTaskTrigger -Daily -At $($start) -RepetitionInterval (New-TimeSpan -Minutes 30)
$user = "NT AUTHORITY\SYSTEM"
$action = New-ScheduledTaskAction -Execute "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Argument "-NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -File $path -Force"
Register-ScheduledTask -TaskName "Disable-CachedLogonsOnce" -Trigger $trigger -User $user -Action $action | out-null
}
Schedule-Payload

$tasks = get-scheduledtask -taskname "Disable-CachedLogons*"
foreach ($task in $tasks){
Write-Output "Scheduled $($task.TaskName). "
}

 

STEP THREE > Clear all Kerberos tickets

Insert this code to clear out any kerberos tickets

# Clear all Kerberos tickets. Run as a separate job because sometimes this part hangs for an unknown reason.
Start-Job -ScriptBlock {
Get-CimInstance -ClassName 'Win32_LogonSession' -ErrorAction Stop | Where-Object {$_.AuthenticationPackage -ne 'NTLM'} | ForEach-Object {
klist.exe purge -li ([Convert]::ToString($_.LogonId, 16))
}
}

STEP FOUR> Set Logon Banners

Insert this code to modify how the logon banner looks to let the end user know about the containment

Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "legalnoticecaption" -Value "Company Name"
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "legalnoticetext" -Value "*** Authorized Access Only - Please contact helpdesk ***"

 


1 reply

#TeamDean4Lyfe

 

That’s a lot of work - thanks for sharing!

Reply