更多全球網絡安全資訊盡在邑安全
簡介
在本文中,我們將為讀者詳細介紹Claroty Research團隊的Amir Preminger和Sharon Brizinov是如何組合利用兩個漏洞,來觸發施耐德工控軟件EcoStruxure Operator Terminal Expert的代碼執行漏洞,從而在首屆舉辦的Pwn2Own邁阿密大賽上贏得了2.5萬美元獎金。這里所述的漏洞存在于施耐德電氣公司的EcoStruxure Operator Terminal Expert軟件的V3.1.100.267(SP 1)和之前版本(以前稱為Vijeo XD)中。
實際上,攻擊者只要引誘受害者打開(雙擊)EcoStruxure Operator Terminal Expert軟件的項目文件,就能夠利用默認配置發動相應的漏洞。這時,將觸發應用程序上下文中的代碼執行漏洞。總的來說,要想成功利用這個代碼執行漏洞,需要組合利用下文描述的兩個已知的漏洞。在本文中,我們先按照漏洞被發現的順序來描述其詳細信息,然后,給出組合運用這些漏洞并實現命令執行攻擊所需的具體步驟。下面,我們先給出相應的演示視頻的地址:https://youtu.be/SAmhljE9ZlE。
漏洞詳情
EcoStruxure Control Terminal Expert是一個軟件環境,用于設計人機界面(HMI)設備的圖形用戶界面。這些用戶界面用于控制工業部署中可編程邏輯控制器 (PLC) 的操作。
圖1 使用EcoStruxure Control Terminal Expert設計水流控制
在這里,所有的項目信息,包括各種設置和圖形組件的信息,都會被保存到一個后綴為.VXDZ的EcoStruxure Control Terminal Expert項目文件中。實際上,.VXDZ項目文件就是一個存放各種文件的壓縮目錄,這些文件包含了程序還原項目所需的全部信息,以便工程師在以后可以繼續工作。項目文件主要包括以下幾種文件類型:
.db:SQLite3數據庫文件,包括各種項目配置和設置。
.inf/.dat:JSON文件,用于存儲數據和設置。例如,每個屏幕及其圖形組件都是用JSON表示的。
圖2 項目目錄
當工程師打開項目文件時,壓縮后的目錄會被解壓到一個臨時目錄下,路徑如下所示:
C:\users\USER\AppData\Local\EcoStruxure\Temp\Schneider\CURRENT_VERSION_FULL\GUID\ProjectFiles
為了便于后面進行參考,我們將路徑中與環境有關的組件用紅色進行了相應的標記。另外,橙色顯示的是GUID,它是在每次打開一個項目時隨機生成的,即使這個項目之前已經打開過,亦是如此。這意味著這個路徑無法提前預測,因為它取決于當前登錄的用戶、當前具體的版本名以及一次性隨機生成的GUID。例如,下面就是我們打開一個項目文件時生成的一個有效的路徑:
C:\Users\Administrator\AppData\Local\EcoStruxure\Temp \Schneider\Imagine3.1ServicePack\A1A98F0B-9487-41B3-84A2-2195ECAA11F5\ProjectFiles
此外,由于所使用的.NET zip庫能夠防止路徑遍歷企圖,因此,只能提取隨機生成的目錄。
高級功能
與任何安全研究一樣,我們需要盡量熟悉目標產品,并尋找那些可能沒有被廠商深入檢查過的復雜/先進功能。在把玩一陣EcoStruxure Control Terminal Expert后,我們發現了一個名為“Drivers”的功能。由于HMI是智能屏幕,呈現的數據是從工廠內的現場控制器收集的,所以必須具備查詢功能,才能從PLC中獲取數據。為了達到這個目的,施耐德提供了這樣一種機制,即在項目中添加一個特定廠商的驅動程序,該驅動程序能夠查詢PLC以獲取所需數據。我們知道,PLC有許多不同的型號,并且每個PLC都是通過自己的協議進行通信的。正因為如此,施耐德提供了許多的驅動程序,工程師可以根據他們需要集成的PLC自行選用。
圖3 驅動程序是幫助HMI與所需控制設備(PLC)進行通信的組件。每個供應商及其特定設備(生態系統、協議棧等)都會提供許多不同的驅動程序。
有關特定項目文件使用的驅動程序的所有信息都位于一個名為DriverConfig.db的SQLite3數據庫文件中,我們可以在項目目錄中找到這個文件。我們在項目中添加了一個新的驅動程序,并檢查了DriverConfig.db文件,發現其中有三個數據表:
Driver_X:空表。
Driver_X_Configuration_X:關于驅動程序的詳細信息,如設置和元數據。這其中包括將要加載的驅動程序/模塊名稱。
圖4 DriverConfig.db的內容
Driver_X_Equipment_X:關于HMI將與之通信的PLC的詳細信息。其中,會包括與PLC相關的信息,如IP地址、型號、協議等。
其中,X代表驅動索引,由于我們只添加了一個驅動,所以在我們的例子中X為0。
通過.NET反射器,我們研究了相關的中間語言(IL)代碼。我們發現,ModuleName字段實際上就是驅動程序DLL,它將從預定義的目錄中進行加載,并處理HMI和PLC之間的通信。例如,如果我們有一個Rockwell Automation公司的PLC,我們就需要加載Rockwell公司相應的驅動程序——它通過EtherNet/IP+CIP協議與PLC進行通信。具體這里來說,需要加載驅動程序RockwellEIP.dll。為此,我們可以在該項目中的SQLite3數據庫文件DriverConfig.db中的Driver_0_Configuation_0表的ModuleName列(字段)中加以指定。
圖5 打開DriverConfig.db數據庫的SQLite3查看器。ModuleName字段是驅動DLL的名稱,它將被加載并處理HMI和PLC之間的通信。
Bug No. 1:通過路徑遍歷以獲取DLL加載原語
為了更好地理解如何從DriverConfig.db數據庫中提取信息,我們鉆進了一個“兔子洞”:DriverConfig.db的連接。我們可以看到,這里的代碼會查詢并提取Driver_x_configuration_0表中的所有屬性。然后,它將一個新的Driver對象實例化,并根據表中找到的相應值設置ModuleName字段。最后,它使用 ModuleName字段指定的路徑加載相應的驅動程序DLL文件。
由于數據庫(包括ModuleName字段)在我們的掌控之下,我們可以提供一個帶有一些 ../../../字符的自定義ModuleName,以便從包含合法驅動程序的應用程序定義目錄中導航出來。換句話說,我們能夠從系統中加載任意DLL。
圖6 我們將ModuleName字段改為../../../../claroty.dll,并使用procmon來監控系統。
然而,我們的攻擊要想成功,必須滿足下面兩個條件:
如果一個名為driver.xml的文件沒有出現在將要加載的DLL旁邊,那么該DLL將不會被加載。
加載的DLL必須位于同名的目錄中。
例如,如果我們將ModuleName改為Claroty,軟件將進入預定義的驅動程序目錄C:\Program Files\Schneider Electric\EcoStruxure Operator Terminal Expert 3.1 Service Pack\Drivers\Drivers,并尋找名為Claroty的目錄,然后在該目錄中搜索Claroty.dll和Driver.xml。如果這兩個文件都找到了,就會加載里面的DLL,在本例中就是C:\Program Files\Schneider Electric\EcoStruxure Operator Terminal Expert 3.1 Service Pack\Drivers\Drivers\Claroty\Claroty.dll。
我們通過目錄遍歷實現了加載任意DLL的原語,這真是太棒了。但是,現在面臨的問題是,我們如何才能提供自己的DLL,并使其運行呢?
好吧,在一定程度上說,我們還需要一個具有“任意文件寫入”功能的原語。回想一下,我們的項目文件實際上就是一個包含文件和目錄的壓縮容器。也就是說,我們可以添加我們的文件和目錄,然后再重新打包項目文件。當軟件打開項目文件并提取所有文件時,我們添加的文件也會和其他文件一起被提取出來(并保存到臨時目錄中)。現在唯一的問題是:我們如何才能提前知道我們的文件會被解壓到哪里,這樣我們就可以在DriverConfig.db數據庫下的ModuleName屬性中設置相應的路徑了。
下面,我們來總結一下:我們可以利用目錄遍歷漏洞來跳出正常的驅動程序的目錄,同時,我們也可以在我們的項目文件被提取的時候,把一些文件和目錄保存到硬盤上。但是,這些文件會被提取到一個隨機的臨時目錄,我們無法提前預知,因為GUID每次都是隨機生成的。
Bug No. 2:未進行嚴格安全過濾導致敏感數據信息泄露
我們對這些問題思考了很久,后來終于想到了一個解決方案。這個解決方案來自于一個意想不到的領域:SQLite的魔術!我們使用SQL pragma和SQL views數據庫功能實時生成提取目錄的完整路徑。因此,我們可以讓Terminal Expert軟件直接找到我們的惡意DLL。我們之所以能夠做到這一點,是因為Terminal Expert軟件加載了我們所控制的項目文件中提供的數據庫,并在沒有對數據進行適當安全過濾的情況下查詢表格。
什么是PRAGMA?
PRAGMA語句是一個依賴于具體實現的SQL擴展。它可以用來修改SQLite庫的操作,或者查詢SQLite庫的內部(非表)數據。例如,pragma database_list命令將返回當前連接數據庫的列表。
而SELECT file FROM pragma_database_list命令則會產生當前加載數據庫的完整路徑。
圖7 顯示當前加載的數據庫的完整路徑
這意味著我們可以在實時加載數據庫之后生成數據庫的完整路徑。同樣,這也是在將數據庫保存到新建的、具有隨機路徑的臨時目錄之后完成的。現在,我們只需要一種方法來獲取該查詢的結果,并將其插入到軟件即將查詢的ModuleName屬性中即可。
什么是視圖?
為了達到上述目的,我們使用了數據庫的一個不太常用的功能:視圖。在數據庫中,視圖是一個存儲查詢的結果集。換句話說,視圖就像一個動態創建的表,它是在客戶端查詢時實時生成的。當客戶端查詢視圖時,數據庫會查詢為視圖定義的實際表,并根據視圖的設置對生成的數據進行重組,最后將完整的結果反饋給客戶端——整個過程對客戶端而言是透明的。從客戶端的角度來看,似乎正在查詢數據庫中找到的常規表。
圖8 數據庫視圖和我們實時影響查詢的抽象方案
在我們的案例中,客戶端是EcoStruxure Operator Terminal Expert軟件,它查詢驅動程序數據庫以獲取ModuleName屬性,從而可以加載驅動程序DLL。我們的計劃是在數據庫被提取到臨時位置后,實時修改ModuleName屬性,最終讓ModuleName保存我們數據庫的實際路徑。
1+2=RCE:組合兩個漏洞,實現代碼執行攻擊
在項目文件中,我們需要準備一個名為ClarotyModule的目錄,其中含有如下所示的兩個文件:
Driver.xml
ClarotyModule.dll
我們將按照以下步驟準備DriverConfig.db:
我們將原來的Driver_0_Configuration_0表重命名為Driver_0_Configuration_0_ORIG。
我們將創建一個名為Driver_0_Configuration_0的VIEW表。
當客戶端查詢“原來的”表Driver_0_Configuration_0時,實際上會查詢我們新建的VIEW表。在查詢到ModuleName字段后,我們將VIEW表的內部處理設置為返回SELECT file FROM pragma_database_list的結果,并對其進行必要的修改,以構成正確的目錄遍歷語法。通過這種方式,我們可以在文件夾結構中向上、向下導航,直到抵達當前的臨時目錄中,也就是我們的payload DLL所在的位置。
圖9 精心構造一個驅動數據庫,使其實時包含我們DLL的路徑。
最后,我們把所有的部分重新打包成一個VXDZ項目文件。當受害者雙擊該文件時,我們的DLL將被加載,之后,我們的代碼也將被執行。
圖10 POC運行時,會打開項目文件,并執行相應的代碼
小結
在本文中,我們為讀者詳細介紹了如何利用EcoStruxure Operator Terminal Expert讀取給定項目文件的方式,通過執行一些SQL backflips操作,誘導軟件加載我們提供的DLL,從而在打開項目文件時發動任意代碼執行攻擊。施耐德電氣公司已經修復了這些漏洞,并將其分配了相應的編號:CVE-2020-7494與CVE-2020-7496。
轉自先知社區
歡迎收藏并分享朋友圈,讓五邑人網絡更安全推薦文章
1
新永恒之藍?微軟SMBv3高危漏洞(CVE-2020-0796)分析復現
2
重大漏洞預警:ubuntu最新版本存在本地提權漏洞(已有EXP)