From 9834930299a83789189c7edd4f06f6cfc24de7b0 Mon Sep 17 00:00:00 2001 From: zhaolei <12153398@qq.com> Date: Thu, 29 Oct 2026 17:28:23 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20PDF/Office/=E5=8E=8B=E7=BC=A9=E5=8C=85?= =?UTF-8?q?=E5=85=B3=E9=94=AE=E8=AF=8D=E8=AF=AF=E6=8A=A5=20=E2=80=94=20?= =?UTF-8?q?=E4=B8=A4=E5=B1=82=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【regex 层收紧】policy.yaml keyword_rules 1) ReverseShellNetcat: \\bnc\\b → \\bnc\\s+-[elpvs]\\w* nc 后必须跟参数 (-e/-l/-p/-v/-s), 单独 nc 在二进制里必然误报 ncat 同理: \\bncat\\b → \\bncat\\s+-\\w+ 保留 \\bnetcat\\b (8 字母, 碰撞概率极低) 2) CredentialStealer: 全部关键词加 \\b 词边界 wce 单独加后续约束: wce(\\.exe\\b|\\s|\\/) 要求 wce 后跟 .exe / 空格 / / (二进制随机字节里 WCE 不再触发) 【引擎层架构修复】keywords.py 新增 BINARY_SKIP_EXTS (48 个扩展名): - PDF / Office (.pdf/.docx/.xlsx/.pptx/...) - 压缩包 (.rar/.zip/.7z/.tar/.gz/...) - 图片 (.png/.jpg/.gif/.svg/...) - 视频 (.mp4/.avi/.mkv/...) - 音频 (.mp3/.wav/.flac/...) KeywordEngine.scan() 开头检查: 如果 declared_ext / path ext 在 BINARY_SKIP_EXTS → 直接返回空 根因: PDF/DOCX/ZIP 等文件是 DEFLATE 压缩流 (伪随机字节) 短关键词 (nc=2w/wce=3w) 在压缩流里必然出现 误报导致: 云启智能体平台生成效果.pdf 被拦截 ReverseShellNetcat: 'g%ew;V6Z?)Nc{>72z}*&96' CredentialStealer: '2>>~:pa}w*WCE|2MVB85t/$' 验证: ✅ 新 regex: 真实 nc -e / wce.exe 命中, PDF 压缩流字节不命中 ✅ BINARY_SKIP_EXTS: .pdf/.docx/.zip 跳过, .sh/.ps1/.txt 扫描 ✅ scan() 方法已含跳过逻辑 --- app/engines/keywords.py | 29 +++++++++++++++++++++++++++++ config/policy.yaml | 6 ++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/app/engines/keywords.py b/app/engines/keywords.py index 0c0f34d..bfd8028 100644 --- a/app/engines/keywords.py +++ b/app/engines/keywords.py @@ -13,6 +13,7 @@ from __future__ import annotations import logging +import os import re from typing import Any, Dict, List @@ -24,6 +25,26 @@ logger = logging.getLogger(__name__) class KeywordEngine(Engine): """内网特征词表匹配引擎。""" + # ---- 跳过列表:二进制 / 压缩封装 / 媒体文件 ---- + # 这些文件有专门引擎处理(PDF/Office/Archive/PE 等), + # 它们的内容是压缩流或二进制格式,关键词 regex 在里面会大面积误报。 + # 短关键词 (nc/wce/curl/...) 在压缩流里等于伪随机字节必然碰撞。 + BINARY_SKIP_EXTS = frozenset({ + # PDF / Office + ".pdf", ".docx", ".docm", ".doc", ".xlsx", ".xlsm", ".xls", + ".pptx", ".pptm", ".ppt", ".ppsx", ".pps", ".potx", + # 压缩包 + ".rar", ".zip", ".7z", ".tar", ".gz", ".bz2", ".xz", ".tgz", + ".iso", ".img", ".dmg", + # 图片 + ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".tif", ".webp", + ".ico", ".svg", + # 视频 + ".mp4", ".avi", ".mkv", ".mov", ".flv", ".wmv", ".webm", + # 音频 + ".mp3", ".wav", ".flac", ".ogg", ".aac", ".wma", ".m4a", + }) + name = "keywords" layer = "L2B" version = "1.0" @@ -57,6 +78,14 @@ class KeywordEngine(Engine): findings: List[Finding] = [] + # ---- 跳过二进制/压缩封装文件 ---- + # 这些文件内容是压缩流或纯二进制,短关键词 regex 在里面必然误报 + ext = (target.declared_ext or "").lower() + if not ext and target.path: + ext = os.path.splitext(target.path)[1].lower() + if ext in self.BINARY_SKIP_EXTS: + return result + try: text = self._extract_text(target.path, target.declared_ext) except Exception: # noqa: BLE001 diff --git a/config/policy.yaml b/config/policy.yaml index 0d8fbeb..a0caf8f 100644 --- a/config/policy.yaml +++ b/config/policy.yaml @@ -357,7 +357,8 @@ keyword_rules: # ---- 反弹 Shell ---- - name: ReverseShellNetcat match: regex - pattern: "(\\bnc\\b|\\bncat\\b|\\bnetcat\\b|/dev/tcp/|bash\\s+-i\\s+>&|sh\\s+-i\\s+>&)" + # nc/ncat 后必须跟参数 (如 -e/-l/-p/-v/-s),单独 nc 在二进制里必然误报 + pattern: "(\\bnc\\s+-[elpvs]\\w*|\\bncat\\s+-\\w+|\\bnetcat\\b|/dev/tcp/|bash\\s+-i\\s+>&|sh\\s+-i\\s+>&)" ignore_case: true weight: 40 severity: critical @@ -372,7 +373,8 @@ keyword_rules: # ---- 凭据窃取工具 ---- - name: CredentialStealer match: regex - pattern: "(mimikatz|sekurlsa|wce|gsecdump|fgdump|lsadump|dcsync|dcsyncer|rubeus)" + # 全部加 \b 词边界, wce 要求后跟 .exe / 空格 / / (二进制随机字节里的 WCE 不会触发) + pattern: "(\\bmimikatz\\b|\\bsekurlsa\\b|\\bwce(\\.exe\\b|\\s|\\/)|\\bgsecdump\\b|\\bfgdump\\b|\\blsadump\\b|\\bdcsync\\b|\\bdcsyncer\\b|\\brubeus\\b)" ignore_case: true weight: 45 severity: critical