Skip to content
KitploitKITPLOIT
ToolsBlog
Log in
Einreichen
ToolsBlog
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-40634 — Exploit für einen Stack-basierten Pufferüberlauf, der im conn-indicator-Binärprogramm im TP-Link Archer AX50 Router gefunden wurde | Kitploit
Tools/GitHubGitHub/hacefresko/cve-2025-40634
Embedded-System-SicherheitIoT-SicherheitExploitationFuzzingPenetrationstestsHardware-SicherheitRemote-Access-ToolBinary-Exploitation
GitHubhacefresko/cve-2025-40634

CVE-2025-40634

Exploit für einen Stack-basierten Pufferüberlauf, der im conn-indicator-Binärprogramm im TP-Link Archer AX50 Router gefunden wurde

Repository anzeigen
31812vor 11 MonatenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2025-40634

Der TP-Link Archer AX50 Router ist anfällig für einen stack-basierten Pufferüberlauf in seiner Firmware Version 1.0.14 Build 20240108 rel.42655(4555), was zu Remote-Code-Ausführung sowohl im LAN als auch im WAN führt. Diese Schwachstelle hat dieselbe Ursache wie CVE-2020-10881, die vom Flashback-Team gefunden und in ihrer Videoserie darüber ausführlich beschrieben wurde (siehe Referenzen). Der Ausnutzungsprozess unterscheidet sich jedoch etwas, sodass ein neuer Exploit geschrieben werden musste.

Ursache

Diese Schwachstelle tritt in der Binärdatei conn-indicator auf, die dafür zuständig ist, zu überprüfen, ob der Router mit dem Internet verbunden ist, indem sie regelmäßig DNS-Anfragen sendet und auf deren Antworten an einem zufälligen UDP-Port zwischen 32000 und 61000 lauscht.

Die Funktion, die diese DNS-Antwortpakete empfängt und zuerst verarbeitet, ist TPDns_RecvAndResolve(), die sich bei 0x00405e3c befindet. Beim Empfangen eines Pakets mit recvfrom wird es in buf gespeichert, das eine Größe von 2960 Bytes hat. Dann wird geprüft, ob der Rückgabecode korrekt ist (RCODE == 0), und die Anzahl der Fragen und Antworten im Paket (QDCOUNT und ANCOUNT) wird überprüft. Um die Antworten zu verarbeiten, wird process_resolved_IP() aufgerufen, dem ein Zeiger auf buf, answer_ptr (ein Zeiger auf die Position der Antworten im Paket innerhalb von buf), die Anzahl der Antworten (ANCOUNT) und weitere Flags übergeben werden:

undefined4 * TPDns_RecvAndResolve(int socket,void *param_2,int param_3){
  
  [...]
  
  byte buf [2960];
  
  [...]
  
      while( true ) {
        recv_bytes = recvfrom(socket,buf + total_recv_bytes,0xb90 - total_recv_bytes,0,&sStack_50,
                              local_38);
        piVar2 = __errno_location();
        if (recv_bytes == 0) goto RECV_ERROR;
        if (recv_bytes < 0) break;
        total_recv_bytes = total_recv_bytes + recv_bytes;
        if (2959 < total_recv_bytes) goto PROCESS_DNS_RESP;
      }

  [...]

                    /* Check that ANCOUNT is not 0 (answer contains at least one domain) */
          puVar5 = (undefined4 *)0x0;
          if (buf._6_2_ != 0) {
            local_40 = 0;
            puVar5 = process_resolved_IP(buf,answer_ptr,(uint)buf._6_2_,&local_3c,&local_40);
            answer_ptr = answer_ptr + local_40;
          }

  [...]

Die Funktion process_resolved_IP(), bei 0x00405818, durchläuft jede Antwort und ruft für jede DNS_answer_parser() auf. Ihr werden als Argumente derselbe Zeiger auf buf, answer (ein Zeiger auf die aktuelle Antwort, die innerhalb des ursprünglichen Pakets in buf geparst wird) und ein Zeiger auf current_answer (ein Puffer der Größe 256) übergeben:

undefined4 * process_resolved_IP(byte *buf,byte *answer_ptr,uint ANCOUNT,undefined4 *param_4,int *param_5){
  
  [...]
  
  byte current_answer [256];
  ushort answer_flags [5];
  
  i = 0;
  puVar9 = (undefined4 *)0x0;
  puVar7 = (undefined4 *)0x0;
  answer = answer_ptr;
  do {
                    /* Check if all answers have been parsed already */
    if (i == ANCOUNT) {
      if (param_4 != (undefined4 *)0x0) {
        *param_4 = puVar7;
      }
      if (param_5 != (int *)0x0) {
        *param_5 = (int)answer - (int)answer_ptr;
      }
      return puVar9;
    }
    bytes_processed = DNS_answer_parser(buf,answer,current_answer,1);
    memcpy(answer_flags,answer + bytes_processed,10);
    uVar1 = answer_flags._4_4_;
    bytes_processed = bytes_processed + 10;
    uVar6 = (uint)answer_flags[4];
    uVar8 = (uint)answer_flags[0];
    if (uVar8 == 2) {
LAB_00405924:
      DNS_answer_parser(buf,answer + bytes_processed,abStack_240,1);
    }
    else if (uVar8 < 3) {
      pbVar2 = answer + bytes_processed;
      if (uVar8 == 1) {
        sprintf((char *)abStack_240,"%u.%u.%u.%u",(uint)*pbVar2,(uint)pbVar2[1],(uint)pbVar2[2],
                (uint)pbVar2[3]);
      }
    }
    else {
      if (uVar8 == 5) goto LAB_00405924;
      if (uVar8 == 0x1c) {
        inet_ntop(10,answer,(char *)abStack_240,0xff);
      }
    }
    answer = answer + bytes_processed + uVar6;
  
  [...]

    i = i + 1;
  } while( true );
}

Die Funktion DNS_answer_parser(), bei 0x004054e0, parst jede Antwort einzeln, die aus einem Domainnamen in der Form <len><domain><len><domain>... besteht. Als Beispiel würde example.com als 7example3com dargestellt werden. Die Funktion durchläuft jedes Paar <len><domain>, das den Domainnamen in der Antwort bildet, und prüft, ob <len < 63 ist (domain_name & 0xc0 != 0). Dann ruft sie memcpy auf und kopiert <len> Bytes von answer, die <domain> entsprechen, in current_answer. Sie wiederholt den Vorgang für das nächste Paar <len><domain> im Domainnamen.

int DNS_answer_parser(byte *buf,byte *answer,byte *current_answer,int flag){
  int iVar1;
  uint __n;
  int iVar2;
  uint uVar3;
  ushort flag_and_offset;
  byte domain_name;
  
  iVar2 = 0;
  do {
    domain_name = *answer;
    __n = (uint)domain_name;
    iVar1 = 1;
    if (__n == 0) {
      *current_answer = 0;
LAB_004055b0:
      return iVar2 + iVar1;
    }
                    /* Check if compression mode is used */
    if ((domain_name & 0xc0) != 0) {
      flag_and_offset = CONCAT11(domain_name,answer[1]);
      DNS_answer_parser(buf,buf + (flag_and_offset & 0x3fff),current_answer,flag);
      iVar1 = 2;
      goto LAB_004055b0;
    }
    uVar3 = __n + 1;
    if (flag == 0) {
      *current_answer = '.';
      memcpy(current_answer + 1,answer + 1,__n);
      __n = uVar3;
    }
    else {
      memcpy(current_answer,answer + 1,__n);
    }
    answer = answer + uVar3;
    current_answer = current_answer + __n;
    iVar2 = iVar2 + uVar3;
    flag = 0;
  } while( true );
}

Da current_answer nur 256 Byte lang ist, kann ein Angreifer ein Paket mit einer Antwort senden, die einen ausreichend großen Domainnamen enthält, um den Puffer zu überlaufen.

Ausnutzung

Der Ausnutzungsprozess ist dem vom Flashback-Team in ihrer Videoserie zu CVE-2020-10881 erläuterten (siehe Referenzen) sehr ähnlich, mit einigen wesentlichen Unterschieden:

  1. Die Adressen sind nicht dieselben.
  2. Der Code ist nicht exakt derselbe, daher waren auch die Offsets und die Größe des Stacks an manchen Stellen unterschiedlich.
  3. Während das erste und das dritte ROP-Gadget identisch waren (nur an unterschiedlichen Adressen), unterscheidet sich das zweite in der move-Instruktion, da nun das Register, das nach $a2 als count-Argument für memcpy() verschoben wird, $s1 anstelle von $s0 ist.
  4. Die Variable i in process_resolved_IP() wird in $s5 statt in $s8 geladen. Wenn sie dann mit $v1 verglichen wird, stammt $v1 von $sp+616, was sehr weit vom überlaufenen Puffer entfernt ist, sodass der Stack weiter über die Antwort und den Befehl hinaus beschädigt werden musste.
  5. Das Dateisystem ist mit Ausnahme von /tmp schreibgeschützt, daher müssen alle Schreib- und Lesevorgänge dort erfolgen. Dies macht es unmöglich, dass die Reverse Shell weniger als 62 Zeichen lang ist. Um sie auf dem Ziel zu platzieren, muss sie von einem Webserver bereitgestellt und ein Befehl zum Herunterladen und Ausführen an das Ziel gesendet werden.

Trotzdem werde ich den gesamten Prozess erläutern.

Die Binärdatei conn-indicator hat NX aktiviert und ASLR ist bei allem außer sich selbst aktiviert:

Tool herunterladen