ysoserial--JBoss篇

前言

ysoserial是一款在Github开源的知名java 反序列化利用工具,里面集合了各种java反序列化payload。该工具涉及大量的序列化与反序列化、反射等安全研究人员所必备的JAVA代码技能,通过对该框架的分析,我们可以个更好的学习该工具,巩固JAVA代码审计的技能树。同时在二次开发和使用该工具时得心应手。

ysoserial目录结构

+— appveyor.yml
+— assembly.xml
+— DISCLAIMER.txt
+— Dockerfile
+— LICENSE.txt
+— pom.xml
+— README.md
+— src
| +— main
| | +— java
| | | +— ysoserial
| | | | +— Deserializer.java
| | | | +— exploit
| | | | | +— JBoss.java
| | | | | +— JenkinsCLI.java
| | | | | +— JenkinsListener.java
| | | | | +— JenkinsReverse.java
| | | | | +— JMXInvokeMBean.java
| | | | | +— JRMPClassLoadingListener.java
| | | | | +— JRMPClient.java
| | | | | +— JRMPListener.java
| | | | | +— JSF.java
| | | | | +— RMIRegistryExploit.java
| | | | +— GeneratePayload.java
| | | | +— payloads
| | | | | +— annotation
| | | | | | +— Authors.java
| | | | | | +— Dependencies.java
| | | | | | +— PayloadTest.java
| | | | | +— BeanShell1.java
| | | | | +— C3P0.java
| | | | | +— Clojure.java
| | | | | +— CommonsBeanutils1.java
| | | | | +— CommonsCollections1.java
| | | | | +— CommonsCollections2.java
| | | | | +— CommonsCollections3.java
| | | | | +— CommonsCollections4.java
| | | | | +— CommonsCollections5.java
| | | | | +— CommonsCollections6.java
| | | | | +— CommonsCollections7.java
| | | | | +— DynamicDependencies.java
| | | | | +— FileUpload1.java
| | | | | +— Groovy1.java
| | | | | +— Hibernate1.java
| | | | | +— Hibernate2.java
| | | | | +— JavassistWeld1.java
| | | | | +— JBossInterceptors1.java
| | | | | +— Jdk7u21.java
| | | | | +— JRMPClient.java
| | | | | +— JRMPListener.java
| | | | | +— JSON1.java
| | | | | +— Jython1.java
| | | | | +— MozillaRhino1.java
| | | | | +— MozillaRhino2.java
| | | | | +— Myfaces1.java
| | | | | +— Myfaces2.java
| | | | | +— ObjectPayload.java
| | | | | +— ReleaseableObjectPayload.java
| | | | | +— ROME.java
| | | | | +— Spring1.java
| | | | | +— Spring2.java
| | | | | +— URLDNS.java
| | | | | +— util
| | | | | | +— ClassFiles.java
| | | | | | +— Gadgets.java
| | | | | | +— JavaVersion.java
| | | | | | +— PayloadRunner.java
| | | | | | +— Reflections.java
| | | | | +— Vaadin1.java
| | | | | +— Wicket1.java
| | | | +— secmgr
| | | | | +— DelegateSecurityManager.java
| | | | | +— ExecCheckingSecurityManager.java
| | | | +— Serializer.java
| | | | +— Strings.java

test模块先不放,首先先关注最核心的攻击代码部分:

| | | | | +— JBoss.java
| | | | | +— JenkinsCLI.java
| | | | | +— JenkinsListener.java
| | | | | +— JenkinsReverse.java
| | | | | +— JMXInvokeMBean.java
| | | | | +— JRMPClassLoadingListener.java
| | | | | +— JRMPClient.java
| | | | | +— JRMPListener.java
| | | | | +— JSF.java
| | | | | +— RMIRegistryExploit.java

正文–JBoss.java

先来看这个ysoserial/exploit/JBoss.java

Payload构建阶段

调用方法

java -cp ysoserial.jar ysoserial.exploit.JBoss

1609140925182

此处触发参数数量小于3

1609140981855

正确的攻击是需要加上URI和可选的其他参数的

然后108行根据URI构建一个URI对象:

1609141136594

这里使用了静态方法create,因此无需实例化,可直接调用传入参数

1609144548901

这里出现了Utils的 makePayloadObject方法,我们跟进看一下,按住Ctrl点击左键,传入参数为payloadType和payloadArg(示例:”119.23.31.1” “Clojure”):

1609141402939

此处Class用了泛型(限制通配符),该泛型需要继承自ObjectPayload对象,JAVA将错误解决在编译期,若指定的泛型对象不是ObjectPayload的子对象将不会通过。

通过类中getPayloadClass方法取得类Class对象(clazz):

1609141685786

其中还有两种取得类Class对象的方法,Class.class的方式在JBoss类104行已经使用过了,其区别为:

  • Class.class的形式会使 JVM 将使用类装载器将类装入内存(前提是类还没有装入内存),不做类的初始化工作,返回 Class 对象。
  • Class.forName()的形式会装入类并做类的静态初始化,返回 Class 对象。
  • getClass() 的形式会对类进行静态初始化、非静态初始化,返回引用运行时真正所指的对象(因为子对象的引用可能会赋给父对象的引用变量中)所属的类的 Class 对象。

因此本处使用了Class.forName的方式提取类class对象,同时进行了异常处理,防止没有找到。并且还进行了类型强制转换。

当然,如果没有在String中表达出完整的类路径,45行还会帮你进行设置添加Payload生成的包路径给你

1609142758230

再找不到就看clazz是否是ObjectPayload的父类(52行),比如说JAVA中的初始类Object,不是则返回null(未找到),是则返回类class对象(猜测是为了兼容父对象)

继续回到makePayloadObject对象,在获取了类Class对象(以下称clazz)后,判断clazz为空或者不是父类就抛出异常了:

1609143308050

在62行,对应:

1609143335823

很明显,Class.forName(“aaa”)或者Class.forName(“ysoserial.payloads.aaa”)这种是找不到对象的。

反之

1609143486305

后面使用newInstance来构建clazz的实例化对象,使用父类Object来接,这里是多态的应用,父类型声明对象可以接收子类型实例,但是不类型转化的话只能用父对象的方法了,demo示例:

1609396369906

1609143997499

然后使用ObjectPayload的getObject方法。放置执行的命令。然后返回Object对象:

1609144389144

回到JBoss类,开始解析host中的账号信息了:

1609144717230

getUserInfo之前没接触过,直接看文档:

1609144758188

返回解码的账号密码字符串再分割放入username和password变量,如known:knownsec@baidu.com

JBoss连接阶段

没有问题就进入doRun函数,传入URI对象、原始Object实例(用户传入)、账户、密码

先声明几个对象,放置日志记录,因此此步没那么重要,就简单带过了:

1609145278343

然后初始化OptionMap对象、ConnectionProviderContextImpl对象、ConnectionProvider对象

最后通过重重组装和HttpUpgradeConnectionProviderFactory().createInstance方法获取了一个实例用ConnectionProvider去接收。这里某些方法不是JAVA的原生方法,而是org.xnio或者org.jboss中的方法。因此需要翻apache的文档因此使用比较陌生比较正常。

然后构建host和port,实例化InetSocketAddress类,获取连接对象:

1609146800322

在JBoss服务正常的情况下并且账号密码正确时将到150行,之前更多的是通过JAVA去登录该JBoss服务。

而此次更多的是研究ysoserial运行机制因此不做深究。

然后进去makeVersionedConnection函数,发现在使用反射

反射第一步 获取类class对象(clazz)

1609147730694

利用该对象获取方法(createVersionedConnection方法),此步需要传入该方法参数的对应clazz(类class对象)

以前一直不理解怎么传,后来知道这里由该方法需要的参数所决定

1609148218704

文档对应的说明为,第一个参数为String类型的反射方法名,后面接该方法的参数类型(以声明顺序 来标识方法的 形式参数类型的 类对象 的数组):

1609148439068

因此这里是Channel.class, Map.class, JMXServiceURL.class

然后设置访问权限:

反射invoke执行,对方法传入参数为null, c, new HashMap(), new JMXServiceURL(“service:jmx:remoting-jmx://“)

1609148667604

Payload发送阶段

回到doRun函数,接下来用该对象构建一个MBeanServerConnection后便开始攻击了

1609210960495

这里的doExploit无非是拿开始的原生对象payloadObject传递后反射注入到MBeanServerConnection实例中去

同时该注入还需要其他参数,因此对Mbean进行了遍历.将恶意的对象注入后293行执行,在294行返回执行结果

1609211741100

然后回到doRun函数,doRun函数结束,回到main函数:

1609317286775

在127行释放payload:

1609317311001

进入releasePayload,参数有payload的全限定类名和payload类。

首先还是用开始的getPayloadClass函数获取了clazz,同时进行了未取到的报错处理:

1609319851618

利用类class对象创建实例,同时传入同名函数releasePayload,这里使用了相同的参数个数不同的参数类型书写同名方法,体现了JAVA中的重载。

1609320134703

然后判断payload是否是ReleaseableObjectPayload的类实例(上一步已经将其实例化)。如果是的话对其使用release方法,当然这里显然不是:

1609320320408

如果是的话转化为ReleaseableObjectPayload对象后(该接口声明了一个release空方法)

1609320991916

然后将执行payload自身的release方法。因此,如果带入的Payload的恶意的,自身机器将可能被执行恶意命令(重写release方法让其成为恶意的)。

这里第一次看到向父类转型父类是Interface的情况,写了个demo证实向父接口强转的确会调用子类的release方法:

1609384676275

总结

JBoss模块主要是针对JBoss进行服务注入的攻击模块。其需要登录JBoss后进行恶意的Payload注入攻击,过程中多处使用了反射、多态、重载、泛型等方面的知识,而这些知识又是在漏洞代码审计Review时非常重要的JAVA知识,对该工具代码的理解可加深代码审计人员对JAVA代码审计的认知,同时提高对漏洞的理解。

本文标题:ysoserial--JBoss篇

文章作者:

发布时间:2020年12月31日 - 15:13:37

最后更新:2021年01月04日 - 14:31:00

原始链接:http://laker.xyz/2020/12/31/ysoserial-JBoss%E7%AF%87/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。