首先给出payload地址:https://www.cnblogs.com/potatsoSec/p/13307315.html
分析
根据payload给出的内容可以看出主要触发点在com.tangosol.util.extractor.UniversalExtractor类中
可以看出该类与我之前分析的CVE-2020-2555反序列化的原理相似,都是在extract。进行invoke调用。这里可以看到虽然在if中包含了getMethod().invoke(oTarget, this.m_aoParam)这样的反射关键字,但是targetPrev参数是用transient修饰过的也就是说这个参数无法进行反序列化,并不能利用。这里需要跟入else的extractComplex方法继续查看。
可以看到这里有个findMethod的方法,在函数的结束返回了一个method.invoke(oTarget, aoParam)而这里的oTarget和this.m_aoParam是可控的,一个在调用时传参数,一个在实力化时被赋值。
查看findMethod可以发现在这里进行了clz.getMethod(sName, aclzParam),方法通过类、方法名以及方法的参数类型数组来反射返回该类中的特定方法。配合在return处的invoke整个反射链就形成了。接下来需要了解如何触发。
第一反应是我们需要在extractComplex方法中进入else判断。这里需要this.isPropertyExtractor()返回值为false,也就是需要this.m_fMethod的值为true.但这里的m_fMethod也被transient修饰了,我们无法利用。所以只能查看if中的findMethod方法是否可以利用。
1 | public boolean isPropertyExtractor() { |
可以看到这里使用了sCName参数,该参数在UniversalExtractor类实力化的时候被赋值。
跟入init()的getCanonicalName方法可以看到,因为这里的参数是this也就是本身,所以这里sName会为空然后进入if判断中
1 | public static <T extends Remotable> String getValueExtractorCanonicalName(Object oLambda) { |
接下来进入computeValueExtractorCanonicalName看sName是如何赋值的。
如果aoParam不为空,或者结尾不是()字符则会便利VALUE_EXTRACTOR_BEAN_ACCESSOR_PREFIXES查看开头是否符合这个名单。而这个名单中只有两个内容get和is
在之前的extractComplex方法中我们看到了判断,也是类似的情况,也就是说。我们传入的方法需要以get和is开头,另外aoParam这个的值需要为null也就是说传入的方法不能带有参数。这里payload给出的方法是使用com.sun.rowset.JdbcRowSetImpl这个类,这个类大家应该都不陌生,fastjson最开始的利用链就是这个,在使用该类进行jdni连接时候会调用this.getDataSourceName()刚好满足get开头切无参数传递的方法。
至此到extractor这里整个流程就结束了,接下来是如何利用extractor触发反序列化呢?根据payload利用的是PriorityQueue不难想到是compare方法触发。
可以看到在com.tangosol.util.comparator.ExtractorComparator类中ExtractorComparator方法对this.m_extractor进行了赋值,compare方法中使用了extract(this.m_extractor),也就是说我们将m_extractor赋值成我们需要的方法。然后利用PriorityQueue触发compare进行extract完成整个利用链。
利用
1 | UniversalExtractor extractor = new UniversalExtractor("getDatabaseMetaData()", null, 1); |
总结
整个过程是根据现有的exp流程分析,如果有其他的思路希望师傅们指点。