fix: 六引擎误报根因修复 — 解包递归、YARA 恒真规则、签名分级、real_type 溢出

检测范围与证据链修复,不改裁决口径(口径改动在下一条提交)。

- extractor:zip/tar 成员在超限分支外漏加回扫描队列,解包后内容永远不参与检测;
  zip 目录条目被当成内嵌对象;tar 超限成员先落盘不删。递归真正生效后深扫耗时可测。
- clamav:_HIGH/_MEDIUM/_UNWANTED 关键词是小写,而签名名是 "Win.Trojan..." 大小写混排,
  分级判定恒不命中全走默认档;改统一大写匹配。超过 clamd MaxFileSize 的裸奔区间
  (1G~1.5G) 新增 ClamAVSkippedSizeLimit(30) — 按"不可扫描不放行"进复核。
- yara:pe.yar C1 系列改用导入表判定,不再靠裸子串命中字符串表;
  linux.yar C7 多条规则条件恒真(裸 nc/fetch 之类)已收紧;C8/C3 相应收窄。
- structure:DangerousExecutableExtension 是载体信号而非恶意行为,critical 权重 45→35,
  不再作为把中低置信度信号一起顶过 block_score 的底座。
- scanner/documents:real_type 拼进 libmagic 对 MSI/OLE 的元数据串实测 334+ 字符,
  超列宽导致整条 scan_tasks INSERT 连 findings 一起丢(被拒文件不留痕)→
  列宽 256→512,migrate.sql 补 ALTER。
This commit is contained in:
2026-11-02 20:26:56 +08:00
parent 64b682319e
commit b6a004bdb7
13 changed files with 636 additions and 311 deletions

View File

@@ -205,8 +205,9 @@ class SafeExtractor:
safe_name = self._sanitize_name(name)
dest = os.path.join(out_dir, safe_name)
try:
written = 0
overflow = False
with zf.open(info) as src, open(dest, "wb") as out:
written = 0
while True:
chunk = src.read(1024 * 1024)
if not chunk:
@@ -222,20 +223,22 @@ class SafeExtractor:
f"成员 {name} 实际解压超限,已丢弃",
10.0,
)
overflow = True
break
out.write(chunk)
else:
report.total_bytes += written
report.files.append(
ScanTarget(
path=dest,
filename=safe_name,
declared_ext=os.path.splitext(safe_name)[1].lower(),
logical_path=f"{target.logical_path}!/{name}",
depth=target.depth + 1,
is_extracted=True,
)
# 成员必须回到扫描队列,否则压缩包/OOXML 里的内容永远不参与检测
if not overflow:
report.total_bytes += written
report.files.append(
ScanTarget(
path=dest,
filename=safe_name,
declared_ext=os.path.splitext(safe_name)[1].lower(),
logical_path=f"{target.logical_path}!/{name}",
depth=target.depth + 1,
is_extracted=True,
)
)
except Exception as exc: # noqa: BLE001
self._add_finding(
report,
@@ -323,14 +326,26 @@ class SafeExtractor:
continue
with src, open(dest, "wb") as out:
written = 0
overflow = False
while True:
chunk = src.read(1024 * 1024)
if not chunk:
break
written += len(chunk)
if written > self.settings.max_upload_bytes:
out.close()
os.remove(dest)
self._add_finding(
report,
Severity.MEDIUM.value,
"MemberTooLarge",
f"成员 {name} 实际解压超限,已丢弃",
10.0,
)
overflow = True
break
out.write(chunk)
if not overflow:
report.total_bytes += written
report.files.append(
ScanTarget(