Skip to content

Fix stack-based buffer overflow in Embedder::embed (Security Patch)#21

Open
ErikDervishi03 wants to merge 2 commits into
StegHigh:masterfrom
ErikDervishi03:master
Open

Fix stack-based buffer overflow in Embedder::embed (Security Patch)#21
ErikDervishi03 wants to merge 2 commits into
StegHigh:masterfrom
ErikDervishi03:master

Conversation

@ErikDervishi03

Copy link
Copy Markdown

This PR resolves a critical stack-based buffer overflow vulnerability in src/Embedder.cc.

The Issue: The Embedder::embed() function previously used sprintf to format a status message into a fixed-size stack buffer (char buf[200]) without bounds checking.

// Vulnerable Code
sprintf(buf, _("embedding %s in %s..."), embstring.c_str(), cvrstring.c_str());

Providing a combined directory and filename length exceeding 200 bytes caused a stack overflow, overwriting the return address. This vulnerability could be exploited to achieve Remote Code Execution (RCE) or Information Disclosure (leaking sensitive payload data from the heap).

The Fix: Replaced the unsafe sprintf call with snprintf, restricting the output to the buffer's size (sizeof(buf)). This ensures that long file paths are truncated safely instead of corrupting the stack.

Type of Change:

[x] Bug fix (non-breaking change which fixes an issue)
[x] Security Patch

Verification / Testing

I have verified this fix using a Proof of Concept (PoC) exploit that previously crashed the application.

Before Fix: Running steghide embed with a 250+ byte file path caused a Segmentation fault (SIGSEGV) and corrupted CPU registers (rbx, rip overwritten with 0x41).

After Fix: The application handles the long path gracefully without crashing. The status message is strictly truncated to fit the 200-byte buffer.

Reproducer (Bash):

Setup

LONG_DIR=$(python3 -c "print('A' * 200)")
mkdir -p "$LONG_DIR"
LONG_NAME=$(python3 -c "print('A' * 200 + '.wav')")
touch "$LONG_DIR/$LONG_NAME"
echo "data" > secret.txt

Test Command

./src/steghide embed -cf "$LONG_DIR/$LONG_NAME" -ef secret.txt -p pass

Checklist:

[x] Code compiles successfully.
[x] The unsafe sprintf has been replaced with snprintf.
[x] Verified that the application no longer crashes with long inputs.

@ErikDervishi03

Copy link
Copy Markdown
Author

Executive Summary A Denial of Service (DoS) vulnerability was identified in steghide v0.5.1. The application fails to validate BMP header dimensions (Width and Height) before memory allocation. This allows an attacker to trigger a massive memory allocation (e.g., >6 GB) using a tiny malformed file (0000016:0000060 bytes), resulting in a SIGABRT crash due to std::bad_alloc. Status: Vulnerability Confirmed & Patched.

Technical Analysis

Component: src/BmpFile.cc, function BmpFile::readdata.

Root Cause: The BitmapData.resize() method is called with a size calculated directly from the file header without upper-bound checks.

Risk:

64-bit: Memory Exhaustion (DoS).

32-bit: Integer Overflow leading to Heap Buffer Overflow (Potential RCE).

Proof of Concept (PoC) The following Python script generates dos.bmp, which claims a resolution of 50,000x50,000 pixels.
import struct

filename = "dos.bmp"
with open(filename, "wb") as f:

BMP Header + DIB Header (claiming 50k x 50k pixels)
header = b'BM' + b'\x00'*8 + struct.pack('<I', 54)
dib = struct.pack('<IIIHHIIIIII', 40, 50000, 50000, 1, 24, 0, 0, 0, 0, 0, 0)
f.write(header + dib)
print(f"[+] Created {filename}. Run: steghide info {filename}")

The Solution (Patch) I implemented a sanity check in src/BmpFile.cc that validates the total required memory before allocation. The patch uses unsigned long long to prevent integer overflows during the check itself.
Applied Fix:
// --- SECURITY PATCH ---
unsigned long long total_bytes_needed = (unsigned long long)height (unsigned long long)linelength;
const unsigned long long MAX_ALLOWED_BYTES = 500ULL 1024ULL * 1024ULL; // 500 MB Limit

if (total_bytes_needed > MAX_ALLOWED_BYTES) {
fprintf(stderr, "[!] SECURITY ERROR: BMP requires %llu bytes. Limit is %llu bytes.\n", total_bytes_needed, MAX_ALLOWED_BYTES);
exit(1);
}
// --- END PATCH ---

BitmapData.resize (height * linelength) ;
Verification After recompiling steghide with the patch, executing the PoC no longer results in a crash/abort. Instead, the application handles the error gracefully:
[!] SECURITY ERROR: BMP requires 7499900000 bytes. Limit is 524288000 bytes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant