代码执行&命令执行(RCE)

参考文章:
https://zhuanlan.zhihu.com/p/391439312
https://blog.csdn.net/loseheart157/article/details/109305380
https://blog.csdn.net/qq_45521281/article/details/105585709

0x00 前言

之前没有系统的整理过这方面的东西,因为本身做的题和接触到的都没有对这方面考察特别多,前几天做了几道专项考察的题目才发现对这个洞的掌握还不太扎实,特地回来补一补。

0x01 什么是RCE

RCE又称远程代码执行漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统。

RCE可以细分为代码执行和命令执行。代码执行执行的是后端语言的代码,命令执行执行的是系统的命令,直接对系统进行操作。

0x02 RCE产生的原因

归根结底是对用户输入内容的过滤不完善,最终导致用户输入的恶意内容被执行。

0x03 危险函数或触发方式

php代码执行函数:

eval()assert(),create_function(),call_user_func(),call_user_func_array(),uasort(),preg_replace(),array_map()等

此外,${}也可以执行代码(在双引号中倘若有${}出现,那么{}内的内容将被当做php代码块来执行。)

比如:

<?php
${phpinfo()};
?>

php命令执行函数:

system()
system — 执行外部程序(命令行),并且显示输出
这个函数会将结果直接进行输出 (注意:是直接输出区别于返回值,因为这个,我一般不用它),命令成功后返回输出的最后一行,失败返回FALSE

shell_exec()
shell_exec — 通过 shell 环境执行命令 ( 这就意味着这个方法只能在 linux 或 mac os的shell环境中运行 ),并且将完整的输出以字符串的方式返回。如果执行过程中发生错误或者进程不产生输出,则返回 NULL。

exec()
exec — 执行一个外部程序
返回命令执行结果的最后一行内容。不显示回显。如果想要获取命令的输出内容, 请确保使用 output 参数,或者利用这个函数来构建反弹shell。

passthru()
passthru — 执行外部程序并且显示原始输出

此外还有popen(),pcntl_exec()等函数。

0x04 一些基本的利用手法

执行命令的一些方式:

echo、ping等命令后添加|可以追加命令执行

花括号也可以执行命令

反引号可以直接执行其中的命令,某些时候可以利用反引号来起到声东击西的绕过效果。

命令拼接符

windows或linux下:

command1 ; command2 : 先执行command1后执行comnand2
command1 & command2 : 先执行comnand2后执行command1
command1 && command2 : 先执行command1后执行comnand2
command1 | command2 : 只执行command2
command1 || command2 : command1执行失败, 再执行command2(若command1执行成功,就不再执行command2)

0x05 绕过手法

其实命令执行本身是没有什么好说的,直接去执行命令就可以了,一般实际运用中我们更应该关注的是如何找到RCE的点以及找到RCE注入点后如何绕过开发者所做的限制。关于如何找到这个问题,有点偏离本文的话题,所以我们这里需要去了解一下如何去对限制进行规避和绕过。

思路

我们进行绕过的核心思路就是,如何找到后端语言中没有但是系统语言(如shell,powershell,cmd等)中存在的特性。

一、一些通用的绕过姿势

1.空格被限制

可以用以下字符串代替:

< 、<>、%09(tab键)、%20、$IFS$9、$IFS$1、${IFS}、$IFS等,还可以用{} 比如 {cat,flag}

$1-9(数字)是shell编程中的一个位置变量,表示接受到的第多少个参数,如果不传入参数则为空

那么我们这里为什么要在$IFS之后再用$9呢?原因是我们如果直接在$IFS后面加文件名,会导致变量名判断错误,如下所示

它把$IFSflag视作一个变量名了,后面直接没输出了,所以我们后面加个$9作为分割即可。

二、关键字被过滤

比如ctf中常见的flag,php等关键字被过滤导致无法直接读取flag

1.使用转义符号

使用引号,反斜线等符号可以绕过关键字的限制

ca\t /fl\ag
cat fl''ag


2.字符拼接

a=fl;b=ag;cat$IFS$a$b

3.空变量绕过

shell编程中$@是依次获取参数,如果没有参数则为空

绕过的原理就是这个空变量是shell的概念,在php中检测时依旧是fl$@ag这个字符串,不会被正则匹配到

4.通配符绕过

可以使用通配符去绕过文件名中存在关键字的规则

比如以上这种payload就可以绕过cat限制,绕过空格限制,绕过flag关键字的限制。

二、代码执行中函数被过滤

比如存在eval(),我们想借助这个去转到命令执行来获取flag或者是进一步获取系统的操作权限,但是关键的命令执行函数system()等被过滤

1.反引号绕过

也称之为内敛执行

在权限足够的情况下,php中的反引号可以直接执行系统命令(我愿称之为通杀,函数都不需要=。=)

<?php
if(isset($_GET["code"])){
	$code = $_GET["code"];
	if(preg_match("/system/i",$code)){
		die("no hack!");
	}else{
		eval($code);
	}
}else{
	highlight_file(__FILE__);
}
?>

2.编码绕过

base64、16进制、8进制

三、命令执行中命令被过滤

比如过滤掉了cat这种读取命令

1.同功能替代

more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
sh /flag 2>%261 //报错出文件内容
curl file://文件路径	读取文件内容
strings
bash -v	执行文件里的命令,看报错能看到
rev:反序输出

2.空变量绕过

原理同上

3.字符拼接

原理同上

4.从$PATH环境变量里取字符

如下,我们把ls给过滤了

<?php
    if (isset($_GET['code'])) {
        $code = $_GET['code'];
        if (!preg_match("/\&|\|| |\/|ls/i",$code)){
            system($code);
        } else {
            die("NO hack");
        }    
        
    } else {
        highlight_file(__FILE__);    
    }
?>

我们此时就可以看一下环境变量$PATH

一般都是这个

下面就可以截取其中的字符echo出来然后反引号执行

四、记一套应对过滤的组合拳

这里假设过滤了flag等直接读取flag的关键字,限制了输入长度,我们无法一次执行多条命令

我们就可以用如下方式:

这套组合的核心在于\让命令可以连起来,因为它表示换行,也就是说命令没有断开,否则就会出现这种情况

ls -t是将文本按时间排序输出

ls -t > shell将输出输入到shell文件中

sh将其作为shell文件执行,shell中则是我们按照顺序构造好的读取flag的命令,所以就可以绕过限制去执行命令。

此外通过echo去不断进行追加从而写一个shell脚本去执行也可以

0x06 ctf实战

[GXYCTF2019]Ping Ping Ping

提示传参ip

猜测是命令执行,用|执行多条命令试试

可以执行,查看flag.php看看

有过滤,不如先看看index.php,看看过滤的规则

还不能有空格,$IFS$1绕过

拿到源码,可以看到过滤了很多东西,字符,关键字之类的

但是没有过滤反引号,直接内敛执行绕过

?ip=127.0.0.1|cat$IFS$1`ls`

拿到flag。

posted @ 2023-10-13 12:39  M0urn  阅读(579)  评论(0编辑  收藏  举报