Get-SecurityDescriptor.ps1


<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 23ccfcf4-72c0-4a75-8752-bf5fddd88c1c
 
.AUTHOR adebolaige
 
.COMPANYNAME MSFT
 
.COPYRIGHT
 
.TAGS Tarrask malware, Operating System, Registry, Scripting Techniques, Getting Started, PowerShell Registry, SecurityDescriptor
 
.LICENSEURI
 
.PROJECTURI http://www.3hnovation.ca/
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
#>


<#
 
.DESCRIPTION
 This function returns the registry tasks missing the SecurityDescriptor RegistryName
 
#>
 

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