fix: 裁决口径重构 — rule_overrides 改处置地板,YARA 权重分档与阈值解耦
三件事,都围绕"分数只反映证据,不放行由地板保证": - rule_overrides 的 manual_review 旧实现是 score=max(score,65) 并跳过该规则自身权重: 注进去的 65 不是证据,再叠任意 ≥5 分噪声就越过 block_score=70 变拒绝,同时显示分数 与真实证据脱钩。改为步骤 9「复核地板」:权重照常累加,裁决后处置低于复核才抬到 manual_review,已判 reject 不降回。3661 条历史扫描重放 0 收紧 0 放行;把 review_score 下界抬到 36/40/50 或把 DEE 权重降到 10,无地板时干净 exe 静默放行,有地板恒为人工复核。 - DangerousExecutableExtension 进 rule_overrides(manual_review),落实光闸口径「EXE/DLL/ 脚本不自动放行」,不再依赖 weight=30 恰好等于 review_score 下界这种数值巧合。 - YARA 权重分档 85/65/45/25 → 85/60/30/10,只有 critical 一档能独立越过 70; 档位与 rules/*.yar 的 meta.risk_level 一一对应,控制台注释与 policy.html 同步。 - 词表:RemoteDownloadUnix/PowerShell 移出零容忍、改判"工具与 URL/IP 同框", 新增 RemoteDownloadExec(40)/PayloadDropToDisk(45) 带内网源站白名单。裸 cmdlet 名会把 nvidiaInspector.exe 的 add_DownloadFileCompleted 白送 30 分,把 45 分复核顶成 75 分拒绝。 - 风险等级文案:裁决已是 malicious/error 时仍输出"打开风险低"是自相矛盾的对外文案, 强制收敛到 critical。 - 靶场 L5-005 expected_verdict reject→review:旧 85 分靠载体45+时间戳20+未签名10+架构10 堆叠,属权重堆叠误报;真实注入器由 C1_PE_ProcessInjection(85) 拦截。
This commit is contained in:
@@ -174,7 +174,7 @@ def _annotate_yaml(raw: str) -> str:
|
|||||||
# ---- rule_overrides ----
|
# ---- rule_overrides ----
|
||||||
"rule_overrides": '特定规则的处置覆盖。action: pass | manual_review | reject',
|
"rule_overrides": '特定规则的处置覆盖。action: pass | manual_review | reject',
|
||||||
# ---- yara ----
|
# ---- yara ----
|
||||||
"yara_rule_weights": 'YARA 规则按严重度分档赋权重(critical=85 high=65 medium=45 low=25)',
|
"yara_rule_weights": 'YARA 规则按严重度分档赋权重(critical=85 high=60 medium=30 low=10)',
|
||||||
# ---- keyword ----
|
# ---- keyword ----
|
||||||
"keyword_rules": '词表引擎规则。match: contains | regex | any_of',
|
"keyword_rules": '词表引擎规则。match: contains | regex | any_of',
|
||||||
# ---- notification ----
|
# ---- notification ----
|
||||||
@@ -215,9 +215,9 @@ def _annotate_yaml(raw: str) -> str:
|
|||||||
# YARA 权重分档 → 中文
|
# YARA 权重分档 → 中文
|
||||||
_WEIGHT_TIER_HINTS = {
|
_WEIGHT_TIER_HINTS = {
|
||||||
"critical": "weight=85(严重)",
|
"critical": "weight=85(严重)",
|
||||||
"high": "weight=65(高危)",
|
"high": "weight=60(高危)",
|
||||||
"medium": "weight=45(中等)",
|
"medium": "weight=30(中等)",
|
||||||
"low": "weight=25(低危)",
|
"low": "weight=10(低危)",
|
||||||
}
|
}
|
||||||
|
|
||||||
lines = raw.split("\n")
|
lines = raw.split("\n")
|
||||||
|
|||||||
@@ -115,13 +115,14 @@ class Policy:
|
|||||||
"""YARA 规则权重映射:规则名 → weight(0-100)。
|
"""YARA 规则权重映射:规则名 → weight(0-100)。
|
||||||
|
|
||||||
从 policy.yaml 的 yara_rule_weights.{critical/high/medium/low} 展开。
|
从 policy.yaml 的 yara_rule_weights.{critical/high/medium/low} 展开。
|
||||||
档位权重固定:critical=85 / high=65 / medium=45 / low=25。
|
档位权重固定:critical=85 / high=60 / medium=30 / low=10
|
||||||
|
(与 rules/*.yar 的 meta.risk_level 分档、binary.py 默认权重一致)。
|
||||||
"""
|
"""
|
||||||
weights = {
|
weights = {
|
||||||
"critical": 85.0,
|
"critical": 85.0,
|
||||||
"high": 65.0,
|
"high": 60.0,
|
||||||
"medium": 45.0,
|
"medium": 30.0,
|
||||||
"low": 25.0,
|
"low": 10.0,
|
||||||
}
|
}
|
||||||
result: Dict[str, float] = {}
|
result: Dict[str, float] = {}
|
||||||
for tier, weight in weights.items():
|
for tier, weight in weights.items():
|
||||||
@@ -414,6 +415,8 @@ class PolicyEngine:
|
|||||||
5) 规则覆盖
|
5) 规则覆盖
|
||||||
6) 权重累加评分
|
6) 权重累加评分
|
||||||
7) 阈值裁决
|
7) 阈值裁决
|
||||||
|
8) 复核区间上界校正
|
||||||
|
9) 复核地板(步骤 5 声明 manual_review 的规则,只抬处置不抬分数)
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@@ -566,14 +569,15 @@ class PolicyEngine:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 5) 规则覆盖优先处理
|
# 5) 规则覆盖优先处理
|
||||||
override_findings: List[Finding] = []
|
# action=reject 立即拒绝;action=manual_review 只登记"复核地板",
|
||||||
|
# 不往分数里注 65 —— 地板在步骤 9 生效。
|
||||||
|
review_floor = False
|
||||||
for finding in findings:
|
for finding in findings:
|
||||||
override = policy.rule_overrides.get(finding.rule)
|
override = policy.rule_overrides.get(finding.rule)
|
||||||
if not override:
|
if not override:
|
||||||
continue
|
continue
|
||||||
action = override.get("action", "manual_review")
|
action = override.get("action", "manual_review")
|
||||||
reason = override.get("reason") or f"规则 {finding.rule} 命中策略"
|
reason = override.get("reason") or f"规则 {finding.rule} 命中策略"
|
||||||
override_findings.append(finding)
|
|
||||||
triggered.append(
|
triggered.append(
|
||||||
{
|
{
|
||||||
"type": "rule_override",
|
"type": "rule_override",
|
||||||
@@ -593,12 +597,10 @@ class PolicyEngine:
|
|||||||
triggered=triggered,
|
triggered=triggered,
|
||||||
)
|
)
|
||||||
if action == "manual_review":
|
if action == "manual_review":
|
||||||
score = max(score, 65.0)
|
review_floor = True
|
||||||
|
|
||||||
# 6) 其余信号按权重累加
|
# 6) 全部信号按权重累加
|
||||||
for finding in findings:
|
for finding in findings:
|
||||||
if finding in override_findings:
|
|
||||||
continue
|
|
||||||
score += finding.weight
|
score += finding.weight
|
||||||
if finding.severity in {Severity.HIGH.value, Severity.CRITICAL.value}:
|
if finding.severity in {Severity.HIGH.value, Severity.CRITICAL.value}:
|
||||||
reasons.append(f"{finding.engine}:{finding.detail}")
|
reasons.append(f"{finding.engine}:{finding.detail}")
|
||||||
@@ -622,6 +624,12 @@ class PolicyEngine:
|
|||||||
if score >= policy.block_score:
|
if score >= policy.block_score:
|
||||||
verdict, action = "malicious", "reject"
|
verdict, action = "malicious", "reject"
|
||||||
|
|
||||||
|
# 9) 复核地板:策略里声明 manual_review 的规则保证"不低于人工复核",
|
||||||
|
# 与权重数值和 review_score 阈值解耦——调高 review_score 下界或调低
|
||||||
|
# 这些规则的权重,都不会让它们覆盖的文件类型静默放行。
|
||||||
|
if review_floor and action in ("pass", "pass_with_flag"):
|
||||||
|
verdict, action = "suspicious", "manual_review"
|
||||||
|
|
||||||
reason = self._build_reason(verdict, reasons, score)
|
reason = self._build_reason(verdict, reasons, score)
|
||||||
return Decision(
|
return Decision(
|
||||||
verdict=verdict,
|
verdict=verdict,
|
||||||
@@ -753,7 +761,9 @@ class PolicyEngine:
|
|||||||
if any("url" in f.rule.lower() or "link" in f.rule.lower() or "qr" in f.rule.lower()
|
if any("url" in f.rule.lower() or "link" in f.rule.lower() or "qr" in f.rule.lower()
|
||||||
for f in findings):
|
for f in findings):
|
||||||
factors.append("external_url")
|
factors.append("external_url")
|
||||||
if ext in {".exe", ".dll", ".elf", ".so", ".desktop", ".appimage", ".run", ".bin", ".deb", ".rpm"}:
|
if ext in {".exe", ".dll", ".elf", ".so", ".desktop", ".appimage", ".run", ".bin", ".deb", ".rpm",
|
||||||
|
".msi", ".msp", ".com", ".pif", ".scr", ".cpl", ".jar", ".war",
|
||||||
|
".vbs", ".vbe", ".js", ".jse", ".ps1", ".bat", ".cmd", ".hta", ".lnk", ".cab", ".appx"}:
|
||||||
factors.append("contains_executable")
|
factors.append("contains_executable")
|
||||||
if ext == ".iso":
|
if ext == ".iso":
|
||||||
factors.append("is_mountable_image")
|
factors.append("is_mountable_image")
|
||||||
@@ -774,6 +784,14 @@ class PolicyEngine:
|
|||||||
advice = "文件结构正常,无特别提示"
|
advice = "文件结构正常,无特别提示"
|
||||||
requires_macro = False
|
requires_macro = False
|
||||||
|
|
||||||
|
# 裁决已经是恶意/引擎不可判定时,"打开风险低"是自相矛盾的对外文案:
|
||||||
|
# 摆渡系统会把这段展示给用户,等于告诉用户"被拦下的文件可以放心打开"。
|
||||||
|
if verdict in {"malicious", "error", "reject"} and level != "critical":
|
||||||
|
level = "critical"
|
||||||
|
factors.append("verdict_rejected")
|
||||||
|
advice = "该文件已被判定为恶意或不可判定,请勿打开,联系管理员处理"
|
||||||
|
requires_macro = False
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"level": level,
|
"level": level,
|
||||||
"factors": factors,
|
"factors": factors,
|
||||||
|
|||||||
@@ -172,10 +172,10 @@
|
|||||||
<h3>权重分档说明(来自 policy.yaml → yara_rule_weights)</h3>
|
<h3>权重分档说明(来自 policy.yaml → yara_rule_weights)</h3>
|
||||||
<div style="font-size:13px;color:#555;line-height:1.8;">
|
<div style="font-size:13px;color:#555;line-height:1.8;">
|
||||||
<span class="chip chip-zt">critical → weight=85</span>
|
<span class="chip chip-zt">critical → weight=85</span>
|
||||||
<span class="chip chip-warn">high → weight=65</span>
|
<span class="chip chip-warn">high → weight=60</span>
|
||||||
<span class="chip chip-info">medium → weight=45</span>
|
<span class="chip chip-info">medium → weight=30</span>
|
||||||
<span class="chip chip-ok">low → weight=25</span>
|
<span class="chip chip-ok">low → weight=10</span>
|
||||||
<span style="color:#888;margin-left:12px;">未配置的规则默认 weight=50</span>
|
<span style="color:#888;margin-left:12px;">未列出的规则沿用 rules/*.yar 中 meta.risk_level 推导出的同档权重</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -67,8 +67,6 @@ zero_tolerance_rules:
|
|||||||
- ReverseShellPowershell # PowerShell 反弹 Shell (-enc)
|
- ReverseShellPowershell # PowerShell 反弹 Shell (-enc)
|
||||||
- CredentialStealer # 凭据窃取工具 (mimikatz/sekurlsa/wce/...)
|
- CredentialStealer # 凭据窃取工具 (mimikatz/sekurlsa/wce/...)
|
||||||
- CredentialExport # 凭据导出命令 (reg save/reg export/...)
|
- CredentialExport # 凭据导出命令 (reg save/reg export/...)
|
||||||
- RemoteDownloadUnix # Unix 远程下载执行 (curl|wget|certutil)
|
|
||||||
- RemoteDownloadPowerShell # PowerShell 远程下载执行 (IWR/DownloadString)
|
|
||||||
|
|
||||||
# ---------- 文件类型白名单 ----------
|
# ---------- 文件类型白名单 ----------
|
||||||
# 只允许这些类型通过。空列表表示不限制(不推荐生产使用)。
|
# 只允许这些类型通过。空列表表示不限制(不推荐生产使用)。
|
||||||
@@ -217,6 +215,12 @@ sandbox_required_extensions:
|
|||||||
# rule_name: [action, reason_override]
|
# rule_name: [action, reason_override]
|
||||||
# action 取值:pass / pass_with_flag / manual_review / reject / reject_and_notify
|
# action 取值:pass / pass_with_flag / manual_review / reject / reject_and_notify
|
||||||
rule_overrides:
|
rule_overrides:
|
||||||
|
# 光闸口径:EXE/DLL/脚本一律不自动放行,最低人工复核。
|
||||||
|
# 用 override 而不是靠 weight=30 恰好等于 review_score 下界来维持——
|
||||||
|
# 数值巧合意味着把下界调到 >35 或把权重降一点,干净可执行文件就会静默放行。
|
||||||
|
DangerousExecutableExtension:
|
||||||
|
action: manual_review
|
||||||
|
reason: "可执行/脚本类型文件,按光闸口径最低转人工复核"
|
||||||
VBAShellInvocation:
|
VBAShellInvocation:
|
||||||
action: manual_review
|
action: manual_review
|
||||||
reason: "宏调用 Shell 但无自动执行入口,需人工复核"
|
reason: "宏调用 Shell 但无自动执行入口,需人工复核"
|
||||||
@@ -255,58 +259,60 @@ notification:
|
|||||||
max_reason_length: 500
|
max_reason_length: 500
|
||||||
|
|
||||||
# ---------- YARA 规则权重映射 ----------
|
# ---------- YARA 规则权重映射 ----------
|
||||||
# 按规则名精细设定权重(0-100),覆盖 binary.py 里的默认 weight=50
|
# 档位权重与 rules/*.yar 的 meta.risk_level 一一对应(由 binary.py 读取 meta 得到
|
||||||
# 命中但不在下列名单中的规则 weight 保持默认值 50
|
# 默认严重度,再用本表覆盖为固定权重,保证规则文件与策略只有一处真相)。
|
||||||
# 严重度分档由规则内 meta.risk_level 决定(critical/high/medium/low)
|
# critical=85(单独命中即 reject)/ high=60 / medium=30 / low=10
|
||||||
|
# 只有 critical 一档可以独立越过 block_score=70;其余档位需与其他信号叠加。
|
||||||
|
# 不在本表的规则:沿用 meta.risk_level 推导出的默认权重。
|
||||||
yara_rule_weights:
|
yara_rule_weights:
|
||||||
critical: # weight=85
|
critical: # weight=85
|
||||||
- C3_PHP_Webshell_Oneliner
|
|
||||||
- C3_JSP_Webshell_RuntimeExec
|
|
||||||
- C3_Webshell_Behinder
|
|
||||||
- C1_PE_ProcessInjection
|
- C1_PE_ProcessInjection
|
||||||
- C8_Ransomware_Encryption
|
- C1_PE_RAT_CommandControl
|
||||||
- C8_Ransomware_LockBit
|
- C3_JSP_Webshell_Deserialization
|
||||||
- C8_Ransomware_BlackCat
|
- C3_JSP_Webshell_RuntimeExec
|
||||||
- C8_Ransomware_Conti
|
- C3_PHP_Webshell_Oneliner
|
||||||
|
- C3_Webshell_Behinder
|
||||||
|
- C3_Webshell_CommandExecutionEcho
|
||||||
|
- C3_Webshell_Godzilla
|
||||||
- C7_Linux_ReverseShell_Bash
|
- C7_Linux_ReverseShell_Bash
|
||||||
- C7_Linux_ReverseShell_NC
|
- C7_Linux_ReverseShell_NC
|
||||||
- C7_Linux_Rootkit_KernelModule
|
- C7_Linux_Rootkit_KernelModule
|
||||||
high: # weight=65
|
- C8_Ransomware_BlackCat
|
||||||
|
- C8_Ransomware_Conti
|
||||||
|
- C8_Ransomware_Encryption
|
||||||
|
- C8_Ransomware_LockBit
|
||||||
|
high: # weight=60
|
||||||
|
- C1_PE_DLLHijacking
|
||||||
|
- C1_PE_Downloader_Loader
|
||||||
|
- C1_PE_LOLBin_Usage
|
||||||
|
- C3_JSP_Webshell_MemoryShell
|
||||||
- C3_PHP_Webshell_Obfuscated
|
- C3_PHP_Webshell_Obfuscated
|
||||||
- C3_PHP_Webshell_VariableDeformation
|
- C3_PHP_Webshell_VariableDeformation
|
||||||
- C3_Webshell_CommandExecutionEcho
|
- C3_Webshell_ASP_Classic
|
||||||
- C3_Webshell_Godzilla
|
- C3_Webshell_ASPNET
|
||||||
- C1_PE_Downloader_Loader
|
- C3_Webshell_AntSword
|
||||||
- C1_PE_RAT_CommandControl
|
|
||||||
- C1_PE_LOLBin_Usage
|
|
||||||
- C1_PE_Mutex_Persistence
|
|
||||||
- C7_Linux_ReverseShell_Python
|
|
||||||
- C7_Linux_ReverseShell_Perl
|
|
||||||
- C7_Linux_ReverseShell_Socat
|
|
||||||
- C7_Linux_Persistence_Crontab
|
|
||||||
- C7_Linux_Persistence_SystemD
|
|
||||||
- C7_Linux_Persistence_AuthorizedKeys
|
- C7_Linux_Persistence_AuthorizedKeys
|
||||||
|
- C7_Linux_Persistence_Crontab
|
||||||
- C7_Linux_Persistence_LD_PRELOAD
|
- C7_Linux_Persistence_LD_PRELOAD
|
||||||
- C8_Ransomware_VolumeShadow
|
- C7_Linux_Persistence_SystemD
|
||||||
- C8_Ransomware_Note_Filename
|
- C7_Linux_ReverseShell_Perl
|
||||||
|
- C7_Linux_ReverseShell_Python
|
||||||
|
- C7_Linux_ReverseShell_Socat
|
||||||
|
- C8_Mining_Monero
|
||||||
- C8_Ransomware_Ryuk_Pseudo
|
- C8_Ransomware_Ryuk_Pseudo
|
||||||
medium: # weight=45
|
- C8_Ransomware_VolumeShadow
|
||||||
- C9_Packer_UPX
|
medium: # weight=30
|
||||||
- C9_Packer_Themida_VMP
|
|
||||||
- C1_PE_DLLHijacking
|
|
||||||
- C1_PE_EntropyHighNetwork
|
- C1_PE_EntropyHighNetwork
|
||||||
|
- C1_PE_Mutex_Persistence
|
||||||
- C7_Linux_Miner_Generic
|
- C7_Linux_Miner_Generic
|
||||||
|
- C7_Linux_ReverseShell_Misc
|
||||||
- C7_Misc_Ruby_Lua_ReverseShell
|
- C7_Misc_Ruby_Lua_ReverseShell
|
||||||
- C7_Network_Tools_Malicious
|
- C7_Network_Tools_Malicious
|
||||||
- C3_Webshell_AntSword
|
- C8_Ransomware_Note_Filename
|
||||||
- C3_Webshell_ASPNET
|
- C9_Packer_Themida_VMP
|
||||||
- C3_Webshell_ASP_Classic
|
low: # weight=10
|
||||||
- C3_JSP_Webshell_Deserialization
|
|
||||||
- C3_JSP_Webshell_MemoryShell
|
|
||||||
- C3_Webshell_CommandExecutionEcho
|
|
||||||
- C8_Ransomware_Extension_Blacklist
|
- C8_Ransomware_Extension_Blacklist
|
||||||
low: # weight=25
|
- C9_Packer_UPX
|
||||||
- C7_Linux_ReverseShell_Misc
|
|
||||||
|
|
||||||
|
|
||||||
# ---------- 内网特征词表引擎(P1)----------
|
# ---------- 内网特征词表引擎(P1)----------
|
||||||
@@ -339,26 +345,55 @@ keyword_rules:
|
|||||||
# 恶意行为特征词表(覆盖 CSV L3 全部 25 条用例)
|
# 恶意行为特征词表(覆盖 CSV L3 全部 25 条用例)
|
||||||
# ================================================================
|
# ================================================================
|
||||||
|
|
||||||
# ---- 远程下载执行 ----
|
# ---- 远程下载即执行(要有完整动作链,裸词不算;README 里的安装命令进复核而非直接拒)----
|
||||||
|
# cross_line:命令换行/续行是本类特征最常见的绕过(curl \ + 下一行 | sh),
|
||||||
|
# 拼接后仍要求"下载工具 + 执行动作"同框,散文里的多行文本不会凑出这条链。
|
||||||
|
- name: RemoteDownloadExec
|
||||||
|
match: regex
|
||||||
|
pattern: "(?:\\b(?:curl|wget)\\b[^\\n]{0,120}\\|\\s*(?:ba|z|k|da)?sh\\b|\\b(?:curl|wget)\\b[^\\n]{0,120}(?:&&|;)\\s*(?:chmod\\s+\\+x|\\./)|(?:^|[^\\w$-])(?:iex|invoke-expression)\\b[^\\n]{0,60}(?:\\biwr\\b|invoke\\s*[-_]?\\s*web\\s*[-_]?\\s*request|invoke\\s*[-_]?\\s*rest\\s*[-_]?\\s*method|downloadstring)|\\b(?:iwr|invoke\\s*[-_]?\\s*web\\s*[-_]?\\s*request|invoke\\s*[-_]?\\s*rest\\s*[-_]?\\s*method)\\b[^\\n]{0,120}\\|\\s*(?:iex|invoke-expression)\\b|certutil\\s+[-/]urlcache[^\\n]{0,60}\\.exe\\b|mkfifo[^\\n]{0,60}(?:\\bnc\\s|\\bnetcat\\b))"
|
||||||
|
ignore_case: true
|
||||||
|
cross_line: true
|
||||||
|
weight: 40
|
||||||
|
severity: critical
|
||||||
|
|
||||||
|
# ---- 下载并落地成可执行文件(dropper 行为,比"下载即执行"弱一档但仍高危)----
|
||||||
|
- name: PayloadDropToDisk
|
||||||
|
match: regex
|
||||||
|
pattern: "(?:\\b(?:curl|wget)\\b[^\\n]{0,120}(?:-o|-O|--output)\\s+\\S*\\.(?:exe|dll|ps1|bat|cmd|vbs|jar|msi|so|bin)\\b|\\b(?:i\\s*[-_]?\\s*wr|invoke\\s*[-_]?\\s*web\\s*[-_]?\\s*request|invoke\\s*[-_]?\\s*rest\\s*[-_]?\\s*method)\\b[^\\n]{0,120}-o(?:utfile)?\\s+\\S*\\.(?:exe|dll|ps1|bat|cmd|vbs)\\b|\\b(?:new-object|activexobject)\\s+system\\.net\\.webclient[^\\n]{0,80}downloadfile)"
|
||||||
|
ignore_case: true
|
||||||
|
cross_line: true
|
||||||
|
weight: 45
|
||||||
|
severity: critical
|
||||||
|
|
||||||
|
# ---- 外部下载动作(cmdlet/API + 无执行链):计分进复核,不再零容忍 ----
|
||||||
|
# cmdlet 名(Invoke-WebRequest/Invoke-RestMethod/BitsAdmin)是 PowerShell 专有写法,
|
||||||
|
# 单独出现即进复核。.NET/Win32 的方法名(DownloadString/DownloadFile)不一样——
|
||||||
|
# 它们存在于所有托管程序的标识符表里,裸匹配实测把 nvidiaInspector.exe 的
|
||||||
|
# `add_DownloadFileCompleted`、`DownloadFileAsync` 各算一次命中,白送 30 分,
|
||||||
|
# 把 45 分的人工复核顶成 75 分拒绝。所以方法名必须与 URL/IP 同框才算下载。
|
||||||
- name: RemoteDownloadPowerShell
|
- name: RemoteDownloadPowerShell
|
||||||
match: regex
|
match: regex
|
||||||
pattern: "(Invoke-WebRequest|Invoke-RestMethod|DownloadString|DownloadFile|Start-BitsTransfer|BitsAdmin)"
|
pattern: "(?:\\b(?:Invoke-WebRequest|Invoke-RestMethod|Start-BitsTransfer|BitsAdmin)\\b|\\bDownload(?:String|File)\\b[^\\n]{0,40}(?:https?://|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|(?:https?://|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})[^\\n]{0,40}\\bDownload(?:String|File)\\b)"
|
||||||
ignore_case: true
|
|
||||||
weight: 35
|
|
||||||
severity: high
|
|
||||||
|
|
||||||
- name: RemoteDownloadUnix
|
|
||||||
match: regex
|
|
||||||
pattern: "(\\bwget\\b|\\bcurl\\b|\\bcertutil\\s+-urlcache\\s+-split|\\bfetch\\b)"
|
|
||||||
ignore_case: true
|
ignore_case: true
|
||||||
weight: 30
|
weight: 30
|
||||||
severity: high
|
severity: medium
|
||||||
|
|
||||||
|
# ---- 下载工具 + 明确地址:只认"工具与 URL/IP 同框",裸 -o 参数不算 ----
|
||||||
|
# 旧写法里的 `curl|wget -O/-o 任意值` 会命中任何写成两段的安装文档,去掉。
|
||||||
|
- name: RemoteDownloadUnix
|
||||||
|
match: regex
|
||||||
|
pattern: "(?:\\b(?:curl|wget|certutil)\\b[^\\n]{0,80}(?:https?://|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}))"
|
||||||
|
ignore_case: true
|
||||||
|
weight: 30
|
||||||
|
severity: medium
|
||||||
|
|
||||||
# ---- 反弹 Shell ----
|
# ---- 反弹 Shell ----
|
||||||
- name: ReverseShellNetcat
|
- name: ReverseShellNetcat
|
||||||
match: regex
|
match: regex
|
||||||
# nc/ncat 后必须跟参数 (如 -e/-l/-p/-v/-s),单独 nc 在二进制里必然误报
|
# 只认「执行原语」形态:nc/ncat/netcat 带 -e/-c(把 shell 交给连接),
|
||||||
pattern: "(\\bnc\\s+-[elpvs]\\w*|\\bncat\\s+-\\w+|\\bnetcat\\b|/dev/tcp/|bash\\s+-i\\s+>&|sh\\s+-i\\s+>&)"
|
# 或 /dev/tcp、bash -i >& 这类内核级反连。裸 nc / nc -l / nc -z 是运维常用,
|
||||||
|
# 出现在速查文档和二进制字符串表里必然误报,不计分。
|
||||||
|
pattern: "(\\b(?:nc|ncat|netcat)\\s+(?:[^\\n]{0,60}\\s)?-[ec]\\w*\\s*(?:/bin/|/usr/|cmd\\.exe\\b|\\S*sh\\b)|/dev/tcp/|bash\\s+-i\\s+>&|sh\\s+-i\\s+>&)"
|
||||||
ignore_case: true
|
ignore_case: true
|
||||||
weight: 40
|
weight: 40
|
||||||
severity: critical
|
severity: critical
|
||||||
@@ -430,6 +465,32 @@ keyword_whitelist:
|
|||||||
- ".senmesh.com"
|
- ".senmesh.com"
|
||||||
- "repo.internal"
|
- "repo.internal"
|
||||||
- "mirror.internal"
|
- "mirror.internal"
|
||||||
|
- rule: RemoteDownloadExec # 下载即执行:内网源站安装脚本按白名单放行
|
||||||
|
allowed_keywords:
|
||||||
|
- "192.168."
|
||||||
|
- "10."
|
||||||
|
- "172.16."
|
||||||
|
- "172.17."
|
||||||
|
- "172.18."
|
||||||
|
- "172.19."
|
||||||
|
- "172.2"
|
||||||
|
- "172.3"
|
||||||
|
- ".senmesh.com"
|
||||||
|
- "repo.internal"
|
||||||
|
- "mirror.internal"
|
||||||
|
- rule: PayloadDropToDisk # 下载落地可执行文件:内网源站安装包放行
|
||||||
|
allowed_keywords:
|
||||||
|
- "192.168."
|
||||||
|
- "10."
|
||||||
|
- "172.16."
|
||||||
|
- "172.17."
|
||||||
|
- "172.18."
|
||||||
|
- "172.19."
|
||||||
|
- "172.2"
|
||||||
|
- "172.3"
|
||||||
|
- ".senmesh.com"
|
||||||
|
- "repo.internal"
|
||||||
|
- "mirror.internal"
|
||||||
- rule: RemoteDownloadPowerShell # Invoke-WebRequest/BitsAdmin
|
- rule: RemoteDownloadPowerShell # Invoke-WebRequest/BitsAdmin
|
||||||
allowed_keywords:
|
allowed_keywords:
|
||||||
- "192.168."
|
- "192.168."
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ rule_overrides:
|
|||||||
|---|---|
|
|---|---|
|
||||||
| `pass` | 放行 |
|
| `pass` | 放行 |
|
||||||
| `pass_with_flag` | 放行并标记 |
|
| `pass_with_flag` | 放行并标记 |
|
||||||
| `manual_review` | 转人工复核(同时把评分提升至 65,确保落入复核区间) |
|
| `manual_review` | 处置地板:该文件最终不低于人工复核(评分不变,低于复核区间时只抬处置) |
|
||||||
| `reject` | 拒绝 |
|
| `reject` | 拒绝 |
|
||||||
| `reject_and_notify` | 拒绝并通知(当前实现等同 `reject`) |
|
| `reject_and_notify` | 拒绝并通知(当前实现等同 `reject`) |
|
||||||
|
|
||||||
@@ -201,7 +201,9 @@ rule_overrides:
|
|||||||
|
|
||||||
1. 命中 `rule_overrides` 的规则会**优先于评分**处理
|
1. 命中 `rule_overrides` 的规则会**优先于评分**处理
|
||||||
2. 若 `action` 为 `reject` 类 → 立即返回拒绝结论,不再累加评分
|
2. 若 `action` 为 `reject` 类 → 立即返回拒绝结论,不再累加评分
|
||||||
3. 若 `action` 为 `manual_review` → 评分提升至 65 并继续后续裁决
|
3. 若 `action` 为 `manual_review` → 登记"复核地板",规则自身权重照常累加,评分累加与阈值裁决完成后,处置若低于 `manual_review` 才抬到 `manual_review`(已判 `reject` 的不会被降回来)
|
||||||
|
|
||||||
|
> 旧实现是"评分提升至 65",有两个副作用:注进去的 65 分本身不是证据,再叠加任意 ≥5 分的噪声信号就会越过 `block_score=70` 变成拒绝;同时该规则自身的权重被跳过不再计分,控制台显示的分数与真实证据脱钩。现改为处置地板后,分数只反映权重,"不放行"由地板保证,与 `review_score` 阈值数值解耦——`DangerousExecutableExtension`(光闸口径:EXE/DLL/脚本不自动放行)正是靠这条地板生效,而不是靠 `weight=30/35` 恰好等于 `review_score` 下界。
|
||||||
|
|
||||||
**为什么用覆盖而不是纯评分**:像 `PathTraversal`、`DDEAutoExecution` 这类信号,一旦出现就足以判定不可放行,不应依赖其他信号累加来"凑够"阈值。
|
**为什么用覆盖而不是纯评分**:像 `PathTraversal`、`DDEAutoExecution` 这类信号,一旦出现就足以判定不可放行,不应依赖其他信号累加来"凑够"阈值。
|
||||||
|
|
||||||
|
|||||||
@@ -1047,14 +1047,14 @@
|
|||||||
"filename": "L5-005_injection_imports.exe",
|
"filename": "L5-005_injection_imports.exe",
|
||||||
"case_id": "L5-005",
|
"case_id": "L5-005",
|
||||||
"category": "L5",
|
"category": "L5",
|
||||||
"expected_verdict": "reject",
|
"expected_verdict": "review",
|
||||||
"expected_rules": [
|
"expected_rules": [
|
||||||
"DangerousExecutableExtension",
|
"DangerousExecutableExtension",
|
||||||
"PEArchInfo",
|
"PEArchInfo",
|
||||||
"SuspiciousTimestamp",
|
"SuspiciousTimestamp",
|
||||||
"UnsignedExecutable"
|
"UnsignedExecutable"
|
||||||
],
|
],
|
||||||
"description": "注入组合导入(需要真实 pefile 引入 API)",
|
"description": "注入组合导入占位样本(928B 假 PE,实际没有导入表)。旧策略靠 载体45+时间戳20+未签名10+架构10 累加到 85 才判 reject,属于权重堆叠误报;权重收紧后应停在人工复核。真实注入器由 YARA C1_PE_ProcessInjection(critical=85) 直接拦截。",
|
||||||
"_scan_verdict": "malicious"
|
"_scan_verdict": "malicious"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user