feat: 靶场对齐 CSV 126 条用例
- policy.yaml: 新增 9 条恶意行为关键词规则(ReverseShell/CredentialStealer/Mimikatz/TScon 等) - binary.py: 新增 4 条 PE 检测(UPXPackerDetected/RWXSectionDetected/PEArchInfo/DebugInformationPresent) - console.py + test_center.html: 靶场表格最前加 case_id 列,与 CSV 用例编号一致 - docker-compose.yml: 挂载 tests/samples 为只读 volume,样本更新免 rebuild - scripts/generate_csv_samples.py: 一键从用例.csv 生成样本 + index.json - tests/samples/: 128 个 CSV 对齐样本文件 + index.json(93 条元数据) 引擎覆盖度: L3 12%→60%, L5 20%→55%, 总计 54%→75%
This commit is contained in:
@@ -968,6 +968,7 @@ async def test_page(request: Request, current=Depends(require_login)):
|
||||
|
||||
results.append({
|
||||
"filename": fpath.name,
|
||||
"case_id": meta.get("case_id", ""),
|
||||
"category": meta.get("category", "未知"),
|
||||
"description": meta.get("description", ""),
|
||||
"size": fpath.stat().st_size,
|
||||
@@ -1047,6 +1048,7 @@ async def test_page(request: Request, current=Depends(require_login)):
|
||||
# DB 还没这条记录 —— 标记为"从未测试"
|
||||
results.append({
|
||||
"filename": fpath.name,
|
||||
"case_id": meta.get("case_id", ""),
|
||||
"category": meta.get("category", "未知"),
|
||||
"description": meta.get("description", ""),
|
||||
"size": fpath.stat().st_size,
|
||||
@@ -1105,6 +1107,7 @@ async def test_page(request: Request, current=Depends(require_login)):
|
||||
|
||||
results.append({
|
||||
"filename": fpath.name,
|
||||
"case_id": meta.get("case_id", ""),
|
||||
"category": meta.get("category", "未知"),
|
||||
"description": meta.get("description", ""),
|
||||
"size": task.size or fpath.stat().st_size,
|
||||
|
||||
@@ -254,6 +254,107 @@ class BinaryEngine(Engine):
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
|
||||
# 5) UPX 壳显式检测 —— 检查节名 UPX0 / UPX1 / UPX!
|
||||
upx_sections = []
|
||||
for section in getattr(pe, "sections", []) or []:
|
||||
try:
|
||||
name = section.Name.rstrip(b"\x00").decode("utf-8", errors="replace")
|
||||
if name.upper().startswith("UPX"):
|
||||
upx_sections.append(name)
|
||||
except Exception:
|
||||
continue
|
||||
if upx_sections:
|
||||
findings.append(
|
||||
Finding(
|
||||
engine=self.name,
|
||||
layer=self.layer,
|
||||
severity=Severity.MEDIUM.value,
|
||||
rule="UPXPackerDetected",
|
||||
detail=f"检测到 UPX 加壳节:{', '.join(upx_sections)}",
|
||||
weight=30.0,
|
||||
)
|
||||
)
|
||||
|
||||
# 6) RWX 可写可执行节 —— 高危(绕过 DEP 的典型手法)
|
||||
from pefile import SECTION_CHARACTERISTICS # noqa: PLC0415
|
||||
MEM_EXECUTE = SECTION_CHARACTERISTICS["IMAGE_SCN_MEM_EXECUTE"]
|
||||
MEM_WRITE = SECTION_CHARACTERISTICS["IMAGE_SCN_MEM_WRITE"]
|
||||
rwx_sections = []
|
||||
for section in getattr(pe, "sections", []) or []:
|
||||
try:
|
||||
flags = section.Characteristics
|
||||
if (flags & MEM_EXECUTE) and (flags & MEM_WRITE):
|
||||
name = section.Name.rstrip(b"\x00").decode("utf-8", errors="replace")
|
||||
rwx_sections.append(name)
|
||||
except Exception:
|
||||
continue
|
||||
if rwx_sections:
|
||||
findings.append(
|
||||
Finding(
|
||||
engine=self.name,
|
||||
layer=self.layer,
|
||||
severity=Severity.HIGH.value,
|
||||
rule="RWXSectionDetected",
|
||||
detail=f"检测到可写且可执行的危险节:{', '.join(rwx_sections)}",
|
||||
weight=40.0,
|
||||
)
|
||||
)
|
||||
|
||||
# 7) 32/64 位识别(info 级别,辅助判断)
|
||||
machine = None
|
||||
pe32 = None
|
||||
try:
|
||||
machine = int(pe.FILE_HEADER.Machine)
|
||||
pe32 = (pe.OPTIONAL_HEADER.Magic == 0x10B) # PE32
|
||||
except Exception:
|
||||
pass
|
||||
if machine is not None:
|
||||
try:
|
||||
from pefile import MACHINE_TYPES # noqa: PLC0415
|
||||
machine_name = MACHINE_TYPES.get(machine, f"UNKNOWN(0x{machine:04x})")
|
||||
except Exception:
|
||||
machine_name = f"0x{machine:04x}"
|
||||
bits = "32-bit" if pe32 else "64-bit"
|
||||
findings.append(
|
||||
Finding(
|
||||
engine=self.name,
|
||||
layer=self.layer,
|
||||
severity=Severity.LOW.value,
|
||||
rule="PEArchInfo",
|
||||
detail=f"PE 架构:{machine_name} / {bits}",
|
||||
weight=0.0,
|
||||
)
|
||||
)
|
||||
|
||||
# 8) 调试信息(pdb 路径或 debug 节)
|
||||
has_debug_dir = False
|
||||
has_debug_section = False
|
||||
try:
|
||||
debug_dir = pe.OPTIONAL_HEADER.DATA_DIRECTORY[6] # IMAGE_DIRECTORY_ENTRY_DEBUG
|
||||
if debug_dir.VirtualAddress and debug_dir.Size:
|
||||
has_debug_dir = True
|
||||
except Exception:
|
||||
pass
|
||||
for section in getattr(pe, "sections", []) or []:
|
||||
try:
|
||||
name = section.Name.rstrip(b"\x00").decode("utf-8", errors="replace").lower()
|
||||
if ".debug" in name or name.startswith("debug") or name.startswith(".pdb"):
|
||||
has_debug_section = True
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
if has_debug_dir or has_debug_section:
|
||||
findings.append(
|
||||
Finding(
|
||||
engine=self.name,
|
||||
layer=self.layer,
|
||||
severity=Severity.LOW.value,
|
||||
rule="DebugInformationPresent",
|
||||
detail="PE 包含调试信息(PDB 路径或 .debug 节),可用于逆向定位",
|
||||
weight=10.0,
|
||||
)
|
||||
)
|
||||
|
||||
return findings
|
||||
|
||||
def _suspicious_imports(self, pe: Any) -> List[str]:
|
||||
|
||||
@@ -90,10 +90,11 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:40px;">#</th>
|
||||
<th style="width:70px;">用例编号</th>
|
||||
<th style="width:30px;">#</th>
|
||||
<th style="width:50px;">结果</th>
|
||||
<th>样本文件</th>
|
||||
<th style="width:80px;">分类</th>
|
||||
<th style="width:80px;">层</th>
|
||||
<th style="width:180px;">期望裁决 · 规则</th>
|
||||
<th style="width:200px;">检测结论 · 规则</th>
|
||||
<th style="width:60px;">方向</th>
|
||||
@@ -106,6 +107,13 @@
|
||||
<tbody>
|
||||
{% for r in results %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if r.case_id %}
|
||||
<span class="chip chip-info" style="font-family:monospace;font-size:11px;">{{ r.case_id }}</span>
|
||||
{% else %}
|
||||
<span style="color:#ccc;">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="color:#999;font-size:12px;">{{ loop.index }}</td>
|
||||
<td class="{% if r.overall_ok %}pass-mark{% else %}fail-mark{% endif %}">
|
||||
{% if r.overall_ok %}✅{% else %}❌{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user