
LINKSYS AC1900 EA7500v3 IGD UPnP Stack-Pufferüberlauf-Schwachstelle für Remote-Code-Ausführung
Diese Schwachstelle ermöglicht es angrenzenden Angreifern im Netzwerk, auf betroffenen Installationen von LINKSYS EA7500-Routern beliebigen Code auszuführen. Für die Ausnutzung dieser Schwachstelle ist keine Authentifizierung erforderlich.
Die spezifische Schwachstelle liegt in der Verarbeitung von HTTP-Anforderungsdaten an den IGD UPnP-Dienst. Beim Parsen des Inhalts einer vom Benutzer bereitgestellten Variable einer bestimmten SOAP UPnP Action Request-Anfrage validiert der Prozess die Länge der vom Benutzer bereitgestellten Daten nicht ordnungsgemäß, bevor er sie in einen Stack-Puffer fester Länge kopiert. Ein Angreifer kann diese Schwachstelle ausnutzen, um Code im Kontext von root auszuführen.
Produkt/Firmware: Linksys EA7500 Firmware ALLE VERSIONEN, einschließlich Ver.3.0.1.207964 - Auch andere Routermodelle und Firmware-Versionen, die diese Binärdatei verwenden, sind betroffen.
Die UPnP-IGD-Dienstbinärdatei befindet sich unter /usr/sbin/IGD und läuft standardmäßig auf Port 49152. Dieser Dienst stellt die IGDdevicedesc.xml UPnP-XML-Beschreibungsdatei bereit, die mehrere Funktionen detailliert beschreibt, die mit HTTP-Anfragen mit einem XML-Body aufgerufen werden können.
Eine dieser Funktionen ist SetDefaultConnectionService. Diese Funktion erfordert eine Variable vom Typ String. Wenn die Funktion SetDefaultConnectionService aufgerufen und ausgeführt wird, validiert das Programm die Länge der vom Benutzer bereitgestellten Variable nicht, bevor ein strncpy-Aufruf mit diesem Puffer durchgeführt wird.
Sowohl die Quelladresse als auch die Kopiergrößenvariablen des strncpy-Aufrufs werden vom Benutzer gesteuert, wobei die Kopiergröße der Länge der vom Benutzer bereitgestellten Variable entspricht.
Die Daten werden dann in einen festen Puffer von 184 Bytes kopiert, was zu einer Stack-Pufferüberlauf-Schwachstelle führt.
Die Funktion SetDefaultConnectionService wird als _set_connection_type bezeichnet. Die Funktion beginnt mit der Initialisierung eines 184-Byte-Puffers und erhält dann einen Zeiger auf den Puffer, der die vom Benutzer bereitgestellte String-Variable aus der Anfrage enthält, sofern diese nicht NULL ist.
Dies geschieht durch Aufruf von PAL_xml_node_GetFirstbyName und dann PAL_xml_node_get_value. Siehe Code unten:
int _set_connection_type(int **param_1)
{
int iVar1;
char *var_value;
size_t var_value_length;
undefined uVar2;
undefined1 *puVar3;
char **ppcVar4;
undefined4 *puVar5;
char *pcVar6;
int *piVar7;
char acStack_d4 [184]; -----> /* Initializing 184-byte buffer */
memset(acStack_d4,0,0xb4);
iVar1 = PAL_xml_node_GetFirstbyName((*param_1)[0xf0],"NewConnectionType",0); -----> /* iVar1 now points to the user-supplied value */
if ((iVar1 != 0) && (var_value = (char *)PAL_xml_node_get_value(), var_value != (char *)0x0)) { -----> /* Ensures the user-supplied value is not empty and obtains a pointer to it */
...
Später in derselben Funktion wird ein strlen-Aufruf durchgeführt, um die Größe der vom Benutzer bereitgestellten Zeichenfolge plus einen statischen Offset von 0x174 zu erhalten. Die anfällige Bedingung wird im folgenden strncpy-Aufruf ausgelöst, bei dem das Zielargument die Adresse des neu initialisierten 184-Byte-Puffers ist, die Quelle der Zeiger auf die vom Benutzer bereitgestellte Zeichenfolge und die Größe des Kopiervorgangs die Größe der vom Benutzer bereitgestellten Zeichenfolge ist, die vom strlen-Aufruf plus einem statischen Offset von 0x174 zurückgegeben wird. Dies führt zu einer Pufferüberlauf-Schwachstelle, da sowohl die Quelladresse als auch die Größenvariablen vom Benutzer kontrolliert werden und keine Größenvalidierungsprüfungen durchgeführt werden. Siehe Code unten:
int _set_connection_type(int **param_1)
{
...
var_value_length = strlen((char *)(iVar1 + 0x174)); ----> /* iVar1 is a pointer to the user supplied string */
strncpy(acStack_d4,(char *)(iVar1 + 0x174),var_value_length + 1); ----> /* Vulnerable strncpy call */
...
Der Offset zum Überschreiben einer Rücksprungadresse einer Funktion auf dem Stack beträgt 276 Bytes. Die nächsten 4 Bytes können genutzt werden, um die Ausführung auf eine beliebige Adresse umzuleiten und so den Kontrollfluss des Programms zu übernehmen.
Verwenden Sie eine sicherere String-Kopierfunktion: Anstelle von strncpy, das keine Nullterminierung des Zielpuffers garantiert, kann eine sicherere String-Kopierfunktion wie strncpy_s oder memcpy_s verwendet werden. Diese Funktionen stellen sicher, dass der Zielpuffer immer nullterminiert ist und erlauben nicht das Kopieren von mehr Daten, als der Puffer aufnehmen kann.
Eingabevalidierung: Validieren Sie Benutzereingaben, um sicherzustellen, dass sie die Größe des Zielpuffers nicht überschreiten. Wenn die Eingabe länger als die Puffergröße ist, lehnen Sie sie entweder ab oder kürzen Sie sie, damit sie in den Puffer passt.
Verwenden Sie einen dynamisch zugewiesenen Puffer: Weisen Sie Speicher für den Zielpuffer dynamisch zu, anstatt einen Stack-Puffer fester Größe zu verwenden. Dieser Ansatz ermöglicht es, die Puffergröße entsprechend der Eingabedatengröße anzupassen. (Nicht empfohlen für ein System mit begrenzten Ressourcen)
PoC-Ausführung: python poc.py 192.168.1.1 49152
Software-Download-Link: https://support.linksys.com/kb/article/559-en/ (Firmware-Version Ver. 3.0.1.207964)
gdbserver-7.7.1-armel-eabi5-v1-sysv verwendet, die hier verfügbar ist: https://github.com/stayliv3/gdb-static-cross/tree/master/prebuilt).pkill IGD, um die Binärdatei zu beenden, und starten Sie sie dann mit ./gdbserver :1337 /usr/sbin/IGD neu. Die folgende .gdbinit-Datei kann verwendet werden, um eine stabile Debugging-Sitzung zu initiieren:> set follow-fork-mode child
> set detach-on-fork off
> target remote 192.168.1.1:1337
> c