前言
一开始是看到ctfio上的这篇文章,感到比较好奇,因为挺新的
https://www.ctfiot.com/96133.html
经过我一晚上的玄学探究,和调试,最终发现这东西还挺好玩的妈的,并且发现POC不是一般的多,网上传出来的只有2种,我挖出来至少十种格式xml以上,但是没有完全统计出来,搞懂原理就知道一切了
简单复现
Apache SCXML2 可以通过加载恶意xml文件实现RCE,这个XML的标签需要经过恶意的构造才行,接下来简单复现一下
1 | import org.apache.commons.scxml2.SCXMLExecutor; |
1 |
|
我们加载这个XML文件后,就可以RCE
细腻分析
断点先先给在read方法出,我们看看流程
进入read方法,又调用了另一个参数不同的read,在这里传入我们xml的path,并且初始化了一个Configuration
将XML的路径和配置类都传入readInternal方法里,跟进
然后初始化了一个URLresovler去读取XML,这边咱们的http服务就会接收到对应的请求,最后进入readDocument方法进行下一步读取
获取xml的namespace和localname,最后进入readSCXML方法中进行更深次的读取
,这里就是重点了
这里会获取几个标签,可以看到包括我们payload里的state标签,由于最外层是state,因此进入readstate方法
第二层标签是onentry,所以进入了readOnEntry方法
进入readExecutableContext方法,接下来也是重点
第三层是script,所以读取script标签
在这里设置了body体,也就是恶意的payload,最后进入addAction方法,随之就完成了这一系列的读取和添加,退回readOnEntry
最后添加进去后,进入POC中的第二个方法,setStateMachine
省去一些跟进,直接到getGlobalContext(),在这里获取一下globalcontext
随之退回setStateMaching,给evaluator属性赋值为刚刚上述流程得到的evaluator
随之进入最后一个步骤,go方法
进入firststep方法,这里的exctx储存着上述得到的所有东西
进入fiststep方法先初始化,然后通过executeGloablScript方法执行globalscript,由于我们这次payload最外层是state不是script,所以没用
先进入getStateMachine方法
这里面放着我们的payload,然后退出去,进入getInitialTransition
方法
这里面也放着payload,退出去,然后add进了一个hashmap,随后进入microStep
最后进入里面的executeTransitionContent(exctx, step)
执行命令
通过不断的迭代取出step里面的值,但是由于这次咱们的标签里没有Transition
所以取不出什么东西,不会执行命令
进入enterStates方法
获取第二层标签onentry后又进入executecontent方法
首先获取一个迭代器,里面再往深一层就是script标签
进入getActionExecutionContext()
方法,获取可执行的content,终于到最后一步了,随后进入excute方法最终执行命令
在这里获取了script标签,调用evalScript执行命令
思考其他payload
在这上述过程中,最后一步咱们调用的是不是evalScript,方法,我们看看还有啥其他类似的?
那也就是说明Cond、Location、Assign、Script
起码都是可以的,其实Location、Assign最终实际调用的是eval,都是获取expr属性
会获取expr属性,然后eval就是执行expr属性的
然后这些payload的根源都是从哪儿起来的呢?答案是read方法,记得read方法里的这一步吗?
会获取以下5个最外层标签,那我们就分析一下,这五个标签有啥可能性,就不调试了直接说简单说分析
最终可用来执行命令的属性或者是标签为
- script标签
- expr属性
- cond属性
- assign标签的expr属性(归根还是expr属性)
这里就直接放一些其他payload了
1 | <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"> |
1 | <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"> |
1 | <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"> |
1 |
|
1 |
|
其他还有很多payload,不想一个个测,直接说一下原理,去寻找哪里调用了setExpr或者setCond即可
onEntry的替代品可以是onexit,然后最后可以附带expr属性的标签可以是location、assign,还有一些带cond的也是,就在上面的SCXMLReader方法里面一个个找,就五个最外层的大标签
About this Post
This post is written by Boogipop, licensed under CC BY-NC 4.0.