Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

Infinite loop in ChunkHeader._load_strings / _load_templates on a crafted chunk (cyclic next_offset)

Offen Anfängerfreundlich
#101 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

@memx13 arbeitet bereits daran.

Seit 23.10.2026.

  • #102 von @memx13 — offen

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
78/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
python
Bereich
backend, security

Rechercherichtung

Lies Evtx/Evtx.py und konzentriere dich auf ChunkHeader._load_strings und _load_templates sowie auf die next_offset-Felder in Nodes.py. Reproduziere zuerst unter einem Timeout den bereitgestellten Proof of Concept mit zyklischen Offsets und prüfe anschließend beide Loader auf wiederholte Offsets. Die Aufgabe ist erledigt, wenn zyklische Ketten zurückkehren, statt zu hängen, und Regressionstests die Zyklusfälle abdecken.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

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)
Vorherrschende Sprache
Python
Sterne
783
Forks
169
Ø Merge
2 T. 21 Std.
Gemergte PRs (30 T.)
1

Entwicklungsumgebung

Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus williballenthin/python-evtx

Alle Issues in williballenthin/python-evtx

Ähnliche Issues

Weitere Issues zu Python

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.