Fix heap-buffer-overflow READ in LightPcapNg parse_by_block_type#2160
Open
trailfork wants to merge 1 commit into
Open
Fix heap-buffer-overflow READ in LightPcapNg parse_by_block_type#2160trailfork wants to merge 1 commit into
trailfork wants to merge 1 commit into
Conversation
Signed-off-by: trailfork <tyler.rolling@trailofbits.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
parse_by_block_typein the bundled LightPcapNg(
3rdParty/LightPcapNg/LightPcapNg/src/light_pcapng.c) reads each block'smandatory fixed header with no minimum-size check.
light_read_record(
light_pcapng.c:353) sizes the block body from the attacker-controlledblock_total_lengthand allocates exactly that many bytes:parse_by_block_typethen reads each block type's fixed header out of thatbuffer without verifying it is large enough. With
block_total_length == 16,bytesToRead == 4, so the second 4-byte field read runs one word past theallocation — e.g. the Section Header Block
versionfield(
light_pcapng.c:115, afterbyteorder_magic) or the Interface DescriptionBlock
snapshot_lengthfield (light_pcapng.c:140, afterlink_type/reserved). A crafted.pcapng/.zstd/.zstopened viaPcapNgFileReaderDevice(the standardIFileReaderDevice::getReader(path)->open()path) triggers a heap-buffer-overflow READ.
Impact
Attack surface: file parsing only — not network-reachable. The faulting
fields (SHB
version, IDBsnapshot_length,block_total_length) are pcapngcontainer metadata emitted by the capture writer, not captured wire data.
Reachable through the library's default consumption pattern:
IFileReaderDevice::getReaderdispatches on file extension, so any.pcapng/.zstd/.zstpath is routed to the vulnerable reader, and at leasteight shipped examples use
getReader(path)->open()(PcapPrinter, PcapSplitter,PcapSearch, HttpAnalyzer, TcpReassembly, SSLAnalyzer, TLSFingerprinting,
IPFragUtil/IPDefragUtil).
Trigger: the victim opens or scans a crafted capture file.
PcapPrinteropens asingle CLI-named file (crash during
open(), matchingpoc.pcapng);PcapSearchrecursively sweeps every capture under a-ddirectory with noper-file interaction (the unattended-ingest case).
No disclosure: the over-read is read-only with no write primitive. The over-read
value is consumed internally — it becomes the parsed SHB
version/ IDBsnapshot_length, surfaced to callers only as opaque 64-bit numbers — and isnever returned to the attacker on an observable channel. There is no demonstrated
information-disclosure primitive and no path to memory-corruption RCE.
Affected versions: present at
masterHEAD (commitaf83983b) and at theoriginally reported commit
12cdbd5b. The vendored LightPcapNg sources under3rdParty/are the only copy on the read path; the seladb LightPcapNg fork theyderive from has had no upstream maintainer since 2017, so the fix is proposed
here, against PcapPlusPlus.
Severity: Medium — denial of service (crash on an unmapped page; deterministic
abort under ASan / hardened builds). Read-only, no write, no disclosure.
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H(5.5)interaction (e.g. a recursive directory sweep like the
PcapSearchexample):CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H(7.5)Reproduction
Two minimal inputs exercise the two crash paths (base64 below):
poc.pcapng(16 bytes) — undersized Section Header Block; crashes duringopen()->light_pcapng_open_read->light_read_record->parse_by_block_type(SHB, line 115).evidence_bundle.bin(44 bytes) — valid SHB followed by an undersizedInterface Description Block; crashes later via
getNextPackets->getNextPacketInternal->light_read_record->parse_by_block_type(IDB, line 140).Build the pcapng fuzz target with ASan and run each input:
The fuzz target links libFuzzer (
-fsanitize=fuzzer), which ships with thedefault clang on Linux. On macOS, Apple's clang lacks libFuzzer: install
Homebrew LLVM (
brew install llvm) and add-DCMAKE_C_COMPILER="$(brew --prefix llvm)/bin/clang" -DCMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++"to the
cmakeinvocation above.Expected:
heap-buffer-overflow ... READ of size 4,0 bytes after 4-byte region, allocated inlight_read_record.To recreate the input files:
Fix
Reject blocks whose body is too small to hold the mandatory fixed fields, per
block type, before parsing them. The patch derives
body_size = block_total_length - 12(mirroringlight_read_record'sbytesToRead) at thetop of
parse_by_block_typeand validates it against each block type'sfixed-header size (16 for SHB, 8 for IDB, 20 for EPB, 4 for SPB, 12 for CUSTOM)
before reading any field. On an insufficient body the case allocates a
zero-initialised header struct (and, where applicable, an empty option) and
returns, so downstream consumers read a well-formed but empty record instead of
dereferencing NULL. After the fix, both inputs are rejected gracefully
("Couldn't read the first packet in the file") with no ASan report. See the
commit in this PR.
Credit
Found by Claude during an automated review conducted by Anthropic; manually
validated and patched by Trail of Bits. Reference: ANT-2026-01245.