PHP文件包含漏洞(利用phpinfo)
Path php/inclusion
PHP文件包含漏洞中,如果找不到可以包含的文件,我們可以通過包含臨時文件的方法來getshell。因為臨時文件名是隨機的,如果目標網站上存在phpinfo,則可以通過phpinfo來獲取臨時文件名,進而進行包含。
參考鏈接:
漏洞環境
執行如下命令啟動環境:
docker-compose up -d
目標環境是官方最新版PHP7.2,說明該漏洞與PHP版本無關。
環境啟動后,訪問http://your-ip:8080/phpinfo.php即可看到一個PHPINFO頁面,訪問http://your-ip:8080/lfi.php?file=/etc/passwd,可見的確存在文件包含漏洞。
利用方法簡述
在給PHP發送POST數據包時,如果數據包里包含文件區塊,無論你訪問的代碼中有沒有處理文件上傳的邏輯,PHP都會將這個文件保存成一個臨時文件(通常是/tmp/php[6個隨機字符]),文件名可以在$_FILES變量中找到。這個臨時文件,在請求結束后就會被刪除。
同時,因為phpinfo頁面會將當前請求上下文中所有變量都打印出來,所以我們如果向phpinfo頁面發送包含文件區塊的數據包,則即可在返回包里找到$_FILES變量的內容,自然也包含臨時文件名。
在文件包含漏洞找不到可利用的文件時,即可利用這個方法,找到臨時文件名,然后包含之。
但文件包含漏洞和phpinfo頁面通常是兩個頁面,理論上我們需要先發送數據包給phpinfo頁面,然后從返回頁面中匹配出臨時文件名,再將這個文件名發送給文件包含漏洞頁面,進行getshell。在第一個請求結束時,臨時文件就被刪除了,第二個請求自然也就無法進行包含。
這個時候就需要用到條件競爭,具體流程如下:
- 發送包含了webshell的上傳數據包給phpinfo頁面,這個數據包的header、get等位置需要塞滿垃圾數據
- 因為phpinfo頁面會將所有數據都打印出來,1中的垃圾數據會將整個phpinfo頁面撐得非常大
- php默認的輸出緩沖區大小為4096,可以理解為php每次返回4096個字節給socket連接
- 所以,我們直接操作原生socket,每次讀取4096個字節。只要讀取到的字符里包含臨時文件名,就立即發送第二個數據包
- 此時,第一個數據包的socket連接實際上還沒結束,因為php還在繼續每次輸出4096個字節,所以臨時文件此時還沒有刪除
- 利用這個時間差,第二個數據包,也就是文件包含漏洞的利用,即可成功包含臨時文件,最終getshell
漏洞復現
利用腳本exp.py實現了上述過程,成功包含臨時文件后,會執行<?php file_put_contents('/tmp/g', '<?=eval($_REQUEST[1])?>')?>,寫入一個新的文件/tmp/g,這個文件就會永久留在目標機器上。
用python2執行:python exp.py your-ip 8080 100:

可見,執行到第289個數據包的時候就寫入成功。然后,利用lfi.php,即可執行任意命令:

Vulhub 文檔
推薦文章: