Get-SecurityDescriptor.ps1


<#PSScriptInfo
 
.VERSION 1.1
 
.GUID 23ccfcf4-72c0-4a75-8752-bf5fddd88c1c
 
.AUTHOR adebolaige
 
.COMPANYNAME Employed
 
.COPYRIGHT Copyright (c) 2022 Adebola Ige
 
.TAGS Tarrask, malware, Hafnium, Registry, SecurityDescriptor, Scheduledtasks, tasks, Windows, MITRE, T1036, Persistence, T1053, schtasks, scheduler
 
.LICENSEURI
 
.PROJECTURI https://github.com/Zoudo
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
#>
 



<#
 
.DESCRIPTION
This script reviews the Registry Hive and identifies any scheduled tasks without SD (security descriptor) Value within the Task Key. We recommend that you perform analysis on these tasks as needed. The absence of SecurityDescriptor is a Defense Evasion and Persistence technique as these tasks will remain hidden from regular tasks queries results except an examiner manually reviews the registry path
 
#>
 

Param()


Function Get-SecurityDescriptor

{

<#.Synopsis
SD refers to the Security Descriptor, which determines the users allowed to run the task.
 Interestingly, removal of this value results in the task �disappearing� from �schtasks /query� and Task Scheduler.
 The task is effectively hidden unless an examiner manually inspects the aforementioned registry paths
 This script is inspired by the Defense Evasion technique for scheduled tasks described here:
 https://www.microsoft.com/security/blog/2022/04/12/tarrask-malware-uses-scheduled-tasks-for-defense-evasion/
  
#>


    Param([string]$registryPath="HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree")
    
    $task_No_SecurityDescriptor=@() #to store tasks missing SD registryName
    $task_Yes_SecurityDescriptor=@() #to store tasks which contains SD registryName
    $registry_name=@() #to store the registryName
    $task=@() #to store the registry tasks
    $Nameexist=@() #to verify if the registry name exists
    $list_registry_path=@() #to list the registry paths
    $registry_path=@() #to iterate each registry path


    $list_registry_path=(get-childitem -path $registryPath -Recurse)
    
    $registry_name=@(
    foreach ($registry_path in $list_registry_path) 
        {
        ($registry_name+=$registry_path.Name) 
        })
    
    foreach ($task in $registry_name)
    {
    
        $Nameexist=(get-itemproperty -path Registry::$task).SD
        if ($Nameexist -eq $null) 
        { 
            
            $task_No_SecurityDescriptor+=$task
                } 
        else 
        {
            $task_Yes_SecurityDescriptor+=$task
                }
    
    }
    
    write-host -ForegroundColor Red ("Please review tasks without the SecurityDescriptor RegistryName, downloaded to $pwd\task_No_SecurityDescriptor.csv")
    $task_No_SecurityDescriptor | Select-Object @{Name='Name';Expression={$_}} -Unique |Export-Csv -Path task_No_SecurityDescriptor.csv -NoTypeInformation
    write-host "`n"
    write-host -ForegroundColor Green ("Tasks with SecurityDescriptor RegistryName are downloaded to $pwd\task_Yes_SecurityDescriptor.csv")
    $task_Yes_SecurityDescriptor | Select-Object @{Name='Name';Expression={$_}} -Unique |Export-Csv -Path task_Yes_SecurityDescriptor.csv -NoTypeInformation

} #end function Get-SecurityDescriptor

Get-SecurityDescriptor