Einführung
In diesem Artikel werden wir uns mit dem Konzept des DLL-Hijacking befassen und wie es verwendet werden kann, um auf Windows-Systemen eine Persistenz des Benutzerlandes zu erreichen. Diese Methode wird in MITRE ATT & CK unter "Abfangen der DLL-Suchreihenfolge (T1038) " beschrieben.
DLL-Spoofing kann von Angreifern für viele verschiedene Zwecke verwendet werden. Dieser Artikel konzentriert sich jedoch auf das Erreichen der Ausfallsicherheit mithilfe von Autostart-Anwendungen. Da beispielsweise Slack- und Microsoft-Teams beim Start (standardmäßig) gestartet werden, kann ein Angreifer durch DLL-Spoofing in einer dieser Anwendungen dauerhaft auf sein Ziel zugreifen, wenn sich ein Benutzer anmeldet.
Nachdem ich das Konzept der DLLs, der DLL-Suchreihenfolge und des DLL-Spoofing vorgestellt habe, werde ich Sie durch den Prozess der Automatisierung der DLL-Abhörerkennung führen . In diesem Artikel wird das Erkennen von DLL-Abfangpfaden in Slack, Microsoft Teams und Visual Studio Code beschrieben.
Schließlich entdeckte ich mehrere DLL-Abfangpfade, die von verschiedenen Anwendungen verwendet wurden, untersuchte die Grundursache und stellte fest, dass Anwendungen, die bestimmte Windows-API-Aufrufe verwenden, für das Abfangen von DLLs anfällig sind, wenn sie nicht ausgeführt werden
C:\Windows\System32\.
Ich möchte meinem Kollegen Josiah Massari (
@Airzero24) dafür danken, dass er als erster einige dieser DLL-Hooks entdeckt, ihre Methodik erklärt und mich dazu inspiriert hat, die Erkennung zu automatisieren.
Was ist eine DLL?
Eine DLL ist eine Bibliothek mit Code und Daten, die von mehr als einem Programm gleichzeitig verwendet werden können. ( Quelle ) Die
Funktionalität einer DLL kann von einer Windows-Anwendung mit einer der Funktionen verwendet werden
LoadLibrary*. Anwendungen können auf DLLs verweisen, die speziell für diese Anwendungen entwickelt wurden, oder auf Windows-DLLs, die sich bereits in System32 auf der Festplatte befinden. Entwickler können DLLs von System32 laden, um Funktionen zu verwenden, die bereits in Windows in ihren Anwendungen implementiert sind, ohne diese Funktionen von Grund auf neu schreiben zu müssen.
Beispielsweise kann ein Entwickler, der HTTP-Anforderungen stellen muss, die WinHTTP (
winhttp.dll) - Bibliothek verwenden, anstatt HTTP-Anforderungen mithilfe von Raw-Sockets zu implementieren.
DLL-Suchreihenfolge und Abfangen
Da DLLs als Dateien auf der Festplatte vorhanden sind, fragen Sie sich möglicherweise, woher eine Anwendung weiß, woher die DLL geladen werden soll. Microsoft hat die DLL-Suchreihenfolge hier detailliert dokumentiert .
Ab Windows XP SP2 ist der sichere DLL-Suchmodus standardmäßig aktiviert (
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode). Wenn der abgesicherte Modus aktiviert ist, lautet die DLL-Suchreihenfolge wie folgt:
- Das Verzeichnis, aus dem die Anwendung geladen wurde.
- Systemverzeichnis. Verwenden Sie die Funktion GetSystemDirectory , um den Pfad zu diesem Verzeichnis abzurufen .
- 16-Bit-Systemverzeichnis. Es gibt keine Funktion, die einen Pfad zu diesem Verzeichnis bereitstellt, aber es wird gesucht.
- Windows-Verzeichnis. Verwenden Sie die Funktion GetWindowsDirectory , um den Pfad zu diesem Verzeichnis abzurufen .
- Aktuelles Verzeichnis.
- , PATH. , , App Paths. App Paths DLL.
Ein System kann mehrere Versionen derselben DLL enthalten. Anwendungen können die Auswahl des Speicherorts steuern, von dem die DLL geladen werden soll, indem sie den vollständigen Pfad angeben oder einen anderen Mechanismus wie ein Manifest verwenden. ( Quelle )
Wenn die Anwendung nicht angibt, von wo die DLL geladen werden soll, verwendet Windows die oben gezeigte Standard-DLL-Suchreihenfolge. Die erste Position in der DLL-Suchreihenfolge (das Verzeichnis, aus dem die Anwendung geladen wird) ist für Angreifer von Interesse.
Wenn der Anwendungsentwickler beabsichtigt, die DLL von zu laden
C:\Windows\System32, aber nicht explizit in die Anwendung geschrieben, wird die im Anwendungsverzeichnis platzierte schädliche DLL vor der legitimen DLL von System32 geladen. Das Laden einer schädlichen DLL wird als DLL-Spoofing (oder Abfangen) bezeichnet und von Angreifern verwendet, um bösartigen Code in vertrauenswürdige / signierte Anwendungen zu laden.
Verwenden von DLL-Spoofing zum Erreichen von Ausfallsicherheit
DLL-Spoofing kann verwendet werden, um Ausfallsicherheit zu erreichen, wenn eine anfällige Anwendung / ein anfälliger Dienst gestartet und eine schädliche DLL an einem anfälligen Ort abgelegt wird. Ein Kollege von mir
@Airzero24entdeckte DLL-Spoofing in Microsoft OneDrive, Microsoft Teams und Slack as userenv.dll.
Diese Programme wurden zum Ziel des Abfangens, da sie standardmäßig so konfiguriert sind, dass sie beim Start von Windows gestartet werden. Dies ist unten im Task-Manager zu sehen: Für
den Autostart konfigurierte Windows-Anwendungen
Um das DLL-Spoofing zu testen, habe ich einen DLL-Shellcode-Loader erstellt, mit dem Cobalt Strike Beacon gestartet wurde. Ich habe die schädliche DLL in umbenannt
userenv.dllund in das betroffene Anwendungsverzeichnis kopiert. Ich habe die Anwendung gestartet und meinen neuen Beacon-Rückruf gesehen.
Cobalt Strike Beacon durch DLL-Interception
mitIm Prozess-Explorer kann ich überprüfen, ob meine schädliche DLL tatsächlich von einer anfälligen Anwendung geladen wurde.
Prozess-Explorer zeigt geladene schädliche DLL an
Automatische Erkennung des DLL-Abhörpotentials
Nachdem ich das zuvor bekannte DLL-Hijacking bestätigt hatte, wollte ich sehen, ob ich andere DLL-Spoofing-Funktionen finden konnte, die ausgenutzt werden konnten.
Den in meiner Kasse verwendeten Code finden Sie hier .
Am Beispiel von Slack
Um diesen Prozess zu starten, habe ich Process Monitor (ProcMon) mit den folgenden Filtern ausgeführt:
- Prozessname -
slack.exe - Ergebnis enthält
NOT FOUND - Der Weg endet mit
.dll.
Finden Sie fehlende DLLs in ProcMon.
Dann startete ich Slack und untersuchte ProcMon auf DLLs, die Slack suchte, aber nicht finden konnte.
Mögliche von ProcMon entdeckte DLL-Abfangpfade
Ich habe diese Daten aus ProcMon als CSV-Datei exportiert, um das Parsen in PowerShell zu vereinfachen.
Mit meiner aktuellen Shellcode Loader-DLL konnte ich die DLL-Namen, die von Slack erfolgreich geladen wurden, nicht einfach herausfinden. Ich habe eine neue DLL erstellt, die verwendet
GetModuleHandleExwird GetModuleFileName, um den Namen der geladenen DLL zu ermitteln und in eine Textdatei zu schreiben .
Mein nächstes Ziel war es, die CSV-Datei für DLL-Pfade in der Liste zu analysieren, diese Liste anzuzeigen, meine Test-DLL in den angegebenen Pfad zu kopieren, den Zielprozess zu starten, den Zielprozess zu stoppen und die Test-DLL zu löschen. Wenn die Test-DLL erfolgreich geladen wurde, schreibt sie ihren Namen in die resultierende Datei.
Wenn dieser Prozess abgeschlossen ist, werde ich eine Liste möglicher DLL-Hijacks (ich hoffe) in eine Textdatei schreiben lassen.
Die ganze Magie in meinem DLLHijackTest-Projekt wird von einem PowerShell-Skript ausgeführt . Es akzeptiert den Pfad zu der von ProcMon generierten CSV-Datei, den Pfad zu Ihrer schädlichen DLL, den Pfad zu dem Prozess, den Sie ausführen möchten, und alle Argumente, die Sie an den Prozess übergeben möchten.
Get-PotentialDLLHijack-Parameter
Get-PotentialDLLHijack.ps1
Nach einigen Minuten überprüfe ich die in meiner "böswilligen" DLL aufgeführte Textdatei auf mögliche DLL-Hijacks. Ich habe die folgenden möglichen Abfangpfade für Slack gefunden:
PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\slack\slack.exe"
C:\Users\John\AppData\Local\slack\app-4.6.0\WINSTA.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\LINKINFO.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\ntshrui.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\srvcli.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\cscapi.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\KBDUS.DLL
Am Beispiel von Microsoft Teams
Wir führen den oben beschriebenen Prozess erneut durch:
- Verwenden Sie ProcMon, um potenzielle DLL-Abfangpfade zu identifizieren, und exportieren Sie diese Daten als CSV-Datei.
- Bestimmen Sie den Pfad zum Starten des Prozesses.
- Definieren Sie alle Argumente, die Sie an den Prozess übergeben möchten.
- Führen Sie
Get-PotentialDLLHijack.ps1mit den entsprechenden Argumenten aus.
Ich habe die folgenden möglichen Abfangpfade für Microsoft-Teams gefunden:
PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\Microsoft\Teams\Update.exe" -ProcessArguments '--processStart "Teams.exe"'
C:\Users\John\AppData\Local\Microsoft\Teams\current\WINSTA.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\LINKINFO.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\ntshrui.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\srvcli.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\cscapi.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\WindowsCodecs.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\TextInputFramework.dll
Hinweis : Zum Abschluss musste ich kleine Änderungen am PowerShell-Skript vornehmenTeams.exe, da mein Skript versucht, den zu startenden Prozess zu beenden. In diesem Fall ist dies der FallUpdate.exe.
Verwenden Sie Visual Studio Code als Beispiel
Durch Wiederholen des obigen Vorgangs habe ich die folgenden möglichen Abfangpfade für Visual Studio Code gefunden:
PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\Programs\Microsoft VS Code\Code.exe"
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\WINSTA.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\LINKINFO.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\ntshrui.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\srvcli.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\cscapi.dll
Freigeben von DLLs
Ich habe festgestellt, dass Slack, Microsoft Teams und Visual Studio Code die folgenden DLLs gemeinsam nutzen:
WINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dllcscapi.dll
Ich fand das interessant und wollte verstehen, was dieses Verhalten verursacht.
Methodik: Grundlegendes zum Abfangen gemeinsam genutzter DLLs
Ich sah Tracy Stapel , wenn sie Last versucht Lasches
WINSTA.dll, LINKINFO.dll, ntshrui.dll, srvcli.dllund cscapi.dll.
DLL mit verzögertes Laden
bemerkte ich Ähnlichkeiten in Tracy - Stack beim Laden
WINSTA.dll, LINKINFO.dll, ntshrui.dllund srvcli.dll.
Stack-Trace, wenn Code.exe versucht,
WINSTA.dll
einen Stack-Trace beim
Teams.exeLaden zu laden LINKINFO.dll,
Stack-Trace, wenn Slack versucht,
ntshrui.dll
einen Stack-Trace zu laden , enthält ständig einen Aufruf
_tailMerge_<dllname>_dll, delayLoadHelper2gefolgt von LdrResolveDelayLoadedAPI. Dieses Verhalten war für alle drei Anwendungen gleich.
Ich habe festgestellt, dass dieses Verhalten mit dem verzögerten Laden der DLL zusammenhängt . Vom Trace-Stack beim Booten
WINSTA.dllIch konnte sehen, dass das Modul für dieses verzögerte Laden verantwortlich war wtsapi32.dll.
Ich öffnete
wtsapi32.dllin Ghidra und benutzte Search -> For Strings -> Filter: WINSTA.dll. Ein Doppelklick auf die gefundene Zeile führt Sie zu ihrer Position im Speicher.
Die Zeile "
WINSTA.dll" inwtsapi32.dll
Wenn Sie mit der rechten Maustaste auf eine Stelle im Speicher klicken, können Sie Verweise auf diese Adresse finden.
Links zu
WINSTA.dll
Wenn Sie den Links folgen, sehen Sie, dass die Zeichenfolge
WINSTA.dllan eine Struktur mit dem Namen übergeben wird ImgDelayDescr. In der Dokumentation zu dieser Struktur können wir bestätigen, dass sie mit dem verzögerten Laden von DLLs zusammenhängt.
typedef struct ImgDelayDescr {
DWORD grAttrs; //
RVA rvaDLLName; // RVA dll
RVA rvaHmod; // RVA
RVA rvaIAT; // RVA IAT
RVA rvaINT; // RVA INT
RVA rvaBoundIAT; // RVA IAT
RVA rvaUnloadIAT; // RVA IAT
DWORD dwTimeStamp; // 0, ,
// O.W. / DLL, (Old BIND)
} ImgDelayDescr, * PImgDelayDescr;
Diese Struktur kann an übergeben werden
__delayLoadHelper2, die LoadLibrary/ GetProcAddresszum Laden der angegebenen DLL und zum Korrigieren der importierten Funktionsadresse in der IAT (Lazy Load Import Address Table) verwendet.
FARPROC WINAPI __delayLoadHelper2(
PCImgDelayDescr pidd, // ImgDelayDescr
FARPROC * ppfnIATEntry // IAT
);
Indem
ImgDelayDescrwir andere Verweise auf unsere Struktur finden , können wir einen Anruf finden __delayLoadHelper2, der dann anruft ResolveDelayLoadedAPI. Ich habe den Funktionsnamen, die Typen und die Variablen umbenannt, um das Verständnis zu erleichtern.
__delayLoadHelper2und ResolveDelayLoadedAPIbei Ghidra
Excellent! Dies stimmt mit dem überein, was wir in unserem ProcMon-Stack-Trace gesehen haben, als Slack versuchte zu laden
WINSTA.dll.
__delayLoadHelper2 und ResolveDelayLoadedAPIin ProcMon.
Dieses Verhalten wurde einheitlich für
WINSTA.dll, LINKINFO.dll, ntshrui.dllund srvcli.dll. Der Hauptunterschied zwischen jeder Lazy-Load-DLL war die "übergeordnete" DLL. In allen drei Anwendungen:
wtsapi32.dllaufgeschoben geladenWINSTA.dllshell32.dllfaul geladenLINKINFO.dllLINKINFO.dllaufgeschoben geladenntshrui.dllntshrui.dllaufgeschoben geladensrvcli.dll
Haben Sie etwas Interessantes bemerkt? Es sieht so aus, als würde es
shell32.dllherunterladen LINKINFO.dll, welche herunterladen ntshrui.dll, welche schließlich herunterladen srvcli.dll. Dies bringt uns zu unserer letzten gemeinsamen potenziellen DLL-Spoofing-Option - cscapi.dll.
DLL-Ersetzung in NetShareGetInfo und NetShareEnum
Ich folgte der Stapelverfolgung, als Slack versuchte zu laden
cscapi.dllund einen Anruf sah LoadLibraryExW, der anscheinend von kam srvcli.dll.
Ich habe den
Stack-Trace beim Booten
cscapi.dll in Ghidra
geöffnet und verwendet . Ein Doppelklick auf die gefundene Zeile und das Folgen der Links führt zum erwarteten Anruf. ruft LoadLibrary auf, um die Funktion, die den Aufruf enthält, umzubenennen und den Links zu folgen. Ich habe zwei Stellen, an denen die Funktion verwendet wird:
srvcli.dllSearch -> For Strings -> Filter: cscapi.dllLoadLibrary
srvcli.dllcscapi.dll
LoadLibrary
NetShareEnum-Downloads cscapi.dll
NetShareGetInfo-Downloads
cscapi.dll
Ich habe dies mit PoC-Programmen überprüft, die aufgerufen haben
NetShareEnumund NetShareGetInfo:
NetShareEnum.exeDownloads cscapi.dll
NetShareGetInfo.exeherunterladencscapi.dll
Ergebnisse
Die folgenden DLL-Spoofing-Pfade sind in Slack verfügbar:
C:\Users\John\AppData\Local\slack\app-4.6.0\WINSTA.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\LINKINFO.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\ntshrui.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\srvcli.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\cscapi.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\KBDUS.DLL
Die folgenden DLL-Spoofing-Pfade sind in Microsoft Teams verfügbar:
C:\Users\John\AppData\Local\Microsoft\Teams\current\WINSTA.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\LINKINFO.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\ntshrui.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\srvcli.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\cscapi.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\WindowsCodecs.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\TextInputFramework.dll
Die folgenden DLL-Spoofing-Pfade sind in Visual Studio Code verfügbar:
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\WINSTA.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\LINKINFO.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\ntshrui.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\srvcli.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\cscapi.dll
Darüber hinaus stellte ich fest, dass Programme DLLs in der Form verwenden
NetShareEnumund NetShareGetInfobereitstellen, die cscapi.dllaufgrund des fest codierten Aufrufs ersetzt werden können LoadLibrary. Ich habe dieses Verhalten mit Ghidra und PoC überprüft.
Fazit
Zur Erinnerung: Das Abfangen von DLLs ist eine Methode, mit der Angreifer die Codeausführung in signierten / vertrauenswürdigen Anwendungen stören können. Ich habe Tools erstellt, mit denen die Erkennung von DLL-Abfangpfaden automatisiert werden kann. Mit diesem Tool habe ich DLL-Abfangpfade in Slack, Microsoft Teams und Visual Studio Code entdeckt.
Ich habe festgestellt, dass sich die DLL-Abfangpfade dieser drei Anwendungen überschneiden, und die Ursache untersucht. Ich habe meine Methode zum Verständnis dieses Zufalls hervorgehoben. Ich habe etwas über das verzögerte Laden von DLLs gelernt und zwei API-Aufrufe entdeckt, die es ermöglichen, DLLs in jedem Programm abzufangen, das sie aufruft:
NetShareEnumLadungencscapi.dllNetShareGetInfoLadungencscapi.dll
Vielen Dank, dass Sie sich die Zeit genommen haben, diesen Artikel zu lesen. Ich hoffe, Sie haben ein oder zwei Dinge über Windows-APIs, Ghidra, ProcMon, DLLs und DLL-Interception gelernt!
Links
Ein großes Hallo an meine Kollegen Daniel Heinsen (
@hotnops), Lee Christensen ( @tifkin_) und Matt Hand ( @matterpreter) für ihre Hilfe bei Ghidra / ProcMon!
Überprüfen öffentlicher PoCs zur Verwendung beim Pentesting