Infinite loop in ChunkHeader._load_strings / _load_templates on a crafted chunk (cyclic next_offset)
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 78/100
Hướng nghiên cứu
Đọc Evtx/Evtx.py, tập trung vào ChunkHeader._load_strings và _load_templates cũng như các trường next_offset trong Nodes.py. Trước tiên, hãy tái hiện bằng chứng khái niệm được cung cấp về các offset tuần hoàn với thời gian chờ giới hạn, sau đó kiểm tra xem cả hai bộ nạp có gặp các offset lặp lại hay không. Hoàn tất khi các chuỗi tuần hoàn trả về thay vì bị treo và các bài kiểm thử hồi quy bao quát những trường hợp chu kỳ.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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)
- Ngôn ngữ chính
- Python
- Star
- 783
- Fork
- 169
- Merge trung bình
- 2 ngày 21 giờ
- Pull request đã merge (30 ngày)
- 1
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của williballenthin/python-evtx
-
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 25/100
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 35/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 42/100
williballenthin/python-evtx#94 · 2 bình luận ·
-
parse data from dirty chunksĐang mởbug
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 35/100
williballenthin/python-evtx#85 · 2 bình luận ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 42/100
Tất cả issue của williballenthin/python-evtx
Issue tương tự
-
type-bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
push_gh-pages fails on master branch on forksCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mởgood first issue infrastructure
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
kuznia-rdzeni/coreblocks#1135 ·
-
good first issue server
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
Maintainer thường phản hồi trong vòng 1 ngày
-
documentation priority: high
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
a-lex-s/mealie-telegram-bot#54 ·
Maintainer thường phản hồi trong vòng 1 ngày