說到fastcgi,大家都知道這是目前最常見的webserver動態指令碼執行模型之一。目前基本所有web指令碼都基本支援這種模式,甚至有的型別指令碼這是唯一的模式(ror,python等)。
fastcgi的主要目的就是,將webserver和動態語言的執行分開為兩個不同的常駐程序,當webserver接收到動態指令碼的請求,就通過fcgi協議將請求通過網路**給fcgi程序,由fcgi程序進行處理之後,再將結果傳送給webserver,然後webserver再輸出給瀏覽器。這種模型由於不用每次請求都重新啟動一次cgi,也不用嵌入指令碼解析器到webserver中去,因此可伸縮性很強,一旦動態指令碼請求量增加,就可以將後端fcgi程序單獨設立乙個集群提供服務,很大的增加了可維護性,這也是為什麼fcgi等類似模式如此流行的原因之一。
然而正是因為這種模式,卻也帶來了一些問題。例如去年80sec發布的
《nginx檔案解析漏洞》
實際上就是由於fcgi和webserver對script路徑級引數的理解不同出現的問題。除此之外,由於fcgi和webserver是通過網路進行溝通的,因此目前越來越多的集群將fcgi直接繫結在公網上,所有人都可以對其進行訪問。這樣就意味著,任何人都可以偽裝成webserver,讓fcgi執行我們想執行的指令碼內容。
ok,以上就是背景原理解釋,我這裡就用我最熟悉的php給各位做個例子。
php的fastcgi目前通常叫做fpm。他預設監聽的埠是9000埠。我們這裡用nmap直接掃瞄一下:
nmap -sv -p 9000 --open x.x.x.x/24
為什麼要用sv?因為9000埠可能還存在其他服務,這裡需要借用nmap的指紋識別先幫我們鑑定一下。
[root@test:~/work/fcgi]#nmap -sv -p 9000 --open 173.***.***.1/24
為了做測試,我寫了乙個fastcgi的客戶端程式,直接向對方發起請求。我們利用乙個開放的fastcgi能有什麼作用?這裡和普通的http請求有一點不同,因為webserver為了提供fastcgi一些引數,每次**請求的時候,會通過fastcgi_params的包向fcgi程序進行傳遞。本來這些引數是使用者不可控的,但是既然這個fcgi對外開放,那麼也就說明我們可以通過設定這些引數,來讓我們去做一些原本做不到的事情:
[root@test:~/work/fcgi]#./fcgi_exp read 173.***.***.183 9000 /etc/issue
x-powered-by: php/5.3.2-1ubuntu4.9
content-type: text/html
ubuntu 10.04.3 lts \n \l
讀到了/etc/issue檔案,可以看到這是臺ubuntu 10.04的機器。那又是怎麼實現的呢?其實我們只要在fastcgi_params中,設定 document_root為"/"根目錄即可,隨後再設定script_filename為/etc/issue。這樣,只要我們有許可權,我們就可以控制fcgi去讀取這台機器上的任意檔案了。實際上這並不是讀取,
而是用php去執行它
。 既然是執行,所以其實這個漏洞就類似於乙個普通的lfi漏洞,如果你知道這台機器上的log路徑,或者任何你可以控制內容的檔案路徑,你就可以執行任意**了。
到此為止了麼?不,如果利用log或者去猜其他檔案路徑去執行**,還是不夠方便,有沒有更為方便的利用方式可以讓我執行任意我提交的**呢?
這裡我也找了很多辦法,最先想到的是傳遞env引數過去然後去執行/proc/self/environ檔案,可惜php-fpm在接收到我的引數值後只是在記憶體中修改了環境變數,並不會直接改動這個檔案。因此沒法利用。況且這個方式也不是所有系統都通用。
我們還有一種方法,在我之前寫的
《cve-2012-1823(php-cgi rce)的poc及技術挑戰》
中,可以通過動態修改php.ini中的auto_prepend_file的值,去遠端執行任意檔案。將乙個lfi的漏洞變成了rfi,這樣可利用空間就大大增加。
fastcgi是否也支援類似的動態修改php的配置?我查了一下資料,發現原本fpm是不支援的,直到
某開發者提交了乙個bug
,php官方才將
此特性merge到php 5.3.3的原始碼中去。
通用通過設定fastcgi_params,我們可以利用php_admin_value和php_value去動態修改php的設定。
env["request_method"] = "post"
env["php_value"] = "auto_prepend_file = php://input"
env["php_admin_value"] = "allow_url_include = on\ndisable_functions = \nsafe_mode = off"
利用執行php://input,然後在post的內容中寫入我們的php**,這樣就可以直接執行了。
[root@test:~/work/fcgi]#./fcgi_exp system 127.0.0.1 9000 /tmp/a.php "id; uname -a"
x-powered-by: php/5.5.0-dev
content-type: text/html
uid=500(www) gid=500(www) groups=500(www)
linux test 2.6.18-308.13.1.el5 #1 smp tue aug 21 17:51:21 edt 2012 x86_64 x86_64 x86_64 gnu/linux
細心者會注意到這裡有些變化,我換了本機做測試。因為開始發現的那台機器php版本是5.3.2,正好低於5.3.3,因此無法利用修改ini設定去執行**,只能去猜路徑。
另乙個變化是,我這裡去讀取/tmp/a.php這個php檔案,而不是去讀取/etc/issue。因為在5.3.9開始,php官方加入了乙個配置"security.limit_extensions",預設狀態下只允許執行擴充套件名為".php"的檔案。因此你必須找到乙個已經存在的php檔案。而這個設定是php-fpm.conf裡的,無法通過修改ini的配置去覆蓋它。如果誰能有更好的辦法可以繞過這個限制,請告訴我。
ok,目前為止對php-fpm的所有測試已經結束,我們利用乙個對外開放的fcgi程序,已經可以直接獲取shell了。各位不如也去研究一下其他fcgi,或許會有更多發現。
如何防止這個漏洞?很簡單,千萬不要把fcgi介面對公網暴露。同時也希望將來fcgi會有身份認證機制。
文中使用到的測試程式及原始碼可以
任何系統上編譯,請安裝golang之後,執行:
go build fcgi_exp.go
利用x server遠端顯示Linux GUI
經過1個禮拜的探索,終於找到了三種解決方案 方案一 利用putty xming,在windows下顯示linux gui。對硬體要求不多,而且putty 和ximg都是免費的,但要求windows和suse在同一網段。方案二 利用ubuntu的gui,在ubuntu下顯示linux gui。需要另外...
利用 Saltstack 遠端執行命令
saltstack的乙個比較突出優勢就是具備執行遠端命令的功能。操作方法與func 相似,可以幫助運維人員完成集中化的操作平台。命令格式 salt 操作目標 方法 引數 root saltstack master master salt saltstack web1group 1 cmd.run f...
利用rdiff backup實現遠端備份檔案
本文主要參考 上介紹的安裝方法。a配置 a端為centos5.5 系統,開啟ssh服務,已安裝librsync 系統預設安裝 並按照上邊鏈結的方法安裝好rdiff backup。b配置 b端為windows 7 旗艦系統。1.安裝cygwin,參考 2.利用cygwin編譯並安裝librsync,在...