通用web漏洞应急排查思路(二)

通用web漏洞应急排查思路(二)

什么是开放重定向

开放重定向这个漏洞,在渗透报告里出现频率很高,但很多人对它的危害估计不足。简单来说,就是网站在做跳转时没有对目标 URL 做任何校验,攻击者只要构造一个”看起来是正规站点”的链接,就能把用户悄悄送到钓鱼页面去。

用户看到的链接是 http://yourcompany.com/redirect?url=http://attacker.com,域名前半截是自己公司的,根本没有戒心,点进去就中招了。

攻击面有哪些?

开放重定向的触发点比想象中要多:

  • 最常见的是 URL 参数直接拼接跳转,比如 ?next=?url=?redirect= 这类参数名
  • JavaScript 里直接用 window.location 跳转,但目标地址来自用户可控的输入
  • HTML meta refresh 标签的 content 里拼了外部 URL
  • 服务端 HTTP 响应头 Location 里的值没过滤

危害不止是跳转

攻击者用这个漏洞做钓鱼是最直接的场景,但还有一种场景更隐蔽——结合 OAuth 登录流程,把 redirect_uri 改成自己的服务器,直接截获 token。此外,跳转到恶意页面还可能触发浏览器漏洞或强制下载恶意文件,用户毫无感知。

如何在日志里找到它

SOC 分析师在排查时,重点看 GET 请求里的 query 参数是否包含外部 URL 结构。有一个实用的 Nginx 日志正则:

/^.*"GET.*\?.*=(https%3a%2f%2f[a-z0-9-]+%2e[a-z]{2,}).+?.*HTTP\/.*".*$/gm

注意,攻击者经常对 URL 做编码混淆,比如 %3a 是冒号,%2f 是斜杠,直接看 raw 日志会漏掉。碰到在几秒内来自同一个 IP、连续请求同一个参数名的情况,基本可以断定是工具在自动化扫描。

还有一些绕过 WAF 的花样要留意:

  • http://[::]:80/ 这种 IPv6 写法
  • 十进制编码 IP:http://2130706433/ 其实是 http://127.0.0.1
  • 十六进制:http://0x7f000001/

怎么防

开发层面核心就两点:用白名单控制允许跳转的域名,别信任任何用户传进来的 URL。PHP 里可以用 filter_var($url, FILTER_VALIDATE_URL) 做基础校验,但更稳的做法是直接维护一个允许跳转的域名列表,匹配不上就拒绝。

目录遍历:文件路径操控的攻击手法

目录遍历(Directory Traversal)也叫”点点斜杠攻击(dot-dot-slash attack)”,利用的是 Web 应用在拼接文件路径时没有做边界限制,导致攻击者可以跳出 Web 根目录,访问系统上任意文件。

比如一个查看图片的接口长这样:

http://example.com/profiles/picture.php?name=user1.jpg

攻击者只需要把参数改成:

http://example.com/profiles/picture.php?name=../../etc/passwd

如果代码里直接把参数值和路径拼起来,就会读到 /etc/passwd,服务器上的账号信息直接暴露。

和 LFI 有什么区别

新手容易把目录遍历和本地文件包含(LFI)搞混。区别在于攻击的切入点不同:目录遍历是直接操控文件路径参数去读文件;LFI 则是利用 include() 这类函数,把用户输入当作文件名包含进来执行。后者危害更大,因为有代码执行的可能。

触发入口在哪

  • URL 里的文件名参数,最直接
  • Cookie 里存了文件路径,然后服务端用来读文件
  • HTTP 请求头,比如 Referer 或自定义头被用于文件操作
  • 直接构造文件下载请求

日志特征

检测时最核心的关键词就是 ../,以及它的各种编码变体:

形式内容
原始../
URL 编码%2e%2e%2f
双重编码%252e%252e%252f
混合编码..%2f%2e%2e/

Nginx 日志里检测编码后的目录遍历可以用:

/^.*"GET.*\?.*=(%2e%2e%2f).+?.*HTTP\/.*".*$/gm

防御要点

代码层面,用 realpath() 取绝对路径之后,再判断这个路径是否还在允许的根目录下面,这是最可靠的方式。同时对文件名做正则校验,只允许字母、数字、下划线、连字符,遇到任何 ./\ 直接拒绝。WAF 也要配置对应的规则,因为手动覆盖所有编码变体基本不现实。

暴力破解:最原始也最有效的攻击

暴力破解(Brute Force)听起来很”蛮力”,但在实战里效果出奇的好,原因很简单——很多系统没有任何限制,攻击者可以无限次尝试密码,配上字典或者彩虹表,大量弱口令分分钟就被拿下。

攻击类型比你想的要多

暴力破解不只是”猜登录密码”这一种。针对 Web 应用,常见的还有:

  • 目录爆破:用 dirsearch、gobuster 这类工具扫描服务器上隐藏的目录和文件,找到没有权限控制的后台或备份文件
  • 密码喷洒(Password Spraying):用一个常见密码(比如 Welcome123)去试一大批账号,避开单账号多次失败触发的锁定机制
  • 凭证填充(Credential Stuffing):把从其他地方泄露的账号密码组合,直接来试,成功率在有密码复用习惯的用户里相当高

看日志有什么规律

暴力破解在日志里的特征相对明显。主要看几个维度:

  1. 同一个 IP 大量 POST 请求到登录接口,状态码密集出现 401 或 403
  2. 时间间隔极短,正常人登录不会 1 秒发 50 个请求
  3. User-Agent 固定,自动化工具通常不会每次随机换 UA
  4. 成功登录前有大量失败记录,然后突然出现一个 200 或 302

检测 Nginx 日志里的暴力破解,可以用这个正则匹配失败的登录尝试:

/^(\S+) \S+ \S+ \[.*?\] "(POST|GET) \/login\.php.*?" (401|403) \d+ ".*?" ".*?"/gm

捕获到的第一个分组就是攻击者 IP,统计它出现的次数,超过阈值直接加黑名单。

事后能做什么

检测到暴力破解后,处置思路:

  • 用 Fail2ban 自动根据日志特征封 IP,不需要人工干预
  • Nginx 配置里加 deny 规则,把问题 IP 段直接丢弃
  • 结合 SIEM 查这个 IP 有没有其他攻击行为,判断是不是更大攻击链的一部分

防御不是靠一招

账号锁定策略、CAPTCHA、限速、MFA,这几个缺一不可。WAF 可以做 IP 信誉过滤和行为分析,但不能当作唯一防线——复杂的攻击者完全可以换 IP 池绕过。本质上还是要做多层防御,弱密码、没有 MFA 的账号永远是最脆弱的一环。

XXE:XML 解析器中的漏洞

XXE(XML External Entity)是一个在代码审计和渗透测试里经典到不能再经典的漏洞,但在生产环境里依然反复出现,原因是开发者对 XML 解析器的默认行为了解不够。

先理解 XML 的”外部实体”是什么

XML 允许在文档里定义”实体(Entity)”,外部实体可以引用文件系统上的文件或者远程 URL。本来是为了方便复用内容设计的,但如果解析器在处理用户提交的 XML 时不加限制,攻击者就可以定义一个指向 /etc/passwd 的外部实体,然后让服务端把这个文件内容输出出来。

一个典型的 XXE payload 长这样:

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>&xxe;</data>

解析器一执行,/etc/passwd 的内容就被填进了 <data> 标签里。

可能触发的地方

  • 接收 XML 格式 body 的 API 接口(REST 或 SOAP)
  • 网站上传 XML 或 Office 文件的功能(Word/Excel 本质上是 ZIP + XML)
  • 配置文件导入功能

危害有多大

XXE 的利用方式随着目标环境不同有很大差异:

  • 文件读取:最直接,读敏感配置文件、私钥
  • SSRF:把外部实体的 URL 指向内网地址,借服务端发起内网请求,可以用来探测内网服务
  • 拒绝服务(Billion Laughs):定义层层嵌套的实体引用,指数级消耗内存,把解析器搞崩
  • RCE:在特定语言和配置下,XXE 可以链接到远程代码执行

日志里怎么找

XXE 攻击的 payload 里有几个关键词,几乎在所有攻击场景下都会出现:

  • DOCTYPE
  • ENTITY
  • SYSTEM
  • file://
  • http://(外带数据时会有外部 URL)

在 Nginx 日志里检测包含 DOCTYPE 关键字的请求:

^(\S+) - (\S+) \[(.*?)\] "(\S+) (.*?)\?(?=.*?\b21DOCTYPE\b).*? HTTP\/\d\.\d" (\d+) (\d+) "(.*?)" "(.*?)"

另外,盲 XXE(Blind XXE)不会在响应里直接返回文件内容,而是通过 DNS 查询或 HTTP 请求把数据带出去,在日志里可能只能看到异常的外联请求。这时候要结合 DNS 日志或防火墙出站流量一起分析。

PHP 和 Java 各有坑

PHP 的 DOMDocument 默认允许加载外部实体,必须手动调用 libxml_disable_entity_loader(true) 来禁用。Java 的 DocumentBuilder 同样默认不安全,需要显式配置 setFeature 来关掉外部实体和 DOCTYPE 处理。这种”默认不安全”的设计,是这个漏洞长期存在的根本原因。

总结

这四类攻击——开放重定向、目录遍历、暴力破解、XXE——看起来各不相同,但背后有一个共同的根:对用户输入的信任。无论是跳转 URL、文件路径、登录凭据还是 XML 数据,只要来自外部,就必须当作不可信的数据来处理。

从应急响应的角度看,这些攻击留下的日志特征都是可以规律化的。建立好正则规则、配合 SIEM 做聚合分析,大多数情况下都能在攻击尚未成功时发现异常。真正棘手的是那些低频、慢速、多 IP 轮换的攻击,这时候行为基线分析比单纯的规则匹配更有价值。

赞赏

微信赞赏支付宝赞赏

Zgao

愿有一日,安全圈的师傅们都能用上Zgao写的工具。

发表评论