Skip to content

pe: null-terminate authenticode digest/thumbprint hex buffers#2221

Merged
plusvic merged 1 commit into
VirusTotal:masterfrom
munzzyy:fix-authenticode-digest-null-term
Jul 6, 2026
Merged

pe: null-terminate authenticode digest/thumbprint hex buffers#2221
plusvic merged 1 commit into
VirusTotal:masterfrom
munzzyy:fix-authenticode-digest-null-term

Conversation

@munzzyy

@munzzyy munzzyy commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #2176.

All the hex-digest buffers in _process_authenticode() (authenticode digest, file_digest, signer digest, countersignature digest) and thumbprint_ascii in the write_certificate macro are allocated with room for a trailing null (len * 2 + 1), but the sprintf loop that fills them only ever writes len * 2 hex characters. Nothing ever sets that last byte, so yr_set_string() calling strlen() on the buffer reads past the hex digits into whatever uninitialized stack or heap byte happens to follow, until it hits a zero.

This same bug shape was already fixed correctly elsewhere in this file: pe_get_imphash() sets digest_ascii[YR_MD5_LEN * 2] = '\0' right after its loop. This PR does the same thing at the five spots that were missing it.

This lines up with the failure in #2176 (test-pe.c, the pe.signatures[0].thumbprint check failing on Rocky 9 but not Rocky 8) — thumbprint comes from exactly the buffer this touches, and reading uninitialized memory would naturally be sensitive to stack layout/compiler version, which is what varies between those two.

Didn't have a build toolchain available to run make check locally, so this is verified by code inspection: traced every sprintf-into-hex-buffer site in the file, confirmed each buffer's allocation size already reserves the byte, and matched the fix to the existing correct pattern used for imphash three times over. No behavior change to anything except cases where the buffer wasn't already accidentally null-terminated by chance.

digest_ascii buffers in _process_authenticode() and thumbprint_ascii in
write_certificate() are filled by a sprintf loop that writes exactly
len*2 hex chars but never sets the trailing byte, even though every
buffer is sized len*2+1 to hold it. yr_set_string() calls strlen() on
the result before copying, so the string used to actually run past the
hex digits into whatever uninitialized stack/heap byte follows until
it happens to hit a zero.

Same bug shape already fixed correctly for imphash in this same file
(pe_get_imphash sets digest_ascii[YR_MD5_LEN * 2] = '\''\0'\'' after its
loop) - this applies the same fix to the four authenticode digest sites
and the certificate thumbprint site.

Fixes VirusTotal#2176. The failing test (test-pe.c, pe.signatures[0].thumbprint
compared against a fixed hex string) reads one of the buffers this
touches, which explains the platform/compiler-dependent flakiness
reported there (stack contents differ across Rocky 8 vs 9).
@plusvic
plusvic merged commit fa372eb into VirusTotal:master Jul 6, 2026
14 checks passed
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.

Test failure when building Yara 4.5.4 on Rocky 9 - tests/test-pe.c:292

2 participants