前言 在本篇文章中我将分享如何在
PostgreSQL
堆疊注入場景中通過
CREATE FUNCTION
關鍵字來實作指令執行的思路。 簡要資訊如下:
- CVE:N/A
- CVSS:4.1 (AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:L)
- 适用環境:Windows、Linux、Unix
在新版的
PostgreSQL
中:
- 12.3
- 11.8
- 10.13
- 9.6.18
- 9.5.22
其資料庫超管使用者被限制隻允許從預設目錄讀取字尾為
.dll
或
.so
動态庫檔案,舉例如下:
- Windows:C:\Program Files\PostgreSQL\11\lib
- Unix/Linux:/var/lib/postgresql/11/lib
此外,預設情況下
NETWORK_SERVICE
與
postgres
這兩個系統使用者對該目錄均無寫入權限。但是經過鑒權的資料庫超管使用者可以通過調用
lo_import
函數将檔案寫入
pg_largeobject
系統表,再更新對應的資料内容将原本的内容替換為我們的惡意代碼(通常是反彈個shell),随後通過
lo_export
函數轉儲資料至動态庫目錄,最終生成我們的惡意動态庫檔案。
CREATE FUNCTION
的另一個騷操作就是可以接收指定目錄來周遊其動态庫中的相關函數。是以隻要已鑒權使用者可以将動态庫檔案寫入對應的存儲目錄,然後通過
CREATE FUNCTION
的目錄周遊特性來加載動态庫檔案就可以實作指令執行。 利用流程
1. 通過 lo_import
獲得一個 OID
lo_import
OID
pg_largeobject
系統表儲存了那些标記為
large object(大對象)
的資料。每個
大對象
都會關聯其被建立成功時配置設定的
OID
标志。此後
大對象
都分解成足夠小的資料塊并關聯
pageno
字段來存儲
pg_largeobject
裡。每頁的資料定義為
LOBLKSIZE(目前是BLCKSZ/4或者通常是 2K 位元組)
。
該過程需使用
lo_import
函數,舉例如下:
在Windwos場景下這裡我們還可以使用
UNC路徑
,如果使用該項技術則可跳過3.3,但我希望相容Unix/Windows平台,所有沒有使用。
2. 基于 OID
來進行資料替換
OID
現在,我們基于
OID
的值來替換
pg_largeobject
表中的資料,将其對應内容替換為我們的惡意代碼。這些
惡意代碼
最終需要基于目标資料庫的完整版本來進行編譯還要比對對應的系統架構。對于超過2048位元組大小的檔案,
pg_largeobject
表需使用
pageno
字段來将檔案分割成大小為2048位元組大小的資料塊。分割示例如下:
通過使用PostgreSQL中的
object identifier types
,可以跳過第1階段(并且僅對第2階段執行單個語句執行),但是我沒有時間确認這一點。
3. 使用 lo_export
函數生成惡意動态庫
lo_export
現在我們可以通過
lo_export
來轉儲之前變相導入的資料來生惡意的動态庫檔案。不過這一步不能指定目錄,因為這樣做會觸發
PostgreSQL
内置的安全檢查,而且就算能繞過該檢查,
NETWORK_SERVICE
(Unix/Linux場景下為
postgres
)帳戶也存在路徑限制,搞不定搞不定。
4. 基于惡意動态庫檔案建立函數
我在以往的研究中提到過,可以使用絕對路徑(包括
UNC
)來加載基于
Postgresql 9.x
的擴充進而執行系統指令。
@zerosum0x0
師傅也有相關的 操作筆記 。不過那個時候對系統使用者的檔案操作權限并沒有那麼多的限制。
如今幾年過去了,PostgreSQL官方決定禁用
CREATE FUNCTION
時使用絕對路徑導緻現在這種技術已經失效了。不過現在我們可以很友善地從對應的預設動态庫目錄中周遊并加載我們轉儲的惡意動态庫檔案,舉例如下:
4. 反彈shell
成功建立
connect_back
函數後,直接通過
select
指令來調用:
問題現狀
ZDI團隊
咨詢過PostgreSQL官方對該問題的意見,但無後文,後來我得知官方并不打算修複此問題,因為官方認為該問題屬于正常系統功能而不是漏洞。 造個輪子 代碼如下,将生成poc.sql檔案,以超管使用者在資料庫上逐漸執行,或将poc.sql中的sql指令逐個通過注入點執行:
跑一下展示下效果:
譯文聲明
譯文僅供參考,具體内容表達以及含義原文為準。
戳“閱讀原文”檢視更多内容