Struts2 REST插件在使用xstreamhandler处理反序列化XML时没有进行任何过滤,从而导致远程执行代码,攻击者可以利用该漏洞构造恶意的XML内容获取服务器权限。
漏洞分析
首先看一下struts-plugin.xml配置文件,当Content-Type为xml时会调用XStreamHandler类进行处理
在struts-plugin.xml配置文件中可见,当Content-Type为xml时会调用XStreamHandler类进行处理
此外,从上图还可以看出xml是struts2请求中后缀的默认支持格式
当请求报文中Content-Type为”application/xml”时,程序会调用XStreamHandler.toObject
toObject方法中将会调用XStream.fromXML对传入的xml的内容进行反序列化。在这个过程中,XStream没有对Reader做任何过滤处理
我们通过调试代码来跟踪一下实际的流程
首先我们构造如下数据包以触发漏洞
构造如上图请求数据,将请求中的Content-Type设置为application/xml
当请求进入struts2的Content-Type拦截器即ContentTypeInterceptor时,程序会根据请求中Content-Type类型寻找对应的handler,并调用handler进行反序列化操作,如下图
ContentTypeInterceptor具体的执行流程如下:
1、程序通过getHandlerForRequest方法会判断提交的请求类型并使用对应的handler
由上图可见,此时Content-Type为application/xml形式的请求对应的handler为XStreamHandler
2、通过getContentLength方法获取提交的数据包长度,如果长度大于0则就获取其输入流并将其生成一个InputStreamReader对象赋值给reader,操作见下图红框
3、调用对应handler的toObject方法将reader数据流进行xml反序列化
通过上图可见,在这里对应的handler为XStreamHandler
跟进XStreamHandler类的toObject方法
XStreamHandler类中toObject方法调用 XStream.fromXML对xml的内容进行反序列化
fromXML方法见下图
XStreamHandler并未对传入的Reader做过滤处理,因此导致反序列化漏洞的产生
针对官方缓解措施的分析
官方给出的缓解措施是修改struts-plugin.xml 中”struts.action.extension”属性,将xml字段从其中删除
struts.action.extension指定需要Struts2处理的请求后缀,该属性的默认值是action,即 所有匹配*.action的请求都由Struts2处理。如 果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开
原始的struts-plugin.xml 配置如下
通过上图可知:struts-plugin.xml 中的配置表明,后缀为*.xhtml,*.xml,*.json后缀的请求都有Struts2处理
官方给出的缓解措施
<constant name=”struts.action.extension” value=”xhtml,,,json” />
仅仅将配置中的xml去掉。也就是说,当出现*.xml后缀的请求,Struts2不再处理
但是反观我们的poc
并没有使用xml作为后缀
程序是否使用XStreamHandler进行反序列化操作,仅仅是通过content-Type类型是否为application/xml来判断,因此缓解措施无效