一段時間以來,eset的研究人員一直在跟蹤winnti的活動,該組織從2012年起就開始活躍,并針對視頻游戲和軟件行業供應鏈進行攻擊。最近發現一處以前未被登記的后門,其攻擊目標為microsoft sql(mssql)系統。這個后門與portreuse后門有多處相似之處,portreuse是winnti group使用的另一個工具,于2019年10月首次記錄。
Winnti組織成員發布了一個新的后門樣本,名為Skip-2.0,今年檢測到了該樣本。這個后門程序以MSSQL服務器11和12為目標,攻擊者可以使用magic密碼連接到任何MSSQL帳戶,同時自動將這些連接隱藏在日志中。攻擊者可以利用后門進入數據庫,復制、修改或刪除其中的內容,從而操縱游戲內貨幣,以獲取經濟利益。根據了解,Skip-2.0是第一個被公開記錄的MSSQL服務器后門。
本文將重點介紹mssql服務器后門的技術細節和功能,以及skip.2-0與winnti已知武器庫(特別是portreuse后門和shadowpad)的技術相似性。
vmprotected啟動程序
我們在查找vmprotected啟動程序時找到了skip-2.0,其有效負載通常是portreuse或shadowpad。
嵌入式有效載荷
與加密的portreuse和shadowpad有效負載一樣,skip-2.0嵌入到vmprotected啟動程序中,如圖1所示:
加密
與其他使用VMProtect啟動程序的相同,有效載荷也要進行加密。該加密方式采用RC5算法,密鑰由volumeID和字符串”f@ukd!RCTO R$”組成。
持久性
與portreuse和shadowpad的一樣,啟動程序可能會通過利用dll劫持而持續存在,方法是將其安裝在c:windowssystem32tsvipsrv.dll。這會使得系統啟動時標準的Windows SessionEnv服務加載DLL。
打包器
嵌入有效負載的解密后,實際上是winnti組的自定義打包程序。這個打包器與我們在白皮書中記錄的代碼是相同的。該工具被用于打包PortReuse后門,并將負載嵌入到受損的視頻游戲中。
配置
程序打包配置中包含解密二進制文件所需的密鑰,以及原始文件的名稱、大小和執行類型(exe或dll)。有效載荷配置如表1所示。
打包器配置可以看出,有效負載稱為內部裝載器。內部加載程序是一個注入器的名稱,它是winnti集團的武庫的一部分,用于將portreuse后門注入監聽特定端口的進程。
內部加載器
這是一種內部加載程序的變體,不是像注入portreuse后門時那樣尋找監聽特定端口的進程,而是尋找名為sqlserv.exe的進程,這是mssql server的常規進程名。如果找到,則內部加載程序會將有效負載注入此進程。此有效負載與自定義打包程序一起打包,該打包程序的配置列于表2中。
此注入負載的原始文件名為skip-2.0.dll。
skip-2.0
在被內部加載程序注入并啟動之后,skip-2.0首先檢查它是否在sqlserv.exe進程中執行,如果是,則檢索sqllang.dll的句柄,該句柄由sqlserv.exe加載。然后繼續從該dll中查找并掛接多個函數。圖2描述了skip-2.0的運行過程。
Hooking sqllang.dll
skip-2.0使用的hook過程與netagent非常相似,netagent是負責安裝網絡hook的portreuse模塊。該hook庫建立在開源的distorm反匯編程序基礎上,多個開源的掛接框架也使用了該反匯編程序。需要一個反匯編庫來正確計算要hook的指令的大小。幾乎相同的hook過程被NetAgent和Skip-2.0使用,如下圖所示。
圖3Hex-Rays output comparison between the NetAgent (left) and skip-2.0 (right) hooking procedures
有一個顯著的區別就是skip-2.0中的hooking函數將要安裝的鉤子的地址作為參數,而對于netagent,要安裝的鉤子的地址是硬編碼的。這是因為skip-2.0必須hooksqllang.dll中的多個函數才能正常運行,而netagent只針對一個函數。
要定位hook的每個sqllang.dll函數,skip-2.0首先通過解析pe頭來檢索加載到內存中的dll的大小(即其虛擬大小)。接著,需初始化sqllang.dll中需要匹配的字節數組,參照圖4。一旦找到與字節數組匹配的第一個匹配項的地址,就會使用圖3所示的過程安裝鉤子。
然后,鉤子安裝成功后會在cleartext中記錄,該文件位于硬編碼路徑c: windowstemptsu 2ce1.tmp中,如圖5所示。
如果找不到目標函數,鉤子安裝程序將搜索具有不同字節模式集的回退函數。
通過匹配字節序列來定位目標函數的地址,而不是使用靜態偏移量,再加上使用字節的回退序列,skip-2.0可以更靈活地適應mssql更新,并可針對多個sqllang.dll更新。
密碼控制
skip-2.0的目標函數與身份驗證和事件日志記錄相關。目標功能包括:
CPwdPolicyManager::ValidatePwdForLogin CSECAuthenticate::AuthenticateLoginIdentity ReportLoginSuccess IssueLoginSuccessReport FExecuteLogonTriggers XeSqlPkg::sql_statement_completed::Publish XeSqlPkg::sql_batch_completed::Publish SecAuditPkg::audit_event::Publish XeSqlPkg::login::Publish XeSqlPkg::ual_instrument_called::Publish
其中最有趣的函數是第一個函數(cpwdpolicymanager::validatepwdforlogin),它負責驗證為給定用戶提供的密碼。
此函數的鉤子檢查用戶提供的密碼是否與magic密碼匹配;如果是,則不會調用原始函數,鉤子將返回0,從而允許連接。接下來,設立一個全局標識,由其他負責事件日志記錄的鉤子函數進行檢查。相應的反編譯過程如圖6所示。在設置此全局標志的情況下,hook的日志記錄函數將靜默返回,而不調用其對應的原始函數,因此不會記錄操作。
如果使用magic密碼登錄,reportloginsaccess和issueloginsuccessreport掛鉤將不會調用原始函數。feexecutelogontriggers也適用于同樣的行為。其他日志記錄功能,如xesqlpkg::sql_completed::publish或xesqlpkg::sql_batch_completed::publish,在用戶使用魔法密碼登錄的情況下也將被禁用。還禁用了多個審核事件,包括secauditpkg::audit_event::publish、xesqlpkg::login::publish和xesqlpkg::uau instrument_called::publish。
這一系列hook不僅允許攻擊者通過特殊密碼在受害者的mssql服務器中獲得持久控制,而且使用該密碼時禁用了多個日志,因此無法檢測到攻擊者。
研究人員對多個MSSQL Server版本測試了Skip-2.0,發現能夠使用MSSQL Server 11和12的密碼成功登錄。為了檢查skip-2.0是否針對特定的sqllang.dll版本,創建了一個yara規則,該規則可以在github庫中找到。
與Winnti的聯系
skip-2.0和來自winnti的其他工具有很多相似之處。vmprotected啟動程序、自定義打包程序、內部加載程序和hook框架是winnti工具集的一部分。