
Eine etwas weniger hackige Methode, um nicht-HTTP-Protokolle durch Burp & andere abzufangen und zu modifizieren.
Eine etwas weniger hackige Methode, um Nicht-HTTP-Protokolle durch Burp und andere mit SSL- und TLS-Interception-Unterstützung abzufangen und zu modifizieren. Dieses Tool ist für Forscher und anwendungsorientierte Penetrationstester gedacht, die Sicherheitsbewertungen von Thick Clients durchführen.
Eine verbesserte Version des fantastischen mitm_relay-Projekts.
Im Rahmen unserer Arbeit in der Forschungsabteilung von CyberArk Labs brauchten wir eine Möglichkeit, SSL- und TLS-Kommunikation über TCP zu inspizieren und die Inhalte von Paketen während der Übertragung zu modifizieren. Es gibt viele Wege, dies zu tun (z. B. die bekannte Burp-Suite-Erweiterung NoPE), aber in einigen Fällen hat uns keiner davon funktioniert. Schließlich stießen wir auf mitm_relay.
mitm_relay ist ein schneller und einfacher Weg, um MITM für jedes TCP-basierte Protokoll durch vorhandene HTTP-Interceptionsoftware wie den Proxy von Burp Suite durchzuführen. Es ist besonders nützlich für Sicherheitsbewertungen von Thick Clients. Aber es hat für uns nicht vollständig funktioniert, also mussten wir es anpassen. Nach vielen Anpassungen erforderte jede neue Änderung viel Arbeit, und wir haben schließlich alles in einer modulareren Weise neu geschrieben.
Wir hoffen, dass andere dieses Skript nützlich finden, und wir hoffen, dass das Hinzufügen von Funktionen einfach sein wird.
Zunächst müssen die Adressen und Ports der Listener konfiguriert werden. Für jeden Listener muss auch ein Ziel konfiguriert werden (Adresse und Port). Jede vom Listener empfangene Daten werden in den Body einer HTTP-POST-Anfrage mit der URL, die "CLIENT_REQUEST" enthält, verpackt. Jede vom Ziel empfangene Daten werden in den Body einer HTTP-POST-Anfrage mit der URL, die "SERVER_RESPONSE" enthält, verpackt. Diese Anfragen werden an einen lokalen HTTP-Interceptionserver gesendet.
Es besteht die Möglichkeit, einen HTTP-Proxy zu konfigurieren und ein Tool wie Burp Suite als HTTP-Interception-Tool zu verwenden und die Nachrichten dort zu betrachten. Auf diese Weise ist es einfach, die Nachrichten mit Burps "Match and Replace", Erweiterungen oder sogar manuell zu modifizieren (Denken Sie daran, der Timeout-Mechanismus des abgefangenen Protokolls kann sehr kurz sein).
Eine andere Möglichkeit, die Nachrichten zu modifizieren, ist die Verwendung eines Python-Skripts, das der HTTP-Interceptionserver ausführt, wenn er Nachrichten empfängt.
Die an den HTTP-Interceptionserver gesendeten Nachrichteninhalte werden in der Shell ausgegeben. Wenn das Modifikationsskript angegeben ist, werden die Nachrichten nach den Änderungen ausgegeben. Nach allen Modifikationen gibt der Interceptionserver die Nachricht auch als HTTP-Antwortbody zurück.
Um die SSL/TLS-Kommunikation zu entschlüsseln, muss mitm_intercept ein Zertifikat und einen Schlüssel bereitgestellt werden, die der Client beim Aufbau eines Handshakes mit dem Listener akzeptiert. Wenn der Zielserver ein bestimmtes Zertifikat für einen Handshake benötigt, gibt es die Option, ein Zertifikat und einen Schlüssel anzugeben.
Ein kleines Diagramm, das den typischen Datenverkehrsfluss zeigt:

mitm_intercept ist mit neueren Versionen von Python 3 (Python 3.9) kompatibel und auch mit Windows kompatibel (z. B. existiert socket.MSG_DONTWAIT unter Windows nicht). Wir haben die Option "STARTTLS" beibehalten und sie "Mixed"-Modus genannt. Die Verwendung der SSL-Schlüssel-Log-Datei wurde aktualisiert (die integrierte Option zur Verwendung ist neu ab Python 3.8), und wir haben die Option hinzugefügt, den SNI-Header zu ändern. Nun wird die Verwaltung der eingehenden und ausgehenden Kommunikation durch socketserver erledigt, und alle Daten werden an eine Unterklasse von ThreadingHTTPServer gesendet, die die Darstellung und Modifikation der Daten übernimmt. Auf diese Weise ist es möglich, die durch das Modifikationsskript angewendeten Änderungen in der Antwort zu sehen (praktisch für die Verwendung von Burp). Außerdem können wir jetzt die verfügbaren Ciphers, die das Skript verwendet, mit dem OpenSSL-Cipher-List-Format ändern.
$ python -m pip install requestsusage: mitm_intercept.py [-h] [-m] -l [u|t:]<interface>:<port> [[u|t:]<interface>:<port> ...] -t
[u|t:]<addr>:<port> [[u|t:]<addr>:<port> ...] [-lc <cert_path>]
[-lk <key_path>] [-tc <cert_path>] [-tk <key_path>] [-w <interface>:<port>]
[-p <addr>:<port>] [-s <script_path>] [--sni <server_name>]
[-tv <defualt|tls12|tls11|ssl3|tls1|ssl2>] [-ci <ciphers>]
mitm_intercept version 1.6
options:
-h, --help Zeigt diese Hilfemeldung an und beendet das Programm.
-m, --mix-connection Führt TCP-Relay ohne SSL-Handshake durch. Wenn eine der Relay-Seiten einen
SSL-Handshake startet, wird die Verbindung mit SSL umschlossen und die
Kommunikation abgefangen. Ein Listener-Zertifikat und ein privater Schlüssel
müssen bereitgestellt werden.
-l [u|t:]<interface>:<port> [[u|t:]<interface>:<port> ...], --listen [u|t:]<interface>:<port> [[u|t:]<interface>:<port> ...]
Erstellt einen SSLInterceptServer-Listener, der auf der angegebenen Schnittstelle
und dem angegebenen Port lauscht. Es können mehrere Listener mit einem Leerzeichen
zwischen den Parametern erstellt werden. Das Hinzufügen von "u:" vor der Adresse
lässt den Listener im UDP-Protokoll lauschen. TCP-Protokoll ist die Voreinstellung,
aber das Hinzufügen von "t:" aus Gründen der Übersichtlichkeit ist möglich. Die
Anzahl der Listener muss der Anzahl der Ziele entsprechen. Der i-te Listener
leitet an das i-te Ziel weiter.
-t [u|t:]<addr>:<port> [[u|t:]<addr>:<port> ...], --target [u|t:]<addr>:<port> [[u|t:]<addr>:<port> ...]
Leitet jeden SSLInterceptServer-Listener an eine Zieladresse und einen Zielport
weiter. Es können mehrere Ziele mit einem Leerzeichen zwischen den Parametern
erstellt werden. Das Hinzufügen von "u:" vor der Adresse lässt das Ziel im
UDP-Protokoll kommunizieren. TCP-Protokoll ist die Voreinstellung, aber das
Hinzufügen von "t:" aus Gründen der Übersichtlichkeit ist möglich. Die Anzahl
der Listener muss der Anzahl der Ziele entsprechen. Der i-te Listener leitet an
das i-te Ziel weiter.
-lc <cert_path>, --listener-cert <cert_path>
Das Zertifikat, das der Listener verwendet, wenn ein Client ihn kontaktiert.
Kann ein selbstsigniertes Zertifikat sein, wenn der Client es akzeptiert.
-lk <key_path>, --listener-key <key_path>
Der Pfad zum privaten Schlüssel für das Listener-Zertifikat.
-tc <cert_path>, --target-cert <cert_path>
Das Zertifikat, das zum Aufbau einer Verbindung mit dem Ziel verwendet wird.
Kann ein selbstsigniertes Zertifikat sein, wenn das Ziel es akzeptiert. Nicht
erforderlich, wenn das Ziel kein bestimmtes Zertifikat benötigt.
-tk <key_path>, --target-key <key_path>
Der Pfad zum privaten Schlüssel für das Ziel-Zertifikat.
-w <interface>:<port>, --webserver <interface>:<port>
Gibt die Schnittstelle und den Port an, auf dem der InterceptionServer-
Webserver lauschen soll. Standardmäßig 127.0.0.1:49999, falls nicht angegeben.
-p <addr>:<port>, --proxy <addr>:<port>
Gibt die Adresse und den Port eines Proxys zwischen dem InterceptionServer-
Webserver und dem SSLInterceptServer an. Kann so konfiguriert werden, dass die
Kommunikation über einen lokalen Proxy wie Burp läuft. Falls nicht angegeben,
wird die Kommunikation nur in der Shell ausgegeben.
-s <script_path>, --script <script_path>
Ein Pfad zu einem Skript, das der InterceptionServer-Webserver ausführt. Muss
die Funktion handle_request(message) enthalten, die ausgeführt wird, bevor die
Nachricht an das Ziel gesendet wird, oder handle_response(message) nach dem
Empfang einer Nachricht vom Ziel. Kann ausgelassen werden, falls nicht
erforderlich.
--sni <server_name> Wenn die Notwendigkeit besteht, den Servernamen im SSL-Handshake mit dem Ziel
zu ändern. Falls nicht angegeben, wird der Servername aus dem Handshake mit
dem Listener verwendet.
-tv <defualt|tls12|tls11|ssl3|tls1|ssl2>, --tls-version <defualt|tls12|tls11|ssl3|tls1|ssl2>
Falls gewünscht, kann eine bestimmte TLS-Version angegeben werden.
-ci <ciphers>, --ciphers <ciphers>
Legt andere Ciphers als die Python-Standardwerte für den TLS-Handshake fest.
Es sollte eine Zeichenkette im OpenSSL-Cipher-List-Format sein
(https://www.openssl.org/docs/manmaster/man1/ciphers.html).
Zum Ausgeben von SSL-(Pre-)Master-Secrets in eine Datei setzen Sie die Umgebungsvariable
SSLKEYLOGFILE mit einem Dateipfad. Nützlich für Wireshark.
Die Kommunikation muss zum Listener geleitet werden, um beliebige Protokolle abzufangen. Die Art und Weise hängt davon ab, wie der Client arbeitet. Manchmal verwendet es eine DNS-Adresse, und das Ändern der Hosts-Datei reicht aus, um die Listener-Adresse aufzulösen. Wenn die Adresse fest codiert ist, müssen kreativere Methoden angewendet werden (normalerweise einige Änderungen an der Routing-Tabelle, Patchen des Clients oder Verwendung einer VM und iptables).
Der HTTP-Interceptionserver kann ein Skript ausführen, das ihm mit dem Flag -s übergeben wird. Dieses Skript wird ausgeführt, wenn die HTTP-Anfragen empfangen werden. Die Antwort des HTTP-Interceptionservers ist die empfangene Anfrage nach der Ausführung des Skripts.
Wenn ein Proxy konfiguriert ist (z. B. Burp), erfolgen Modifikationen der Anfrage vor der Ausführung des Skripts und Modifikationen der Antwort danach. Änderungen an der Anfrage und der Antwort durch den Proxy oder das Modifikationsskript ändern die ursprüngliche Nachricht, bevor sie zum Ziel gelangt.
Das Skript muss die Funktionen handle_request(message) und handle_response(message) enthalten. Der HTTP-Interceptionserver ruft handle_request(message) auf, wenn die Nachricht vom Client zum Server geht, und handle_response(message), wenn die Nachricht vom Server zum Client geht.
Ein Beispiel für ein Skript, das ein Null-Byte am Ende der Nachricht hinzufügt:
def handle_request(message):
return message + b"\x00"
def handle_response(message):
# Beide Funktionen müssen eine Nachricht zurückgeben.
return message
Das Tool benötigt ein Server-Zertifikat und einen privaten Schlüssel für die SSL-Interception. Informationen zur Erstellung eines selbstsignierten Zertifikats oder eines Burp-Zertifikats finden Sie hier.
Wenn der Server ein bestimmtes Zertifikat erfordert, können dem Tool ein Zertifikat und ein Schlüssel bereitgestellt werden.
Die Demo unten zeigt, wie eine Verbindung mit MSSQL abgefangen wird (diese Demo wurde mit DVTA durchgeführt):
Die Verbindung zu MSSQL erfolgt über das TDS-Protokoll auf TCP. Die Authentifizierung selbst erfolgt mit TLS über dem TDS-Protokoll. Um diesen TLS-Prozess abzufangen, benötigen wir zwei notdürftige Modifikationsskripte.
demo_script.py:
from time import time
from struct import pack
from pathlib import Path
def handle_request(message):
if message.startswith(b"\x17\x03"):
return message
with open("msg_req" + str(time()), "wb") as f:
f.write(message[:8])
return message[8:]
def handle_response(message):
if message.startswith(b"\x17\x03"):
return message
path = Path(".")
try:
msg_res = min(i for i in path.iterdir() if i.name.startswith("msg_res"))
data = msg_res.read_bytes()
msg_res.unlink()
except ValueError:
data = b'\x12\x01\x00\x00\x00\x00\x01\x00'
return data[:2] + pack(">h", len(message)+8) + data[4:] + message
demo_script2.py:
from time import time
from struct import pack
from pathlib import Path
def handle_request(message):
if message.startswith(b"\x17\x03"):
return message
path = Path(".")
try:
msg_req = min(i for i in path.iterdir() if i.name.startswith("msg_req"))
data = msg_req.read_bytes()
msg_req.unlink()
except ValueError:
data = b'\x12\x01\x00\x00\x00\x00\x01\x00'
return data[:2] + pack(">h", len(message)+8) + data[4:] + message
def handle_response(message):
if message.startswith(b"\x17\x03"):
return message
with open("msg_res" + str(time()), "wb") as f:
f.write(message[:8])
return message[8:]
Wir werden mit diesen notdürftigen Skripten einen Teil der TLS-Kommunikation sehen, aber dann wird der Client fehlschlagen (weil wir mit diesen hackigen Skripten die TDS-Kommunikation außer dem TLS-Teil stark verändern).
Copyright (c) 2022 CyberArk Software Ltd. All rights reserved
Dieses Repository ist unter der Apache-2.0-Lizenz lizenziert – siehe LICENSE für weitere Details.