无参函数的RCE
最近遇到挺多rce的题,这里记录一下关于无参函数的rce。
先看看代码:
<?php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);
} else {
show_source(__FILE__);
}
?>
很明了,get的code只能是函数形式的,且不能带参数。
也就是a();
a(a());
这种可以,不能是a('1');
这种。
这里有几种不同的方法来达到rce的目的。这里我们可以使用函数,但不能传入参数,所以我们就想办法用函数来代替我们想要传入的参数。
还要考虑的是,我们用什么方式来传递参数,很容易想到,常规的get、post可以传参,http headers也可以用来传参。
先来看看用http headers如何传参。
http头中又有那么多内容,而最容易想到的就是利用cookies传递参数
查找php中关于session的函数,发现有一个session_id
函数
session_id ([string$id ] ) :string
session_id() 可以用来获取/设置当前会话 ID。
那么可以用这个函数来获取cookie中的phpsessionid了,并且这个值我们是可控的。
但其有限制:
文件会话管理器仅允许会话 ID 中使用以下字符:a-z A-Z 0-9 ,(逗号)和 - 减号)
没事,我们只要数字和字母就可以了,因为可以将我们的参数转化为16进制穿进去,之后再用hex2bin()函数转换回来就可以了。
所以,payload可以为:code=eval(hex2bin(session_id()));
但session_id必须要开启session才可以使用,所以我们要先使用session_start。
最后,payload:eval(hex2bin(session_id(session_start())));
在http头中设置PHPSSID为想要执行代码的16进制
hex("phpinfo();")=706870696e666f28293b
成功rce
还有一种方法就是使用get/post传参。
先来看看几个函数:
get_defined_vars ( void ) : array 返回由所有已定义变量所组成的数组
此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
试一下,
可见我们的b参数在里面,那么这么把它提取出来呢
再找找位置函数
发现GET的参数在数组的第一个,于是用到current函数。
current ( array &$array ) : mixed 返回数组中的当前单元
每个数组中都有一个内部的指针指向它“当前的”单元,初始指向插入到数组中的第一个单元。
此时,我们就可以提取到GET参数的数组了
我们的b在最后一个位置,于是可以用end函数来取出来。
end ( array &$array ) : mixed end()
将 array 的内部指针移动到最后一个单元并返回其值。
成功取到了传入的b参数,于是在配合eval就可以利用参数b来达到rce的目的了。
最终payload:code=eval(end(current(get_defined_vars())));&b=phpinfo();