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.

FeedsKontaktDatenschutz© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
Tenda-Router-VR-and-Exploit — Beschreibung für Tenda AC15 Router Firmware-Neuhosting und Remote-Befehlsausführung (CVE-2020-10987) Exploit-Reproduktion. | Kitploit
Tools/GitHubGitHub/jaden-bowers/tenda-router-vr-and-exploit
Embedded-System-SicherheitIoT-SicherheitSchwachstellenanalyseExploitationReverse EngineeringPenetrationstestsHardware-SicherheitLernen & BildungFirmware-Analyse

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen
Binary-Exploitation
Labs & Praxis
GitHubjaden-bowers/tenda-router-vr-and-exploit

Tenda-Router-VR-and-Exploit

Beschreibung für Tenda AC15 Router Firmware-Neuhosting und Remote-Befehlsausführung (CVE-2020-10987) Exploit-Reproduktion.

Repository anzeigen
128vor 11 MonatenNoch nicht geprüft

Tenda-Router-VR-and-Exploit

Diese Anleitung zeigt genau, wie ich den Webserver der AC15 (V15.03.05.19) Firmware mit QEMU emuliert, ihn vom Host-Browser aus erreichbar gemacht und den anfälligen /goform/setUsbUnload-Handler (CVE-2020-10987) genutzt habe, um eine Befehlseinführung im emulierten rootfs zu erreichen.


Übersicht

  • Das squashfs-Dateisystem aus dem Firmware-Image extrahieren (oder in unserem Fall beschaffen) und mit dem Reverse Engineering beginnen
  • Ein Debian-armhf-Gast unter qemu-system-arm aufsetzen
  • Netzwerk des Gasts und Portweiterleitung zum emulierten Router einrichten
  • Unser Boot-Skript erstellen
  • Den emulierten Router ausnutzen

Extrahieren des Dateisystems

Zuerst müssen wir unser Firmware-Image besorgen. Ich konnte den Download des Images für AC15 V15.03.05.19 nicht finden, jedoch fand ich ein GitHub-Repository mit dem bereits extrahierten squashfs-Dateisystem. Wenn wir die richtige Image-Datei hätten, könnten wir sie mit binwalk extrahieren, etwa so:``` user@computer $ binwalk -e AC15_V15.03.05.19.bin

DECIMAL HEXADECIMAL DESCRIPTION

64 0x40 TRX firmware header, little endian, image size: 6778880 bytes, CRC32: 0x80AD82D6, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x1A488C, rootfs offset: 0x0 92 0x5C LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 4177792 bytes 1722572 0x1A48CC Squashfs filesystem, little endian, version 4.0, compression:xz, size: 5052332 bytes, 848 inodes, blocksize: 131072 bytes, created: 2017-04-19 16:18:08

user@computer $ cd _AC15_V15.03.05.19.bin.extracted

Da wir nicht die richtige Image-Datei haben, aber ein Repository mit dem bereits extrahierten Dateisystem, können wir einfach das Repository klonen.```
git clone https://github.com/lapinpt/Tenda-AC15-Firmware-V15.03.05.19-9061

Ich habe ein Verzeichnis namens VR erstellt und dieses Repository darin geklont. Mein rootfs befindet sich unter $HOME/VR/Tenda-AC15-Firmware-V15.03.05.19-9061/rootfs

Großartig, jetzt haben wir unsere AC15 V15.03.05.19-Firmware. Lassen Sie uns mit dem Reverse Engineering fortfahren, um zu sehen, was los ist.

Reverse Engineering

Ich werde Ghidra 11.4.2 für mein Reverse Engineering verwenden. Navigieren wir zu unserer Zielbinärdatei hier rootfs/bin/httpd und laden sie in Ghidra. Wenn wir zur Funktion formsetUsbUnload gehen, können wir sehen,```C uVar1 = FUN_0002bd4c(param_1,"deviceName",&DAT_000f4bdc); doSystemCmd("cfm post netctrl %d?op=%d,string_info=%s",0x33,3,uVar1); FUN_0002c6cc(param_1,"HTTP/1.0 200 OK\r\n\r\n"); FUN_0002c6cc(param_1,"{"errCode":0}"); FUN_0002cc14(param_1,200); return;

Dies ist die Schwachstelle. Der Parameter `deviceName` wird direkt an `doSystemCmd` übergeben, sodass wir beliebige Befehle senden können.

Da wir nun diese Firmware mit qemu und nicht mit der ursprünglichen Router-Hardware neu hosten werden, werden einige Programme versuchen, Geräte zu erreichen, die nicht vorhanden sind, und unseren Startvorgang zum Absturz bringen.
Da unser Ziel darin besteht, den Webserver (`httpd`) auszunutzen, habe ich mich nur darauf konzentriert, diese Binärdatei neu zu hosten, nicht den gesamten Startvorgang (`/rootfs/etc_ro/init.d/rcS`). _Im Nachhinein bin ich mir nicht sicher, ob das die richtige Entscheidung war_

Als ich mir also `rcS` ansah, wollte ich alles finden, was `rcS` tun könnte, was `httpd` benötigen würde. Gegen Ende der Datei sehen wir:```bash
cfmd &
echo '' > /proc/sys/kernel/hotplug
udevd &
logserver &

rcS startet cfmd im Hintergrund, kurz bevor der Rest des Stacks hochfährt. Nach weiterer Recherche und der Untersuchung, wie die angreifbare Funktion den Befehl sendet, bin ich zu dem Schluss gekommen, dass

  • httpd einen cfm post erstellt
  • Dann der cfm-Client mit cfmd über einen UNIX domain socket (z. B. /var/cfm_socket) kommuniziert

In der InitServer-Routine in cfmd können wir sehen```C unlink("/var/cfm_socket"); strncpy(sa_unix.sun_path, "/var/cfm_socket", ...); bind(fd, (sockaddr*)&sa_unix, 0x6e); listen(fd, 5);

Es erstellt einen UIX-Socket und horcht.
Insgesamt funktioniert es so, dass der Handler von jedem Client einen festen 0x7e0-Byte-Frame liest (`RecvMsg`/`SendMsg`). Die ersten 4 Bytes sind ein Befehlscode; dann gibt es einen 512-Byte-Schlüsselpuffer und einen 1500-Byte-Wertpuffer (die Größen der Stack-Objekte sind im Handler ersichtlich). Es schaltet auf den Opcode und antwortet mit einem ACK-Code:
- `2` -> Get: `GetCfmValue(key, value)` dann Antwortcode `3`
- `0` -> Set: `SetCfmValue(key, value)` dann Antwortcode `1`
- `0x11` -> Unset: `UnSetCfmValue(key)` dann Antwortcode `0x12`
- `10` -> Commit: `SaveCfm2Flash()` dann Antwort `0x10` (OK) oder `0xB` (Fehler)

Um `cfmd` zu emulieren, habe ich ein kurzes Skript `cfm_stub` erstellt.```C
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

#define SOCK_PATH "/var/cfm_socket"

// minimal UNIX-domain server that httpd expects.
// Replies with an IP string when it sees the key it asks for.
int main(void) {
  int s = socket(AF_UNIX, SOCK_STREAM, 0);
  struct sockaddr_un addr = {0};
  if (s < 0) { perror("socket"); return 1; }
  unlink(SOCK_PATH);
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path)-1);
  if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; }
  if (listen(s, 5) < 0) { perror("listen"); return 1; }

  for (;;) {
    int c = accept(s, NULL, NULL);
    if (c < 0) { if (errno==EINTR) continue; perror("accept"); break; }
    char buf[1024]; ssize_t n = read(c, buf, sizeof(buf));
    if (n > 0) {
      // In some builds httpd asks for "lan.webiplansslen" etc.
      // Any non-empty reply that looks like an IP keeps init happy.
      const char *reply = "192.168.0.1";
      write(c, reply, strlen(reply));
    }
    close(c);
  }
  close(s);
  return 0;
}

Ich werde zeigen, wie man dies nach dem nächsten Teil kompiliert.

Die nächste Hilfsdatei ist hooks.so. Es gibt einige Funktionen, die in httpd und cfm verwendet werden und versuchen, mit nicht vorhandener Hardware zu interagieren. Im Folgenden wird angenommen, was unser Programm beim Start voraussetzt:

  • Flash- und MTD-Partitionen existieren und sind mountbar.
  • Ein NVRAM-Gerät existiert (/dev/nvram) und gibt sinnvolle Standardwerte zurück.
  • Diverse Plattformroutinen gelingen (Layer-7-Einstellungslader, RF-Leistungswiederherstellung usw.).

Die folgenden Funktionen werden zum Problem, und daher müssen wir mit LD_PRELOAD=/hooks.so patchen.

  • get_flash_type() -> wenn es 4 zurückgibt, nimmt der Code einen dateibasierten Pfad (cfm_file_init), andernfalls versucht er, mit MTD zu kommunizieren (was wir nicht haben).
  • get_cfm_blk_size_from_cache() (und/oder die Variante j_get_cfm_blk_size_from_cache) wird für die Konfigurationsblockgröße konsultiert.
  • Aufrufe an Broadcom-NVRAM-Shims (bcm_nvram_get) dürfen nicht fehlschlagen, sonst nimmt der Stack an, „NVRAM zerstört“ und geht in die Wiederherstellungs-/Neustartlogik über.
  • Zusätzliche Routinen wie load_l7setting_file() und restore_power() sollten erfolgreich sein, greifen aber auf nicht vorhandene Hardware/Dateien zu.

Hier ist unser hooks.c. Dank an azeria-labs für das Original.```C #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <dlfcn.h> #include <string.h>

int j_get_cfm_blk_size_from_cache(const int i) { puts("j_get_cfm_blk_size_from_cache called....\n"); return 0x20000; // 128 KiB block — what the file path expects }

int get_flash_type() { puts("get_flash_type called....\n"); return 4; // force file-backed CFM init, not MTD }

Tool herunterladen