目录
RCE
RCE为两种漏洞的缩写,分别为Remote Command/Code Execute,远程命令/代码执行
一、命令执行漏洞
程序员使用脚本语言(比如PHP )开发应用程序过程中,脚本语言开发十分快速、简介,方便,但是也伴随着一些问题。比如说速度慢,或者无法接触系统底层,如果我们开发的应用特别是企业级的一些应用需要去调用一些外部程序。当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如PHP中的system,exec,shell_exec等,当用户可以控制命令执行函数中的参数时,将可注入恶意系统命令到正常命令中,造成命令执行攻击
也就是说命令执行即直接调用操作系统的命令。其原理是,在操作系统中,“&、|、||”都可以作为命令连接符使用,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,将用户的输入作为系统命令的参数拼接到命令行中,在没有过滤用户输入的情况下,造成命令执行漏洞。
命令连接符
win与linux中常用的命令连接符如下
windows中
&,&&,|,||
- a&b,两个命令会同时执行,就算前面的命令执行失败后面的命令也会执行
- a&&b,两个命令会同时执行,但是如果前面的命令执行失败,后面的命令则不会执行
- a|b,前面的命令不执行,只执行最后面的命令。但是如果第一个命令执行失败,则不会执行后面的命令
- a||b,前面的命令能正常执行,则只执行前面的命令,不执行后面的命令。若前面命令执行失败,则执行后面的命令
Linux中
&,&&,|,||,;
- a&b,两个命令会同时执行,就算前面的命令执行失败后面的命令也会执行
- a&&b,两个命令会同时执行,但是如果前面的命令执行失败,后面的命令则不会执行
- a|b,前面的命令不执行,只执行最后面的命令。就算前面的命令执行失败后面的命令也会执行
- a||b,前面的命令能正常执行,则只执行前面的命令,不执行后面的命令。若前面命令执行失败,则执行后面的命令
- a;b,两个命令会同时执行,就算前面的命令执行失败后面的命令也会执行
漏洞危害
继承Web服务程序的权限去执行系统命令或读写文件
反弹shell
PHP中常见的命令执行函数
命令执行案例,传送门 -》DVWA之命令注入漏洞(Command injection)
system()
将字符串作为OS 命令执行,自带输出功能,不需要打印
<?php
system('whoami');
?>
exec()
将字符串作为OS 命令执行,需要输出执行结果
<?php
echo exec('whoami');
?>
shell_exec()
执行shell命令并返回输出的结果的字符串,需要输出执行的结果
<?php
echo shell_exec('whoami');
?>
passthru()
将字符串作为OS 命令执行,自带输出功能,不需要打印
<?php
passthru('whoami');
?>
popen()
将字符串当作OS命令来执行,但是该函数返回的是文件指针而非命令执行结果。该函数有两个参数。
<?php
$file = popen('whoami', 'r');
echo $file;
?>
反引号 ` `
反引号里面的代码也会被当作OS命令来执行
<?php
echo `whoami`;
?>
命令执行漏洞防御
- 尽量减少命令执行函数的使用,并在disable_functions 中禁用
- 在进入命令执行的函数或方法之前,对参数进行过滤
- 参数的值尽量使用引号包裹,并在拼接前调用addslashes 进行转义
二、代码执行漏洞
应用程序在调用一些能够将字符串转换为代码的函数(如PHP中的eval(),eval可以将字符串当做函数进行执行)时,没有考虑用户是否控制这个字符串,将造成代码执行漏洞。一般很难通过黑盒查找漏洞,大部分都是根据源代码判断代码执行漏洞。
代码执行(注入)类似于SQL 注入漏洞,SQLi 是将SQL 语句注入到数据库中执行,而代码执行则是可以把代码注入到应用中最终由服务器运行它。这样的漏洞如果没有特殊的过滤,相当于直接有一个Web 后门的存在。
漏洞危害
可以通过代码执行漏洞继承Web 用户权限,执行任意代码。如果服务器没有正确配置,Web 用户权限比较高的话,我们可以读写目标服务器任意文件内容,甚至控制整个网站以及服务器。
PHP中的代码执行函数
- eval() 将字符串当作php 代码执行
- assert() 同样会作为PHP 代码执行
- call_user_func() 回调函数,可以使用is_callable查看是否可以进行调用
- call_user_fuc_array() 回调函数,参数为数组
- create_function() 创建匿名函数
- preg_replace() 当php版本小于7时,当为 /e 时代码会执行
- array_map() 为数组的每个元素应用回调函数
- array_filter() 依次将 array 数组中的每个值传递到 callback 函数。如果 callback 函数返回 true,则 array 数组的当前值会被包含,在返回的结果数组中。数组的键名保留不变。
- usort() 使用自定义函数对数组进行排序
一句话木马就是利用的代码执行漏洞:
<?php @eval($_POST[cmd]);?>
eval()
eval() 会将字符串当作php 代码执行。 该字符串必须是合法的 PHP 代码。eval函数自带输出功能,不需要再使用echo进行输出。
<?php
eval(phpinfo());
?>
assert
assert() 同样会作为PHP 代码执行。使用方法和eval一样
<?php
assert(phpinfo());
?>
preg_replace()
preg_replace() 函数执行一个正则表达式的搜索和替换。
preg_replace ($pattern ,$replacement ,$subject)
搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换
- $pattern: 要搜索的模式,可以是字符串或一个字符串数组。
- $replacement: 用于替换的字符串或字符串数组。
- $subject: 要搜索替换的目标字符串或字符串数组。
基本用法如下:
搜索字符串中的",并在其前面添加\进行转义
<?php
$b = "hello\"";
$a = preg_replace('/\"/',"\\\"",$b);
echo "替换前的语句 ".$b;
echo "<br/>";
echo "替换后的语句: ".$a;
?>
正则说明:
- /字符/,两个反斜杠用来声明正则,正则的最基本用法。表示其为正则表达式,里面的内容是表达式的式子
- " \\\" ",其中三个反斜杠是什么意思了?。上面是要在双引号前加反斜杠,所以 \"就是我们要替换成的字符。由于"需要转义,不转义会被认为是引号的意思,所以需要一个\转义,所以就变成了\\",然后由于添加的\会被认为是转义符,所以还需要加上\,所以最终是三个反斜杠
当$pattern 处,即第一个参数存在e 修饰符时,$replacement 的值会被当成PHP 代码来执行。
/e 可执行模式,此为PHP专有参数。典型的代码如下
<?php
if(isset($_GET['code'])){
preg_replace("/\[(.*)\]/e",'\\1', $_GET['code']);
//echo "how are you";
}else{
echo "Please submit code!<br />?code=[phpinfo();]";
}
?>
提交参数 ?code=[phpinfo();]
call_user_func()
回调函数。call_user_func() 等函数都有调用其他函数的功能,其中的一个参数作为要调用的函数名,那如果这个传入的函数名可控,那就可以调用其他的函数来执行我们想要的代码,也就是存在任意代码执行漏洞。
以call_user_func() 为例子,该函数的第一个参数作为回调函数,后面的参数为回调函数的参数,测试代码如下
提交参数 ?fun=assert¶=phpinfo()
代码执行漏洞防御
- 保证用户不能轻易接触 eval()函数 的参数或者用正则严格判断输入的数据格式
- 字符串使用单引号包裹,并在插入前进行 addslashes()
- 对preg_replace()放弃使用e修饰符,保证第二个参数中对于正则匹配出的对象,用单引号包裹