成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java代碼審計(jì)之SpEL表達(dá)式注入

安全 漏洞
Spring Expression Language 是一種功能強(qiáng)大的表達(dá)式語(yǔ)言、用于在運(yùn)行時(shí)查詢(xún)和操作對(duì)象圖;語(yǔ)法上類(lèi)似于 Unified EL,但提供了更多的特性,特別是方法調(diào)用和基本字符串模板函數(shù)。

一、SpEL 表達(dá)式注入

Spring Expression Language(簡(jiǎn)稱(chēng) SpEL)是一種功能強(qiáng)大的表達(dá)式語(yǔ)言、用于在運(yùn)行時(shí)查詢(xún)和操作對(duì)象圖;語(yǔ)法上類(lèi)似于 Unified EL,但提供了更多的特性,特別是方法調(diào)用和基本字符串模板函數(shù)。SpEL 的誕生是為了給 Spring 社區(qū)提供一種能夠與 Spring 生態(tài)系統(tǒng)所有產(chǎn)品無(wú)縫對(duì)接,能提供一站式支持的表達(dá)式語(yǔ)言。

二、SpEL 表達(dá)式

  • 基本表達(dá)式:字面量表達(dá)式、關(guān)系,邏輯與算數(shù)運(yùn)算表達(dá)式、字符串鏈接及截取表達(dá)式、三目運(yùn)算、正則表達(dá)式以及括號(hào)優(yōu)先級(jí)表達(dá)式;
  • 類(lèi)相關(guān)表達(dá)式:類(lèi)類(lèi)型表達(dá)式、類(lèi)實(shí)例化、instanceof 表達(dá)式、變量定義及引用、賦值表達(dá)式、自定義函數(shù)、對(duì)象屬性存取及安全導(dǎo)航表達(dá)式、對(duì)象方法調(diào)用、Bean 引用;
  • 集合相關(guān)表達(dá)式:內(nèi)聯(lián) List、內(nèi)聯(lián)數(shù)組、集合、字典訪(fǎng)問(wèn)、列表、字典;
  • 其他表達(dá)式:模版表達(dá)式

三、SpEL 基礎(chǔ)

在 pom.xml 導(dǎo)入 maven 或是把”org.springframework.expression-3.0.5.RELEASE.jar”添加到類(lèi)路徑中

  1. <properties> 
  2.     <org.springframework.version>5.0.8.RELEASE</org.springframework.version> 
  3. </properties> 
  4. <dependency> 
  5.       <groupId>org.springframework</groupId> 
  6.       <artifactId>spring-expression</artifactId> 
  7.       <version>${org.springframework.version}</version> 
  8. </dependency> 

1. SpEL 使用方式

SpEL 在求表達(dá)式值時(shí)一般分為四步,其中第三步可選:首先構(gòu)造一個(gè)解析器,其次解析器解析字符串表達(dá)式,在此構(gòu)造上下文,然后根據(jù)上下文得到表達(dá)式運(yùn)算后的值。

  1. ExpressionParser parser = new SpelExpressionParser(); 
  2. Expression expression = parser.parseExpression("('Hello' + ' freebuf').concat(#end)"); 
  3. EvaluationContext context = new StandardEvaluationContext(); 
  4. context.setVariable("end", "!"); 
  5. System.out.println(expression.getValue(context)); 
  • 創(chuàng)建解析器:SpEL 使用 ExpressionParser 接口表示解析器,提供 SpelExpressionParser 默認(rèn)實(shí)現(xiàn);
  • 解析表達(dá)式:使用 ExpressionParser 的 parseExpression 來(lái)解析相應(yīng)的表達(dá)式為 Expression 對(duì)象。
  • 構(gòu)造上下文:準(zhǔn)備比如變量定義等等表達(dá)式需要的上下文數(shù)據(jù)。
  • 求值:通過(guò) Expression 接口的 getValue 方法根據(jù)上下文獲得表達(dá)式值。

2. SpEL 主要接口

1.ExpressionParser 接口:表示解析器,默認(rèn)實(shí)現(xiàn)是 org.springframework.expression.spel.standard 包中的 SpelExpressionParser 類(lèi),使用 parseExpression 方法將字符串表達(dá)式轉(zhuǎn)換為 Expression 對(duì)象,對(duì)于 ParserContext 接口用于定義字符串表達(dá)式是不是模板,及模板開(kāi)始與結(jié)束字符;

  1. public interface ExpressionParser {   
  2.     Expression parseExpression(String expressionString);   
  3.     Expression parseExpression(String expressionString, ParserContext context);   

事例 demo:

  1. ExpressionParser parser = new SpelExpressionParser(); 
  2. ParserContext parserContext = new ParserContext() { 
  3.     @Override 
  4.     public boolean isTemplate() { 
  5.     return true; 
  6.     } 
  7.     @Override 
  8.     public String getExpressionPrefix() { 
  9.     return "#{"; 
  10.     } 
  11.     @Override 
  12.     public String getExpressionSuffix() { 
  13.     return "}"; 
  14.     } 
  15. }; 
  16. String template = "#{'hello '}#{'freebuf!'}"
  17. Expression expression = parser.parseExpression(template, parserContext); 
  18. System.out.println(expression.getValue()); 

演示的是使用 ParserContext 的情況,此處定義了 ParserContext 實(shí)現(xiàn):定義表達(dá)式是模塊,表達(dá)式前綴為「#{」,后綴為「}」;使用 parseExpression 解析時(shí)傳入的模板必須以「#{」開(kāi)頭,以「}」結(jié)尾。

默認(rèn)傳入的字符串表達(dá)式不是模板形式,如之前演示的 Hello World。

  • EvaluationContext 接口:表示上下文環(huán)境,默認(rèn)實(shí)現(xiàn)是 org.springframework.expression.spel.support 包中的 StandardEvaluationContext 類(lèi),使用 setRootObject 方法來(lái)設(shè)置根對(duì)象,使用 setVariable 方法來(lái)注冊(cè)自定義變量,使用 registerFunction 來(lái)注冊(cè)自定義函數(shù)等等。
  • Expression 接口:表示表達(dá)式對(duì)象,默認(rèn)實(shí)現(xiàn)是 org.springframework.expression.spel.standard 包中的 SpelExpression,提供 getValue 方法用于獲取表達(dá)式值,提供 setValue 方法用于設(shè)置對(duì)象值。

3. SpEL 語(yǔ)法 – 類(lèi)相關(guān)表達(dá)式

類(lèi)類(lèi)型表達(dá)式:使用”T(Type)”來(lái)表示 java.lang.Class 實(shí)例,”Type”必須是類(lèi)全限定名,”java.lang”包除外,即該包下的類(lèi)可以不指定包名;使用類(lèi)類(lèi)型表達(dá)式還可以進(jìn)行訪(fǎng)問(wèn)類(lèi)靜態(tài)方法及類(lèi)靜態(tài)字段。

具體使用方法:

  1. ExpressionParser parser = new SpelExpressionParser(); 
  2.         // java.lang 包類(lèi)訪(fǎng)問(wèn) 
  3. Class<String> result1 = parser.parseExpression("T(String)").getValue(Class.class); 
  4. System.out.println(result1); 
  5.         //其他包類(lèi)訪(fǎng)問(wèn) 
  6. String expression2 = "T(java.lang.Runtime).getRuntime().exec('open /Applications/Calculator.app')"
  7. Class<Object> result2 = parser.parseExpression(expression2).getValue(Class.class); 
  8. System.out.println(result2); 
  9.         //類(lèi)靜態(tài)字段訪(fǎng)問(wèn) 
  10. int result3 = parser.parseExpression("T(Integer).MAX_VALUE").getValue(int.class); 
  11. System.out.println(result3); 
  12.         //類(lèi)靜態(tài)方法調(diào)用 
  13. int result4 = parser.parseExpression("T(Integer).parseInt('1')").getValue(int.class); 
  14. System.out.println(result4); 
  • 類(lèi)實(shí)例化:類(lèi)實(shí)例化同樣使用 java 關(guān)鍵字「new」,類(lèi)名必須是全限定名,但 java.lang 包內(nèi)的類(lèi)型除外,如 String、Integer。
  • instanceof 表達(dá)式:SpEL 支持 instanceof 運(yùn)算符,跟 Java 內(nèi)使用同義;如”‘haha’ instanceof T(String)”將返回 true。
  • 變量定義以及引用:變量定義通過(guò) EvaluationContext 接口的 setVariable(variableName, value) 方法定義;在表達(dá)式中使用”#variableName”引用;除了引用自定義變量,SpE 還允許引用根對(duì)象及當(dāng)前上下文對(duì)象,使用”#root”引用根對(duì)象,使用”#this”引用當(dāng)前上下文對(duì)象;
  • 自定義函數(shù):目前只支持類(lèi)靜態(tài)方法注冊(cè)為自定義函數(shù);SpEL 使用 StandardEvaluationContext 的 registerFunction 方法進(jìn)行注冊(cè)自定義函數(shù),其實(shí)完全可以使用 setVariable 代替,兩者其實(shí)本質(zhì)是一樣的

四、審計(jì)過(guò)程

這里拿 Spring Message 遠(yuǎn)程命令執(zhí)行漏洞來(lái)作為例子

1. 環(huán)境搭建

  1. git clone https://github.com/spring-guides/gs-messaging-stomp-websocket 
  2. git checkout 6958af0b02bf05282673826b73cd7a85e84c12d3 

拿到項(xiàng)目代碼,全局搜索一下 org.springframework.expression.spel.standard,發(fā)現(xiàn) DefaultSubscriptionRegistry.java 文件處有導(dǎo)入。

再搜索一下 SpelExpressionParser

往下跟進(jìn)發(fā)現(xiàn)如下關(guān)鍵代碼,具體分析看代碼注釋

  1. @Override 
  2. protected void addSubscriptionInternal( 
  3. String sessionId, String subsId, String destination, Message<?> message) { 
  4. Expression expression = null
  5. MessageHeaders headers = message.getHeaders(); 
  6.         // 這里可以看出 SpEL 表達(dá)式 expression 是從 headers 中的 selector 字段中取出來(lái) 
  7. String selector = SimpMessageHeaderAccessor.getFirstNativeHeader(getSelectorHeaderName(), headers); 
  8. if (selector != null) { 
  9. try { 
  10.                 //生成 expression 對(duì)象 
  11. expression = this.expressionParser.parseExpression(selector); 
  12. this.selectorHeaderInUse = true
  13. if (logger.isTraceEnabled()) { 
  14. logger.trace("Subscription selector: [" + selector + "]"); 
  15. catch (Throwable ex) { 
  16. if (logger.isDebugEnabled()) { 
  17. logger.debug("Failed to parse selector: " + selector, ex); 
  18.         // expression 傳入 addSubscription 這個(gè)函數(shù)里面,即存放在 this.subscriptionRegistry 
  19. this.subscriptionRegistry.addSubscription(sessionId, subsId, destination, expression); 
  20. this.destinationCache.updateAfterNewSubscription(destination, sessionId, subsId); 

再搜索一下 this.subscriptionRegistry,看看有沒(méi)有調(diào)用傳進(jìn)去的 expression。

然后發(fā)現(xiàn)了!

在這里調(diào)用了 this.subscriptionRegistry.getSubscriptions(sessionId) 并從中取出 info->sub-> expression。

最關(guān)鍵的是,這里直接調(diào)用了 expression.getValue()!這說(shuō)明如果能控制 SpEL 的表達(dá)式,就能直接命令執(zhí)行!

再來(lái)看看這個(gè) filterSubscriptions 函數(shù)在哪里調(diào)用。從函數(shù)的調(diào)用回溯追蹤調(diào)用鏈如下:

  1. filterSubscriptions -> findSubscriptionsInternal -> findSubscriptions -> sendMessageToSubscribers 

2. sendMessageToSubscribers 即發(fā)送消息的功能

回顧一下整個(gè)流程,SpEL 表達(dá)式從 headers 中 selector 獲取,即發(fā)送請(qǐng)求時(shí)添加 selector 到請(qǐng)求的 header 即可傳入,然后生成 expression 對(duì)象傳入 this.subscriptionRegistry,然后當(dāng)發(fā)送消息的時(shí)候,最終會(huì)直接從 this.subscriptionRegistry 取出并調(diào)用 expression.getValue() 執(zhí)行我們傳入的 SpEL 表達(dá)式。

驗(yàn)證過(guò)程,在 expression.getValue() 這里打個(gè)斷點(diǎn),看看發(fā)送消息是否會(huì)攔截并查看調(diào)用鏈?zhǔn)欠袢缟鲜龇治鲆粯印?/p>

Bingo!

簡(jiǎn)單總結(jié)一下 SpEL 表達(dá)式注入的分析思路,可以先全局搜索 org.springframework.expression.spel.standard, 或是 expression.getValue()、expression.setValue(),定位到具體漏洞代碼,再分析傳入的參數(shù)能不能利用,然后再追蹤參數(shù)來(lái)源,看看是否可控。Spring Data Commons Remote Code Execution 的 SpEL 注入導(dǎo)致的代碼執(zhí)行同樣可以用類(lèi)似的思路分析。

五、漏洞修復(fù)

SimpleEvaluationContext、StandardEvaluationContext 是 SpEL 提供的兩個(gè) EvaluationContext:

  • SimpleEvaluationContext - 針對(duì)不需要 SpEL 語(yǔ)言語(yǔ)法的全部范圍并且應(yīng)該受到有意限制的表達(dá)式類(lèi)別,公開(kāi) Spal 語(yǔ)言特性和配置選項(xiàng)的子集。
  • StandardEvaluationContext - 公開(kāi)全套 SpEL 語(yǔ)言功能和配置選項(xiàng)。您可以使用它來(lái)指定默認(rèn)的根對(duì)象并配置每個(gè)可用的評(píng)估相關(guān)策略。

SimpleEvaluationContext 旨在僅支持 SpEL 語(yǔ)言語(yǔ)法的一個(gè)子集。它不包括 Java 類(lèi)型引用,構(gòu)造函數(shù)和 bean 引用;所以最直接的修復(fù)方式是使用 SimpleEvaluationContext 替換 StandardEvaluationContext。

這是我個(gè)人學(xué)習(xí)代碼審計(jì)過(guò)程中的小總結(jié),可能邏輯性相對(duì)來(lái)說(shuō)沒(méi)那么嚴(yán)謹(jǐn),但是個(gè)人覺(jué)得這是一個(gè)比較通俗易懂的分析方法,不喜勿噴。

 

 

責(zé)任編輯:趙寧寧 來(lái)源: Freebuf
相關(guān)推薦

2023-10-10 08:16:07

Spring依賴(lài)注入SpEL表達(dá)式

2009-06-08 16:49:05

Java正則表達(dá)式group

2009-07-06 15:20:30

JSP表達(dá)式

2021-09-13 18:39:50

ServeltELJSP

2017-05-12 10:47:45

Linux正則表達(dá)式程序基礎(chǔ)

2014-01-05 17:41:09

PostgreSQL表達(dá)式

2014-07-04 09:28:25

2023-11-02 18:45:00

Rust編程表達(dá)式

2016-11-10 16:21:22

Java 正則表達(dá)式

2012-04-28 15:22:46

PHP

2024-06-27 00:36:06

2012-06-26 10:03:58

JavaJava 8lambda

2009-02-18 09:48:20

正則表達(dá)式Java教程

2023-11-27 08:28:37

SpEL表達(dá)式

2015-04-16 11:16:05

PHPPOSIX正則表達(dá)式

2024-01-05 17:41:36

Rust編程循環(huán)

2019-07-25 17:00:44

Python正則表達(dá)式字符串

2023-10-07 08:25:09

Java處理工具正則表達(dá)式

2013-04-07 15:44:26

Java8Lambda

2019-12-13 10:24:05

PythonSQL注入ORM注入
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 韩日在线观看视频 | 999久久久 | 亚洲国产精品久久 | 美女一级毛片 | 91综合在线观看 | 91人人澡人人爽 | 国产一区二区精华 | 一区二区三区不卡视频 | 国产成人精品午夜视频免费 | 91精品久久久久久久 | 中文字幕专区 | 蜜桃av一区二区三区 | 在线观看日韩av | 精品综合久久久 | 国产99久久精品 | 日本 欧美 国产 | 一区二区视频 | 欧美日韩国产一区二区三区 | 在线一级片 | 久久一区二区视频 | 亚洲国产一区在线 | 欧美人妇做爰xxxⅹ性高电影 | 欧美黄色片在线观看 | 国产精品久久久久久久久久久久久 | 九色在线观看 | 精品国产视频 | 特黄特黄a级毛片免费专区 av网站免费在线观看 | 成人日批视频 | 亚州精品天堂中文字幕 | 免费精品视频在线观看 | 亚洲一区二区av在线 | 国产精品亚洲综合 | 男女羞羞视频在线 | 亚卅毛片 | 日本不卡一区二区三区在线观看 | 欧美视频二区 | 国产亚洲精品美女久久久久久久久久 | 国产欧美视频一区二区 | 亚洲精品888| 天天看天天爽 | 国产伦一区二区三区四区 |