Infinite loop in ChunkHeader._load_strings / _load_templates on a crafted chunk (cyclic next_offset)
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 78/100
Direzione di ricerca
Leggi Evtx/Evtx.py, concentrandoti su ChunkHeader._load_strings e _load_templates e sui campi next_offset in Nodes.py. Inizia riproducendo, con un timeout, la prova di concetto fornita sugli offset ciclici, quindi verifica se entrambi i loader incontrano offset ripetuti. Il lavoro è completato quando le catene cicliche ritornano invece di bloccarsi e i test di regressione coprono i casi di ciclo.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
Evtx.Evtx.ChunkHeader._load_strings and ._load_templates walk each hash-bucket's on-disk next_offset chain with no guard against an offset that repeats. Because next_offset is read straight from the file, a crafted chunk whose string (or template) chain is cyclic — node A's next_offset points to B and B's points back to A — makes the while ofs > 0: loop run forever. Parsing an untrusted .evtx then hangs the process indefinitely (CWE-835, uncontrolled loop / denial of service).
This is separate from the length-0 records() loop fixed in #17; these two chunk loaders have no cycle/visited protection, and the problem is still present on master (c000744).
Affected code
Evtx/Evtx.py:
def _load_strings(self):
...
for i in range(64):
ofs = self.unpack_dword(0x80 + (i * 4))
while ofs > 0:
string_node = self.add_string(ofs)
ofs = string_node.next_offset() # dword read straight from the file
next_offset is a dword read directly from the buffer (Nodes.py, NameStringNode / TemplateNode: declare_field("dword", "next_offset", 0x0)), so an attacker fully controls it. _load_templates has the same shape — it checks a 0x0C token and a self-pointer per node, but two mutually-pointing templates satisfy both checks, so it can cycle too.
Reachability
Evtx(path).records() iterates chunks without verifying their checksums, and rendering a record reaches add_string → _load_strings. So a single crafted file passed to evtx_dump badfile.evtx hangs the process.
Proof of concept
Builds one 64 KB chunk whose first string bucket points at a two-node cycle (A↔B). The vulnerable call never returns, so run it under a timeout:
import struct
from Evtx.Evtx import ChunkHeader
buf = bytearray(0x10000)
buf[0:8] = b"ElfChnk\x00"
a, b = 0x200, 0x210
struct.pack_into("<I", buf, 0x80, a) # string hash bucket[0] -> A
struct.pack_into("<I", buf, a, b) # A.next_offset -> B
struct.pack_into("<H", buf, a + 6, 0) # A.string_length = 0
struct.pack_into("<I", buf, b, a) # B.next_offset -> A (A <-> B)
struct.pack_into("<H", buf, b + 6, 0) # B.string_length = 0
ChunkHeader(bytes(buf), 0).strings() # never returns
Measured on master (c000744): a non-cyclic bucket returns in ~0.002 s; the cyclic one does not return (killed after 8 s). Reproduced on Python 3.14 (the loop is version-independent).
Suggested fix
Track the offsets already visited while walking a bucket and stop when one repeats. I'll open a PR with the fix plus a regression test that fails on current master and passes with the change.
Environment
- python-evtx master (
c000744), version 0.8.1 - Python 3.14 (reproduces on 3.9–3.14; not version-specific)
- Lingua principale
- Python
- Stelle
- 783
- Fork
- 169
- Merge medio
- 2g 21h
- PR unite (30g)
- 1
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di williballenthin/python-evtx
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 25/100
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 42/100
williballenthin/python-evtx#94 · 2 commenti ·
-
parse data from dirty chunksApertabug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
williballenthin/python-evtx#85 · 2 commenti ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 42/100
Tutte le issue di williballenthin/python-evtx
Issue simili
-
good first issue infrastructure
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
kuznia-rdzeni/coreblocks#1135 ·
-
good first issue server
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
I maintainer di solito rispondono entro 1 giorno
-
documentation priority: high
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
a-lex-s/mealie-telegram-bot#54 ·
I maintainer di solito rispondono entro 1 giorno
-
type/test
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
SaltedTan/virgil-language-server#218 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 83/100
btclib-org/btclib-wallet#541 ·
I maintainer di solito rispondono entro 1 giorno