Docker搭建復現環境
地址:https://github.com/vulhub/vulhub/tree/master/php/inclusion
ps. github單獨下載一個文件夾的方法:
安裝:SVN 命令:sudo apt-get install subversion 如果想下載的文件夾鏈接是:https://github.com/vulhub/vulhub/tree/master/php/inclusion 那么改為:https://github.com/vulhub/vulhub/trunk/php/inclusion 命令行下載:svn checkout https://github.com/vulhub/vulhub/trunk/php/inclusion
下好了以后直接
docker-compose up -d
如果出現 AttributeError: 'module' object has no attribute 'SSL_ST_INIT' 問題:
rm -rf /usr/lib/python2.7/dist-packages/OpenSSL rm -rf /usr/lib/python2.7/dist-packages/pyOpenSSL-0.15.1.egg-info sudo pip install pyopenssl
復現
docker 執行完命令之后,直接訪問網站 8080 端口會出現 phpinfo 界面
lfi.php?file=/etc/passwd 發現存在文件包含的
使用腳本進行 get shell:
python2 運行:python2 exp.py 192.168.149.133 8080 10(IP 端口 線程)
腳本報的結果:Got it! Sehll created in /tmp/g
所以使用:lfi.php?file=/tmp/g&1=system('ls'); 可以執行命令了!
漏洞原理
完全來自:https://github.com/vulhub/vulhub/tree/master/php/inclusion
大佬們寫的太詳細了,一看就懂,我就不胡說八道了
在給 php 發送 post 數據包的時候,如果數據包里面包含文件區塊,無論訪問的代碼中有沒有處理文件上傳的邏輯,php 都會將這個文件保存成臨時文件(通常是 /tmp/php[6個隨機字符]),文件名可以通過在 $_FILES 這個變量中找到,這個臨時文件,在請求結束后就會被刪除
同時,因為 phpinfo 頁面會將當前請求上下文所有變量都打印出來,所以我們如果向 phpinfo 頁面發送包含文件區塊的數據包,則可以在返回包里找到 $_FILES 變量的內容,自然也包含臨時文件名
在文件包含找不到可利用的文件時,即可用這種方法(為什么我覺得這樣一把梭更舒服?),找到臨時文件名,然后包含
但是文件包含漏洞和 phpinfo 頁面通常是兩個頁面,理論上我們需要先發數據包給 phpinfo 頁面,然后從返回頁面中匹配出臨時文件名,再將這個文件名發送給文件包含漏洞頁面,進行 getshell。在第一個請求結束時,臨時文件就被刪除了,第二個請求自然也無法包含
這時候需要用到條件競爭,具體流程如下:
1、發送包含 webshell 的上傳數據給 phpinfo 頁面,這個頁面數據包的 header、get 等位置需要塞滿垃圾數據
2、因為 phpinfo 頁面會將所有數據都打印出來,第一步中的垃圾數據會使得 phpinfo 頁面變得非常大
3、php 默認的輸出緩沖區大小為 4096,可以理解為 php 每次返回 4096 個字節給 socket 連接
4、我們直接操作原生 socket,每次讀取 4096 個字節,只要讀取到的字符里面包含臨時文件名,就立即發送第二個數據包
5、此時,第一個數據包的 socket 連接實際上還沒有結束,因為 php 還在繼續每次輸出 4096 個字節,所以臨時文件此時還沒有刪除
6、利用這個時間差,第二個數據包,也就是文件包含漏洞的利用,即可成功包含臨時文件,最終 getshell
參考
https://github.com/vulhub/vulhub/tree/master/php/inclusion