摘要:在本文中,我们将着手构建一个EDR(端点检测与响应)工具的核心——端点行为监控器(Sensor)。我们将深入探讨现代EDR是如何超越传统杀毒软件(AV),从“静态文件扫描”进化到“实时行为分析”的。为了绕过AV,攻击者越来越多地使用“就地取材(Living off the Land, LotL)”技术(如利用PowerShell、WMI等系统自带工具)。本文将利用强大的跨平台库,构建一个Python“传感器”守护进程,它能够持续监控端点上的进程创建事件,并重点分析父子进程关系(例如,检测
psutil启动
WINWORD.EXE这样的典型恶意行为),从而捕获传统AV无法识别的威胁。
powershell.exe
关键词:Python, EDR, 端点安全, , 进程监控, 行为分析, 威胁狩猎, LotL
psutil
正文
1. EDR的诞生:当AV“失明”时
传统AV(杀毒软件):像一个“文件扫描仪”。它主要依赖签名来识别已知的恶意文件(如病毒、木马)。
AV的“盲点”:
内存马/无文件攻击:恶意代码只在内存中运行,从不落地为文件,AV无法扫描。
就地取材(LotL)攻击:这是现代攻击者最爱的技巧。他们不再使用自定义的恶意程序,而是利用Windows系统自带的、合法的工具(如,
powershell.exe,
bitsadmin.exe,
wmic.exe)来执行恶意操作(如下载Payload、横向移动)。
rundll32.exe
EDR的“视野”:EDR不(仅仅)关心文件是什么,它更关心进程做了什么。它是一个行为录像机和分析师。
EDR的核心逻辑是:“一个合法的程序(如PowerShell)在错误的时间(凌晨3点)、由错误的发起者(如Adobe Reader)、执行了错误的操作(如发起网络连接到某个俄罗斯IP),那么它就是恶意的。”
2. EDR“传感器”:
psutil
psutil
要实现行为监控,我们的EDR工具必须有一个“传感器”来收集端点上的遥测(Telemetry)数据。(Python System and Process Utilities)是实现这一目标的完美跨平台库。它能让我们访问到:
psutil
进程列表
每个进程的详细信息:PID、名称、命令行、父进程ID(PPID)、网络连接、打开的文件…
环境准备:
Bash
pip install psutil
3. 监控的核心:父子进程关系
在所有行为中,进程创建链(Process Tree)是最重要的入侵指标(IoC)之一。一个合法的,其父进程通常是
powershell.exe(用户启动)或
explorer.exe(计划任务)。
svchost.exe
高危警报(Red Flag):
(Word) ->
WINWORD.EXE ->
cmd.exe
powershell.exe
分析:这几乎100%是恶意宏在执行命令。
(Web服务器) ->
apache.exe
cmd.exe
分析:WebShell在执行系统命令。
->
services.exe
powershell.exe
分析:可能是一个恶意的持久化服务。
我们的第一个EDR传感器,就要专注于实时捕获新创建的进程及其父进程。
4. 代码实现 (
edr_sensor.py)
edr_sensor.py
我们将编写一个守护进程,它会定期(例如每秒)扫描当前进程列表,并与上一秒的“快照”进行对比,从而找出所有新创建的进程,并对其进行分析。
Python
# edr_sensor.py
import psutil
import time
import sys
import argparse
from datetime import datetime
# --- 规则引擎 (简化版) ---
# 定义高危的“父进程 -> 子进程”组合
SUSPICIOUS_PARENT_CHILD_MAP = {
# 父进程列表 (小写)
'winword.exe': ['cmd.exe', 'powershell.exe', 'cscript.exe', 'wscript.exe'],
'excel.exe': ['cmd.exe', 'powershell.exe'],
'powerpnt.exe': ['cmd.exe', 'powershell.exe'],
'acrord32.exe': ['cmd.exe', 'powershell.exe'],
# Web服务器
'apache.exe': ['cmd.exe', 'powershell.exe', '/bin/sh', '/bin/bash'],
'nginx.exe': ['cmd.exe', 'powershell.exe', '/bin/sh', '/bin/bash'],
'httpd.exe': ['cmd.exe', 'powershell.exe', '/bin/sh', '/bin/bash'],
}
def get_process_info(proc: psutil.Process):
"""
安全地获取进程的详细信息。
(psutil在访问已死亡的进程时会抛出异常)
"""
try:
pid = proc.pid
ppid = proc.ppid()
name = proc.name()
cmdline = ' '.join(proc.cmdline())
username = proc.username()
# 获取父进程信息
parent_proc = proc.parent()
parent_name = parent_proc.name() if parent_proc else "N/A"
return {
"pid": pid, "ppid": ppid,
"name": name, "cmdline": cmdline,
"username": username, "parent_name": parent_name
}
except (psutil.NoSuchProcess, psutil.AccessDenied):
return None
def check_rules(proc_info: dict):
"""
对新进程应用我们的安全规则。
"""
if not proc_info:
return
p_name = proc_info['name'].lower()
parent_name = proc_info['parent_name'].lower()
# 规则1: 检查父子进程组合
if parent_name in SUSPICIOUS_PARENT_CHILD_MAP:
if p_name in SUSPICIOUS_PARENT_CHILD_MAP[parent_name]:
log_alert(
"HIGH",
"可疑的进程创建链 (LotL)!",
f"父进程 '{proc_info['parent_name']}' (PID: {proc_info['ppid']}) 启动了子进程 '{proc_info['name']}' (PID: {proc_info['pid']})",
f"命令行: {proc_info['cmdline']}"
)
# 规则2: 检查可疑的命令行 (例如,powershell base64编码)
if p_name == "powershell.exe" and "encodedcommand" in proc_info['cmdline'].lower():
log_alert(
"MEDIUM",
"检测到PowerShell编码命令",
f"进程: {proc_info['name']} (PID: {proc_info['pid']})",
f"命令行: {proc_info['cmdline'][:100]}..." # 截断
)
def log_alert(level, title, description, details):
"""格式化并打印告警。"""
print("
" + "="*60)
print(f"[!!!] {level} 威胁警报 [!!!]")
print(f" 时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f" 标题: {title}")
print(f" 详情: {description}")
print(f" 证据: {details}")
print("="*60 + "
")
def main_loop(poll_interval):
"""EDR传感器的
主循环。"""
print(f"[*] EDR端点传感器已启动。监控间隔: {poll_interval}秒...")
# 获取启动时的进程PID快照
known_pids = {p.pid for p in psutil.process_iter()}
try:
while True:
time.sleep(poll_interval)
current_pids = set()
new_processes = []
# 遍历当前所有进程
for proc in psutil.process_iter():
current_pids.add(proc.pid)
if proc.pid not in known_pids:
# 发现新进程!
new_processes.append(proc)
# 更新已知的PID列表
known_pids = current_pids
if new_processes:
print(f"[*] 检测到 {len(new_processes)} 个新进程...")
for proc in new_processes:
info = get_process_info(proc)
# 对新进程进行规则检查
check_rules(info)
except KeyboardInterrupt:
print("
[*] EDR传感器正在关闭...")
def main():
parser = argparse.ArgumentParser(description="一个基础的EDR端点进程监控传感器。")
parser.add_argument("-i", "--interval", type=int, default=2, help="轮询间隔时间(秒)。")
args = parser.parse_args()
main_loop(args.interval)
if __name__ == "__main__":
if sys.platform == "win32" and not 'ADMIN' in os.environ.get('USERNAME', '').upper():
pass # 在Windows上,非管理员权限可能无法获取所有进程信息
main()
5. 如何测试
运行EDR传感器: 在一个终端中启动传感器(在Windows上,最好以管理员身份运行以获取所有进程信息)。
Bash
python edr_sensor.py
模拟攻击(良性): 打开一个新的终端,简单地运行。
powershell
观察结果: EDR传感器会立即检测到这个新进程,但由于其父进程可能是或
explorer.exe(由你手动启动),这不会触发我们的高危规则。
cmd.exe
模拟攻击(恶意): (这是一个非恶意的模拟,它不会伤害你的电脑) 打开一个Word文档,按下打开VBA编辑器,插入一个新模块,并粘贴以下代码:
Alt + F11
VBA
Sub Auto_Open()
Shell "powershell.exe -e WwB...[base64_string]...", vbHide
End Sub
当你(在受控的VM中!)重新打开这个带有宏的文档时,Word()会启动一个隐藏的
WINWORD.EXE进程。
powershell.exe
观察告警: 我们的EDR传感器会立刻捕获到这个事件,并打印出一个高危告警,因为它命中了这条规则。
'winword.exe' -> 'powershell.exe'
总结
我们成功地利用构建了一个基础的EDR传感器的“大脑”——进程行为监控器。它通过分析进程创建链这一核心指标,已经能够检测到大量基于LotL的、AV无法察觉的恶意活动。
psutil
一个完整的EDR系统,还需要:
监控网络连接和文件修改(同样可通过实现)。
psutil
将这些遥测数据实时地、大规模地发送到一个中央分析平台(我们之前设计的Kafka + Elasticsearch)。














暂无评论内容