最近遇到挺多rce的题,这里记录一下关于无参函数的rce。
先看看代码:
1 |
|
http headers传参进行RCE
查找php中关于session的函数,发现有一个session_id
函数
1 | 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进制
1 | hex("phpinfo();")=706870696e666f28293b |
成功rce
使用get/post传参进行RCE
先来看看几个函数:
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();
使用函数读取文件
读取当前目录下的文件
读取当前目录下的文件关键在于使用scandir(".")
等函数将当前目录中的文件列出来,之后再使用readfile()
等函数来读取文件。
获得”.”
- 使用chr()函数。
chr() //将数字当做ascii码转化成字符,传入的参数会自动模256
- 使用time()函数动态生成数字:
time()
函数返回时间戳,配合chr()
,一定时间内一定会有chr(time())
生成的字符为.
- 构造
chr(46)
生成.
:
chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))
- 使用time()函数动态生成数字:
- 使用dirname(xxx)可以生成
.
例如:1
2
3dirname(time())
dirname(True)
dirname(phpversion()) - 用其他函数。
current(localeconv())
的值也为.
读取文件
获取.
后可以使用scandir()
等函数列举当前目录下的文件,之后再使用数组相关函数来得到特定文件,最后使用readfile()
等函数读取文件
例如:
1 | readfile(next(array_reverse(scandir(chr(time()))))) //读取倒数第二个文件 |
读取上级目录下的文件
读取上级目录的文件的基本思想是先使用chdir()
改变工作目录,之后再读取目录下的文件。
跳转到上一级
绝对路径
使用getcwd()
可获得当前目录路径,再使用dirname()
即可获得当前目录的上一级目录路径
即:chdir(dirname(getcwd()))
即可跳转到上一级目录相对路径
使用相对路径进行目录跳转关键在于获得..
,而..
可以由next(scandir("."))
获得。
这里的.
的获得可以使用上面的方法。
读取文件
跳转目录后还需要再进行列目录,读文件的操作,因此这时还需要.
。
目录跳转后chdir
返回的是布尔型
dirname()
可以接受布尔型参数,并且返回值恰好为.
因此,可以这样写:dirname(chdir(".."))
time()
可以接受布尔型参数,可以再使用chr()
获得一个.
来列当前目录的文件。current(localtime(time(chdir(".."))))
结果为当前时间的秒数,也就是一分钟内会有一次值为46.
列目录下的文件:scandir(chr(current(localtime(time(chdir(".."))))))
再使用
scandir
扫描目录:`scandir(chr(time(chdir(next(scandir(chr(time()))))))若跳转目录时使用的
time()
函数获得的"."
,那么此时的chr(time())
值就为.
.scandir(chr(time(chdir(next(scandir(chr(time()))))))
列出目录后就可以使用数组相关函数和读文件函数来读文件了。
相关函数
1 | getallheaders() //获取所有http header信息,返回一个数组 |