基础知识点|命令执行漏洞相关总结

  • A+
所属分类:安全文章
基础知识点|命令执行漏洞相关总结

点击上方蓝字关注我们

0x00 简介

命令执行漏洞是指攻击者可以随意执行系统命令。它属于高危漏洞之一,也属于代码执行的范畴。命令执行漏洞不仅仅存在于B/S架构中,在C/S架构中也常常遇到。

简单的说,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令,可能会允许使用者通过改变$PATH或程序执行环境的其他方面来执行一个恶意构造的代码。

0x01 原理

命令执行漏洞是指应用有时需要调用一些执行系统命令的函数,如:system()exec()shell_exec()eval()passthru(),代码未对用户可控参数做过滤,当用户能控制这些函数中的参数时,就可以将恶意系统命令拼接到正常命令中,从而造成命令执行攻击。

0x02 漏洞产生的原因

  • 没有对用户输入进行过滤或过滤不严

例如:没有过滤&、&&、| 、||等连接符号。

  • 系统漏洞造成的命令执行

bash破壳漏洞(CVE-2014-6271),该漏洞可以构造环境变量的值来执行具有攻击力的脚本代码,会影响到bash交互的多种应用,如http、ssh和dhcp等。

  • 调用的第三方组件存在代码执行漏洞

例如:

php (system() 、 shell_exec() 、 exec() 、 eval())JAVA中的命令执行漏洞(struts2/ElasticsearchGroovy等)ThinkPHP命令执行

0x03 常见连接符(管道符)

  • windows系统支持的连接符:

基础知识点|命令执行漏洞相关总结

  • Linux系统支持的连接符

基础知识点|命令执行漏洞相关总结

0x04 命令执行漏洞与代理漏洞的区别

4.1 命名执行漏洞:直接调用操作系统命令

  • 命令执行漏洞原理:在操作系统中,"&、| 、||"都可以作为命令连接符使用,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令。 

4.2 代码执行漏洞:靠执行脚本代码调用操作系统命令

  • 应用有时需要调用一些执行系统命令的函数,如PHP中的system、exec、assert、shell_exec、passthru、popen、poc_popen、escapeshellcmd、pcntl_exec等,当用户能控制这些函数中的参数时,就可以将恶意系统命令拼接到正常命令中,从而造成命令执行漏洞,这就是命令执行漏洞。以上函数主要也在webshell中用的多,实际上在正常应用中差别不太大,用得最多的还是前三个。

0x05 命令执行漏洞的利用条件

  • 应用调用执行系统命令的函数;

  • 将用户输入作为系统命令的参数拼接到了命令行中;

  • 没有对用户输入过滤或过滤不严。

0x06 命令执行漏洞产生的条件

  • 用户可以控制输入的内容

  • 用户输入的内容被当作命令执行

0x07 命令执行漏洞分类

7.1 命令直接注入执行漏洞

应用程序直接使用了危险的可执行系统命令的函数,比如php的system、exec函数等,并且这些函数的运行参数是用户可控的,若过滤不严格,就会增大命令执行漏洞的概率。命令本地包含执行漏洞。(注:(CGI)系统命令注入执行漏洞示例,就比如Bash漏洞,就属于这类漏洞,用户可以直接更改HTTP头user-agent的值,就可引发命令注入。)

7.2 命令包含执行漏洞

命令本地/远程包含漏洞:应用程序直接包含或执行了用户可控的上传脚本文件或远程文件(URL引用文件),就会触发此漏洞。

7.3 命令反序列执行漏洞

有些动态脚本语言,如php支持实例对象的序列化传输,然后服务端将实例对象反序列化出来并执行解析后实例的构造函数、析构函数或_wakeup()函数,若这些函数利用了用户可控的参数,则会触发命令/代码注入执行漏洞,原理和之前直接注入一样。

7.4 命令动态变量执行漏洞

有些动态脚本语言,如php,支持变量或函数的动态定义,即运行时可通过参数名来动态组装变量、变量值或函数。若代码中包含有类似代码,就会存在动态变量/函数的执行漏洞。

0x08 常见危险函数

8.1 PHP下命令执行函数

  • Eval()

该函数把字符串按照PHP代码来计算。该字符串必须是合法的php代码,且必须以分号结尾。如果没有在代码字符串中调用return语句,则返回NULL。如果代码中存在解析错误,则eval()函数返回false。

语法:eval(phpcode) phpcode必需。规定要计算的php代码。

例子:

<?php $a=$_GET['a'];eval($a);?>
http://127.0.0.1/oscommand/1.php?a=phpinfo();
  • Assert()

检查一个断言是否为false。

语法:

PHP 5 : bool assert(mixed assertion [, stringdescription])PHP 7 : bool assert(mixed assertion [, Throwableexception])assert() 会检查指定的 assertion 并在结果为false时采取适当的行动。

例子:

<?php $a = $_GET['a'];assert($a); ?> http://127.0.0.1/oscommand/1.php?a=phpinfo(); http://127.0.0.1/oscommand/1.php?a=phpinfo()
  • Preg_replace()

该函数执行一个正则表达式的搜索和替换。

语法:

mixed preg_replace(mixed pattern,mixed replacement,mixed subject [,int limit=-1 [,int &$count]])搜索subject 中匹配pattern的部分,以replacement进行替换。

参数说明:

pattern:要搜索的模式,可以是字符串或一个字符串数组。当pattern处存在一个"/e"修饰符时,$replacement的值会被当成php代码来执行。$replacement:用于替换的字符串或字符串数组。$subject:要搜索替换的目标字符串或字符串数组。$limit:可选,对于每个模式用于每个subject字符串的最大可替换次数。默认是-1(无限制)。$count:可选,为替换执行的次数。

例子:

<?php $a = $_GET['a']; echo preg_replace("/test/e", $a, "just test!") ?> http://127.0.0.1/oscommand/1.php?a=phpinfo()

注:在php5.4及以下版本中,preg_replace()可正常执行代码,而在php5.5及后续版本中提醒"/e"修饰符已被弃用,要求用preg_replace_callback()函数来代替。

  • Call_user_func()

该函数把第一个参数作为回调函数调用。

语法:

mixed call_user_func(callable callback [,mixed paremeter [,mixed $...]])第一个参数callback 是被调用的回调函数,其余参数是回调函数的参数。

例子:

<?php call_user_func($_GET['a'],$_GET['b']); ?> http://127.0.0.1/oscommand/1.php?a=assert&b=phpinfo()
  • call_user_func_array

  • create_function

  • array_map

  • system

该函数命令执行后的返回值存在输出值的最后一行,函数本身也会打印全部输出值。

语法:

system(string $command [,int $return_var])函数执行command参数所指定的命令,并输出结果。string和int是参数的数据类型,分别是字符串和整数。command:要执行的命令。return_var:如果提供return_var参数,则外部命令执行后的返回状态会被设置到此变量中。如果成功执行则状态码为0;如果执行失败状态码为1.
  • Exec

该函数命令执行后的值为输出值的最后一行,函数并不会打印任何内容。

语法:

exec ( string KaTeX parse error: Expected 'EOF', got '&' at position 18: …mmand [, array &̲output [, int &$return_var ]] )函数执行command参数所指定的命令。string、array、int是参数的数据类型,分别是字符串、数组和整数/中括号的意思是如果前一个参数存在,那么中括号中的参数可以不写。例如:如果存在$command参数,则$output参数可有可无;如果不存在ouput参数,则$return_var也不能出现。command:要执行的命令。output:如果提供了output参数,那么会用命令执行的输出填充此数组,每行输出填充数组中的一个元素。数组中的数据不包括行位的空白字符,例如n字符。如果数组中自己包含了部分元素,exec()函数会在数组末尾追加内容。如果不想在数组末尾追加,输入exec()函数前使用unset()函数进行重置。return_var:如果同时提供output和return_var参数,命令执行后的返回状态会被写入到此变量。如果命令成功执行,则状态码为0;如果命令执行失败,则状态码为1。
  • Shell_exec

该函数会在命令执行后将所有输出值作为字符串输入返回值,本身并不打印任何信息。

语法:

shell_exec(string $cmd)cmd是要执行的命令。string是参数的数据类型,也就是字符串。shell_exec函数的用法和反引号相同。
  • Passthru

该函数本身会打印全部输出值,但该函数没有返回值。

语法:

passthru ( string KaTeX parse error: Expected 'EOF', got '&' at position 16: command [, int &̲return_var ] )string和int是参数的数据类型,分别为字符串和整型。passthru()函数也是用来执行command的。当所执行的系统命令输出二进制数据,并且需要直接传送到浏览器的时候,需要此函数来代替exec()或system()函数。command:要执行的命令。return_var:如果提供return_var参数,Unix命令返回状态会被记录到此参数。
  • pcntl_exec

  • popen

  • proc_open

  • ob_start()

  • unserialize()

  • usort()

  • uasort()

  • ukaort()

  • array_reduce()

  • escapeshellarg

该函数过滤一个字符串参数,原理是给字符串添加单引号,而shell不会解释单引号中的特殊字符。如果字符串中已经有单引号了,那么该函数会分段处理这个字符串,对字符串中的单引号做转义,并以之分段,也就是这种形式'...'"...'。也可以说,单引号是就近匹配的。这个函数应该用来过滤单个的shell函数的参数。

  • escapeshellcmd

该函数应该被用来过滤整个命令字符串(而不是单个参数),转义shell元字符。

  • 反引号(``)

php支持一个执行运算符:反引号``。php将尝试将反引号中的内容作为外壳命令执行,并将输出信息作为返回值返回(即可以赋给一个变量而不是简单的丢弃到标准输出)。使用反引号运算符到效果与函数shell_exec()相同。反引号运算符在激活了安全模式或者关闭了shell_exec()时是无效的。

8.2 系统命令执行漏洞

  • system()

  • exec()

  • shell_exec()

  • passthru()

  • pcntl_exec()

  • popen()

  • proc_open()

  • 反引号(``)

  • ob_start()

0x09 命令执行漏洞常见可控位置

  • 常见可控位置情况有以下几种:

基础知识点|命令执行漏洞相关总结

  • 示例

sys=ctypes.cdll.LoadLibrary('/lib64/libc.so.6')
sys.system(cmd)

9.1 第一种情况

如果能直接控制$arg,那么就能执行任意命令了。

9.2 第二种情况

能够控制的点是程序的整个参数,可以直接用&& 、|| 或 |等等,利用与、或、管道命令来执行其他命令(可以涉及到很多linux命令行技巧)。还有一个偏门,当$argescapeshellcmd处理之后,不能越出这个外部程序的范围,可以看看这个程序自身是否有"执行外部命令"的参数或功能,比如linux下的sendmail命令自带读写文件功能,可以用来写webshell。

9.3 第三种情况

控制的点是一个参数,也同样可以利用与、或、管道来执行其他命令,情景与二无异。

9.4 第四种情况

这种情况压力大一点,有双引号包囊。如果引号没有被转义,可以先闭合引号,称为第三种情况后按照第三种情况来利用,如果引号被转义(addslashes),也不必着急。linux shell环境下双引号中间点变量也是可以被解析点,可以在双引号内利用反引号执行任意命令id

9.5 第五种情况

这是最难受的一种情况了,因为单引号内只是一个字符串,要先闭合单引号才可以执行命令。如:system("/bin/prog -p='aaa' | id")。危害自然不言而喻,执行命令可以读写文件、反弹shell、获得系统权限、内网渗透等。

在漏洞检测中,除了有回显的命令注入(比如执行dir命令或者cat读取系统文件);还可以使用盲打的方式,比如curl远程机器的某个目录(看access.log),或者通过dns解析的方式获取到漏洞机器发出的请求。

0x10 命令执行漏洞的危害

  • 继承web服务器程序的权限,去执行系统命令或读写系统文件

  • 反弹内外shell

  • 控制整个web服务器

  • 辅助内网渗透

  • 恶意木马被种植

  • 挂马、钓鱼

  • 敏感信息泄漏

0x11 命令执行漏洞的防御(修复)

  • 尽量少用执行命令的函数或者直接禁用,在php下禁用高危系统函数,找到php.ini,查找disable_functions,添加禁用的函数名

  • 参数值尽量使用引号包括,并在拼接前调用addslashes函数进行转义

  • 在使用动态函数之前,确保使用的函数是指定的函数之一

  • 在进入执行命令的函数/方法之前,对参数进行过滤,对敏感字符进行转义

  • 对于可控点是程序参数的情况下,使用escapeshellcmd函数进行过滤,对于可控点是程序参数值的情况下,使用escapeshellarg函数进行过滤。使用 escapeshellarg函数处理相关参数。该函数会将用户引起参数或命令结束的字符进行转义,如单引号"''"会被转义为"'",双引号""""会被转义为""",分号";"会被转义为";",这样escapeshellarg会将参数内容限制在一对单引号或双引号里面,转义参数中包括的单引号或双引号,使其无法对当前执行进行截断,实现防范注入攻击的目的。

  • 不执行外部的应用程序或命令。尽量使用自定义函数或函数库实现外部应用程序或命令的功能。在执行system、eval等命令功能的函数前,要确认参数内容。

  • 使用safe_mode_exec_dir指定可执行的文件路径。将php.ini文件中的safe_mode设置为On,然后将允许执行的文件放入一个目录,并使用safe_mode_exec_dir指定这个可执行的文件路径。这样,在需要执行相应的外部程序时,程序必须在safe_mode_exec_dir指定的目录中才会允许执行否则将失败。

0x12 示例

  • windows使用phpstudy集成环境,在网站根目录下建立php文件(自定义)。

<?php        echo "please input get args cmd!";        echo "<pre>";   //格式化页面        if(isset($_GET["cmd"])){                system($_GET["cmd"]);        }        echo "</pre>";  //是页面更加直观,起换行作用。去掉的话,显示信息不会换行。下面做对比。?>

基础知识点|命令执行漏洞相关总结

  • 输入命令:?cmd=ipconfig

基础知识点|命令执行漏洞相关总结

  • 现在修改一下代码,看看<pre>的作用是什么。在URL前面加个view-source:也是可以的。

基础知识点|命令执行漏洞相关总结

基础知识点|命令执行漏洞相关总结

  • 对指定目录执行ping命令

<?php        echo "<pre>";   //格式化输出        $arg = $_GET['cmd'];    //GET方式执行命令        if($arg){            system("ping $arg");        }        echo "</pre>";
  • 打开cmd ,执行以下命令

ping www.baidu.comping 111 & ipconfigping 127.0.0.1 && ipconfigping 127.0.0.1 | ipconfigping 111 || ipconfig

基础知识点|命令执行漏洞相关总结

0x13 总结

如有不对之处请各位师傅指正!



基础知识点|命令执行漏洞相关总结



原文始发于微信公众号(灼剑安全团队):基础知识点|命令执行漏洞相关总结

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: