So finden Sie herausragende RPC-Schnittstellen
Redaktion und weitere Beiträge von Tricia Howard
Einführung
In den letzten Monaten hat unser Team viel Arbeit in die MS-RPC-Forschung gesteckt, da das Thema sehr komplex und noch nicht ausreichend erforscht ist. Sie haben vielleicht die unzähligen Beiträge über Schwachstellen gelesen, auf die wir im Rahmen dieser Arbeit gestoßen sind, wie srvsvc und Wininit.exezum Beispiel. Angesichts der enormen Menge an Daten und Tools, die wir in dieser Studie gesammelt haben, war es nur sinnvoll, sie an einem Ort aufzubewahren: unserem RPC-Toolkit.
Dieses Open-Source-Repository enthält alles, was Sie für den Beginn oder die Weiterentwicklung Ihres RPC-Projekts benötigen: Tools, Artikel, Blogbeiträge und Konferenzvorträge sowie Informationen zu RPC-Schwachstellen und Proof-of-Concepts zu Exploits. Dieses Repository wurde in dem Bestreben erstellt, Verteidiger und Forscher gleichermaßen über RPC zu informieren. Schließlich sind wir alle sicherer, wenn wir zusammenarbeiten. An alle, die etwas von uns gelesen, ein Tool benutzt oder unsere Arbeit geteilt haben: Vielen Dank! Wir freuen uns, dass Sie es nutzen.
Eines der Tools im Toolkit ist unser RPC Interface Analyzer, der Sicherheitsexperten wie Ihnen hilft, schnell und einfach Hinweise auf potenziell anfällige Schnittstellen zu erkennen. Dieser Blogbeitrag soll Sie über den beabsichtigten Zweck und die Ergebnisse informieren sowie einen Überblick über RPC und einige seiner Sicherheitsmechanismen für diejenigen geben, die noch nicht damit vertraut sind.
Was ist RPC, und welche Sicherheitsmechanismen gibt es?
Ein Remote Procedure Call (RPC, Remoteprozeduraufruf) ist eine Form der Kommunikation zwischen Prozessen (IPC), mit der ein Client eine Prozedur aufrufen kann, die von einem RPC-Server freigelegt wird. Der Client ruft die Funktion wie einen normalen Prozeduraufruf auf, (fast) ohne Details für die Remote-Interaktion codieren zu müssen. Der Server kann in einem anderen Prozess auf demselben Rechner oder auf einem Remote-Rechner gehostet werden.
MS-RPC, die Microsoft-Implementierung von RPC, wird von Windows für viele verschiedene Services verwendet, wie z. B. Aufgabenplanung, Serviceerstellung, Drucker- und Freigabeeinstellungen und die Verwaltung verschlüsselter Daten, die remote gespeichert werden. Dieses breite Anwendungsspektrum und der Remote-Aspekt von RPC als Vektor sind genau der Grund, warum wir dieses Thema heute diskutieren und warum wir so viele Ressourcen in die RPC-Forschung gesteckt haben. Es verfügt über eine Vielzahl von Funktionen und ist daher sicherheitstechnisch von großer Bedeutung.
In den folgenden Abschnitten werden wir näher auf RPC-Sicherheits-Callbacks eingehen, und wie Sie sie mithilfe von Automatisierung analysieren und möglicherweise neue Hinweise für die Sicherheits- und Schwachstellenforschung generieren können.
Was ist ein RPC-Sicherheits-Callback und wie funktioniert es?
Kurz gesagt, ein Sicherheits-Callback ist eine von mehreren Möglichkeiten, eine RPC-Schnittstelle zu sichern. Es ist ein nutzerdefinierter Callback, der vom RPC-Serverentwickler implementiert wird. Seine Logik bleibt dem Entwickler überlassen. Der Entwickler kann nutzerbasierte Zugriffskontrollen, Authentifizierung und Transporttypen durchsetzen oder den Zugriff auf bestimmte Funktionen verhindern, die vom Server bereitgestellt werden.
Letztendlich gibt der Callback RPC_S_OK zurück, um die Kommunikation des Clients mit dem Server zu ermöglichen, oder einen der RPC-Fehlercodes,wie RPC_S_ACCESS_DENIED, um sie zu verweigern.
Die Entscheidung über die Annahme oder Ablehnung einer Kundenanfrage beruht in der Regel auf einem (oder mehreren) Attributen, die wir im Folgenden genauer untersuchen.
Protokollsequenz
Der Client kann mit dem Server über mehrere Transportwege kommunizieren: TCP, Named Pipes, ALPC und mehr. Der Sicherheits-Callback kann auf dieses Attribut prüfen, um nur lokale Verbindungsanfragen, nur Remote-Anfragen, TCP-Kommunikation usw. zu filtern.
Während die Werte der Protokollsequenz nicht dokumentiert sind, haben wir die Protokollsequenzen, die an den Sicherheits-Callback innerhalb der RpcCallAttributes-Struktur übergeben werden, den folgenden Werten zugeordnet:
#define ncacn_ip_tcp 1
#define ncacn_np 2
#define ncalrpc 3
#define ncacn_http 4
Andere Protokollsequenzen (wie z. B. ncacn_hvsocket) können vom Sicherheits-Callback durch ein Parsing der Zeichenfolgenbindung getestet werden.
Authentifizierungsebene
Die Überprüfung der Authentifizierungsebene des Clients ist bei Sicherheits-Callbacks üblich. Auf diese Weise kann der Server die minimal erforderliche Authentifizierungsebene festlegen, die er von seinen Clients erwartet.
Es gibt mehrere Authentifizierungsebenen, von denen jede die vorherige Ebene erweitert:
#define RPC_C_AUTHN_LEVEL_DEFAULT 0
#define RPC_C_AUTHN_LEVEL_NONE 1
#define RPC_C_AUTHN_LEVEL_CONNECT 2
#define RPC_C_AUTHN_LEVEL_CALL 3
#define RPC_C_AUTHN_LEVEL_PKT 4
#define RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
#define RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6
Ein Server würde beispielsweise die Authentifizierungsebene RPC_C_AUTHN_LEVEL_PKT_PRIVACY erwarten, um sicherzustellen, dass die Kommunikationsdaten nur für den Client und den Server sichtbar sind, oder er würde die Authentifizierungsebene RPC_C_AUTHN_LEVEL_NONE erwarten, um keine Authentifizierung anzuzeigen.
Authentifizierungsdienst
Der Authentifizierungsdienst gibt den Dienst an, der für die Validierung der von der Authentifizierungsebene bereitgestellten Authentifizierungsrichtlinie zuständig ist.
Die Konstanten des Authentifizierungsdiensts sind:
#define RPC_C_AUTHN_NONE 0
#define RPC_C_AUTHN_DCE_PRIVATE 1
#define RPC_C_AUTHN_DCE_PUBLIC 2
#define RPC_C_AUTHN_DEC_PUBLIC 4
#define RPC_C_AUTHN_GSS_NEGOTIATE 9
#define RPC_C_AUTHN_WINNT 10
#define RPC_C_AUTHN_GSS_SCHANNEL 14
#define RPC_C_AUTHN_GSS_KERBEROS 16
#define RPC_C_AUTHN_DPA 17
#define RPC_C_AUTHN_MSN 18
#define RPC_C_AUTHN_DIGEST 21
#define RPC_C_AUTHN_NEGO_EXTENDER 30
#define RPC_C_NETLOGON 68 (nicht dokumentiert)
#define RPC_C_AUTHN_MQ 100
#define RPC_C_AUTHN_DEFAULT 0xffffffff
RPC_C_AUTHN_NONEwürde beispielsweise die Authentifizierung deaktivieren. RPC_C_AUTHN_WINNT verwendet dagegen das NTLM-Protokoll.
Die vollständige Liste der Authentifizierungsdienste und ihrer Werte finden Sie auf dieser GitHub-Seite.
NULL-Sitzung
Eine NULL-Sitzung ist eine anonyme Verbindung. In diesem Fall kommuniziert der Client ohne Authentifizierung mit dem Server, d. h. ohne Nutzername oder Kennwort.
In den meisten Fällen werden NULL-Sitzungen standardmäßig blockiert, wenn ein Sicherheits-Callback registriert wird, es sei denn, die Kennzeichnung RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH wird bei der Serverregistrierung angegeben (Informationen zu anderen Fällen finden Sie hier). Sicherheits-Callbacks können auch auf NULL-Sitzungen prüfen.
Durch die Sperrung des Zugriffs auf diese Sitzungen schützt der Sicherheits-Callback die RPC-Schnittstelle vor nicht authentifizierten Nutzern.
Vorgangsnummer (opnum)
Die opnum steht für die Schnittstellenfunktion, die der Client ausführen möchte. Genauer gesagt ist die opnum der Index in der Funktionstabelle des RPC-Servers.
Durch Prüfen des opnum-Werts kann der Server den Clientzugriff auf bestimmte Funktionen einschränken oder blockieren, z. B. Funktionen, die sensible Daten für Remote-Clients verarbeiten, Funktionen, die auf Kernel-Speicher und/oder Funktionen für Clients im Nutzermodus zugreifen usw.
Akamai Security Research hat in einem Blogbeitrag ein Beispiel für einen interessanten Sicherheits-Callback veröffentlicht, der auf diese Prüfung angewiesen ist.
Weitere Sicherheits-Callback-Prüfungen können sein:
Ursprung des Aufrufers – um zu prüfen, ob der Aufrufer aus dem Nutzer- oder dem Kernelmodus kommt
Prozess-ID des Clients – um nur bestimmte Prozesse zuzulassen
Zeichenfolgenbindung – zur Validierung von RPC-Verbindungsattributen wie Protokollsequenz, Netzwerkadresse, Endpunktinformationen usw.
Identitätswechsel – um sicherzustellen, dass der Server den Code im Sicherheitskontext des Clients ausführen kann
Es gibt auch komplexe Prüfungen. Zum Beispiel bei dem Callback LsaCapRpcIfCallbackFn auf lsasrv.dll. Wenn der Authentifizierungsdienst netlogon ist, sollte die Authentifizierungsebene kleiner als RPC_C_AUTHN_LEVEL_PKT_INTEGRITY sein.
RPC Interface Analyzer – praktische Schritt-für-Schritt-Anleitung
Der RPC Interface Analyzer ist ein Automatisierungstool für die Untersuchung von RPC-Schnittstellen. Mit ihm können Forscher RPC-Schnittstellen aus zwei verschiedenen Quellen finden und analysieren – entweder IDL-Dateien (Interface Definition, Schnittstellendefinition) oder PE-Dateien.
IDL-Dateien
IDL-Dateien sind die Dateien, die eine RPC-Schnittstelle und ihre Funktionen definieren. Durch die Analyse öffentlich verfügbarer IDL-Dateien erhalten wir Informationen über eine RPC-Schnittstelle und die Funktionen, die der Server freilegt, sowie deren Parameter und Rückgabewerte. Anhand dieser Informationen kann ein Forscher nach potenziell anfälligen Funktionen suchen, z. B. Funktionen, die ein Pfadargument erhalten, wie bei PetitPotam.
Um unseren IDL-Analysator zu starten,führen Sie die folgenden Befehle aus:
1. Laden Sie alle IDL-Dateien von der Microsoft-Website mit dem Skript idl_scraper auf Ihren Computer herunter:
idl_scraper.py [-h] [-o OUTPUT] [-p PROTOCOL]
2. Führen Sie dann idl_parser aus, um diese IDL-Dateien zu analysieren:
idl_parser.py [-h] [-r] input_path [output_path]
Als Ergebnis erhalten Sie eine CSV-Datei mit den Namen der RPC-Schnittstellen, den UUIDs (Universally Unique Identifier), den angegebenen Funktionsnamen und den Signaturen.
PE-Dateien
Die Analyse der IDL-Dateien kann nützlich sein, aber möglicherweise fehlen einige RPC-Schnittstellen, da wir nur Zugang zu den öffentlich verfügbaren IDL-Dateien haben. Ein anderer Ansatz ist die Suche nach RPC-Schnittstellen in unserem lokalen Dateisystem – in PE-Dateien (entweder .exe- oder .dll-Dateien). Wir finden diesen Ansatz besser als die Überprüfung von Live-Prozessen, da wir RPC-Server, die nicht aktiv sind oder in geschützten Prozessen ausgeführt werden, auf diese Weise nicht übersehen können.
Der RPC PE Analyzer sucht nach RPC-Schnittstellen, die von der Funktion RpcServerRegisterIf (und ihren Varianten) registriert wurden, und analysiert die an sie weitergegebenen Argumente, falls ein Disassembler bereitgestellt wird. Wenn der Analyzer ohne diese Funktion im Standardmodus ausgeführt wird, findet er RPC-Schnittstellen mit Hilfe von regex. In diesem Vortrag wird der Suchvorgang näher erläutert.
Um den RPC PE Analyzer im Standardmodus zu verwenden, führen Sie den folgenden Befehl aus:
pe_rpc_scraper.py <scrape_path> <output_path>
Mit diesem Befehl erhalten Sie eine grundlegende Ausgabe, die die Schnittstellen-UUID, ihre Rolle (Client/Server) sowie die Funktionsnamen und Adressen enthält.
Wenn Sie detailliertere Informationen wünschen, können Sie einen Disassembler und dessen Pfad (wenn es sich nicht um den Standardpfad handelt) zum Skript angeben:
pe_rpc_scraper.py [-d {idapro,radare}] [-P DISASSEMBLER_PATH] <scrape_path> <output_path>
Mit der Option Disassembler werden auch die Registrierungsinformationen der Schnittstelle hinzugefügt, einschließlich:
Kennzeichnungen, die in der Serverregistrierung angegeben werden
Name und Adresse des Sicherheits-Callback der Schnittstelle
Der Sicherheitsdeskriptor des RPC-Servers (falls vorhanden)
Ob globales Caching für den Sicherheits-Callback aktiviert ist
Mit unserer neuesten Funktion, die zusammen mit diesem Blogbeitrag veröffentlicht wird, kann der Sicherheits-Callback auch selbst analysiert werden.
Beispielhafte Verwendung
Nehmen wir an, wir möchten alle auf unserem Computer verfügbaren RPC-Schnittstellen scannen. Wir können den RPC PE Analyzer ausführen, eine Kopie von C:\Windows\System32 als unseren scrape_path angeben und die Ausgabe durchgehen.
pe_rpc_scraper.py -d idapro „C:\Users\User\Documents\System32_Copy“
Da die Ausgabe im JSON-Format erfolgt, ist es einfach, sie zu wiederholen und nach bestimmten Informationen zu suchen. Zum Beispiel:
Suche nach allen RPC-Clients/-Servern in einer DLL-Datei
Suche nach allen RPC-Clients/-Servern auf einem Rechner
Suche nach Clients einer bestimmten RPC-Schnittstelle
Suche nach dem RPC-Sicherheits-Callback eines bestimmten RPC-Servers
Suche nach RPC-Schnittstellen, die Caching auf Schnittstellenebene verwenden (in diesem Blogbeitrag finden Sie weitere Informationen darüber, warum diese Art von Caching problematisch ist)
Dies sind nur einige von vielen Verwendungsmöglichkeiten für diese Ausgabe. Wir freuen uns, von weiteren Nutzungsmöglichkeiten und Ideen zu erfahren.
Neue Funktion – Informationen zum Sicherheits-Callback
RpcCallAttributes-Struktur
RPC_CALL_ATTRIBUTES ist eine Struktur, die Daten über die Anfrage des Clients enthält. Der Sicherheits-Callback der Schnittstelle auf der Serverseite kann diese Informationen durch Aufruf der Funktion RpcServerInqCallAttributes abrufen.
typedef struct tagRPC_CALL_ATTRIBUTES_V3_W
{
unsigned int Version;
unsigned long Flags;
unsigned long ServerPrincipalNameBufferLength;
unsigned short *ServerPrincipalName;
unsigned long ClientPrincipalNameBufferLength;
unsigned short *ClientPrincipalName;
unsigned long AuthenticationLevel;
unsigned long AuthenticationService;
BOOL NullSession;
BOOL KernelModeCaller;
unsigned long ProtocolSequence;
RpcCallClientLocality IsClientLocal;
HANDLE ClientPID;
unsigned long CallStatus;
RpcCallType CallType;
RPC_CALL_LOCAL_ADDRESS_V1 *CallLocalAddress;
unsigned short OpNum;
UUID InterfaceUuid;
unsigned long ClientIdentifierBufferLength;
unsigned char *ClientIdentifier;
} RPC_CALL_ATTRIBUTES_V3_W;
Wir haben bereits die Prüfungen erwähnt, die von Sicherheits-Callbacks durchgeführt werden. Sie können einige dieser Werte einzeln abfragen (z. B. RpcStringBindingParseW für den Empfang der Protokollsequenz, RpcBindingInqAuthClient für Authentifizierungsinformationen usw.) oder diese Struktur verwenden, die alles enthält und nur einen Funktionsaufruf erfordert. In der Tat rufen die meisten von uns analysierten Callbacks RpcServerInqCallAttributes auf und verwenden die Struktur RPC_CALL_ATTRIBUTES, um alle Attribute gleichzeitig abzufragen. Das macht diese Struktur sehr interessant, wenn Sie die Logik des Sicherheits-Callback verstehen wollen.
Die Struktur hat derzeit drei verschiedene Versionen – 1, 2 und 3 – und jede ist eine Erweiterung ihrer vorherigen Version und hat ANSI- und Unicode-Versionen. Die verschiedenen Versionen und deren Mitglieder finden Sie auf dieser GitHub-Seite.
Informationen zum Sicherheits-Callback
Die neue Ergänzung zu unserem RPC-Toolkit sind die Sicherheits-Callback-Informationen,die Teil des RPC PE Analyzer. Sie bieten einen Einblick in die Prüfungen und Verifizierungen, die der Sicherheits-Callback durchführt, bevor er Client-Anfragen genehmigt/ablehnt.
Die Analyse des Sicherheits-Callback einer RPC-Schnittstelle und insbesondere ihres Zugriffs auf die Struktur RPC_CALL_ATTRIBUTES kann Aufschluss über die Schnittstelle geben. Auf diese Weise können Sie nach Sicherheits-Callbacks suchen, die den Authentifizierungsdienst prüfen, wenn Sie RPC-Schnittstellen filtern möchten, die ein bestimmtes Authentifizierungsprotokoll verwenden (oder nicht verwenden). Sie können auch RPC-Schnittstellen abfragen, die nicht auf NULL-Sitzungen prüfen, bevor sie Client-Anfragen zulassen und deren Server-Registrierungskennzeichen NULL-Sitzungen zulassen, um potenziell anfällige RPC-Schnittstellen aufzudecken.
Wie funktioniert das?
Bei jedem Sicherheits-Callback geht der Analyzer folgendermaßen vor:
Ermitteln, welche Strukturversion von RPC_CALL_ATTRIBUTES verwendet wird, und definieren der entsprechenden Strukturversion in den lokalen IDA-Typen
Suche nach der lokalen Variable RpcCallAttribute und Anwenden der Struktur RPC_CALL_ATTRIBUTES als Typ
Analysieren der Prüfungen, die der Sicherheits-Callback mit dieser Struktur durchführt, und Ausgabe des getesteten Elements, des verglichenen Werts und des Operators (== / != / > / < / usw.).
Wie kann ich es verwenden?
An der Verwendung hat sich nichts geändert: Jedes Mal, wenn Sie den RPC PE Analyzer mit der IDA-Disassembler-Kennzeichnung ausführen, enthält die Ausgabe für jede RPC-Schnittstelle jetzt die Sicherheits-Callback-Informationen – ob sie auf die Strukturelemente RpcCallAttributes zugreift und was sie testet.
Hinweis: Diese Ergänzung ist derzeit nur für IDA verfügbar. Wenn der Analyzer mit der Option Radare ausgeführt wird, werden keine Sicherheits-Callback-Informationen angezeigt.
Sobald Sie die Ausgabe haben, können Sie möglicherweise anfällige RPC-Schnittstellen finden und sie entsprechend ihrer Anforderungen filtern. Beispiele:
Abruf einer RPC-Schnittstelle, die nur die Authentifizierungsebene RPC_C_AUTHN_LEVEL_PKT_PRIVACY verwendet
Abruf von RPC-Schnittstellen, die lokale Verbindungen erwarten
Abruf von RPC-Schnittstellen, die nur Kernel-Modus-Aufrufer erwarten
Abruf von RPC-Schnittstellen, die wie im Fall der Caching-Schwachstelle auf opnum prüfen
Zusammenfassung
Es ist mittlerweile weithin bekannt, dass RPC ein großes Forschungspotenzial birgt, insbesondere wenn man bedenkt, wie alt und in wie viele wichtige Prozesse integriert es ist. Seit fast einem Jahr bündeln wir Ressourcen in unserem Repository, und es gibt immer noch viel zu tun, um das Bedrohungspotenzial von RPC voll offenzulegen. Es ist noch weitgehend unerforscht, und obwohl es in letzter Zeit mehr Aufmerksamkeit erregt hat, gibt es noch viel zu entdecken über die unzähligen Möglichkeiten, wie Angreifer es missbrauchen könnten.
Das Wesen von RPC rechtfertigt eine Untersuchung aller potentiell gefährlichen Aspekte. Wir hoffen, dass wir mit unserer kontinuierlichen Forschung und den Tools in unserem Repository diesen Vektor noch genauer beleuchten und andere Forscher dazu inspirieren können, sich ebenfalls damit zu befassen. Ganz gleich, ob Sie Verteidiger sind, die für die Sicherung von RPC verantwortlich sind, oder Forscher auf der Suche nach dem nächsten Ziel – RPC birgt ein großes Potenzial an Wissen und Erkenntnissen.
Sind Sie bereit, loszulegen? Sehen Sie sich das Repositoryan, und lassen Sie uns auf Twitter wissen, was Sie gefunden haben!