前言
Apache OFBiz(Open for Business Project)是一个非常强大的开源企业资源规划(ERP)和企业自动化软件。它提供了一整套业务应用程序组件,可以用于构建各种企业级的业务管理系统,包括但不限于客户关系管理(CRM)、供应链管理(SCM)、电子商务、财务管理、制造管理等多个业务领域。
由于其连续爆出多个由于权限问题所导致的漏洞,本文旨在分析部分相关漏洞,学习了解相关的漏洞成因及利用手法。Apache OFBiz具体的漏洞细节可以在其官网查看,https://ofbiz.apache.org/security.html。
Pre Auth
CVE-2020-9496
Apache XML-RPC是Apache软件基金会下的一个开源项目,它为Java开发者提供了一个完整的XML-RPC实现框架,方便开发人员在Java环境中构建能够支持XML-RPC通信的客户端和服务器端应用程序。但在2010年前后,Apache XML-RPC基本上就不更新了,历史上出现过多个反序列化漏洞(如CVE-2016-5003、CVE-2019-17570),但都没有被修复。而Apache OFBiz由于使用了XML-RPC组件,因此导致了漏洞的存在。
该漏洞的本质原因为Apache OFBiz使用了XML-RPC组件,从而导致其易受不安全反序列化的影响。漏洞入口点在/webtools/control/xmlrpc,查看framework/webtools/webapp/webtools/WEB-INF/web.xml,可以得知control路由由org.apache.ofbiz.webapp.control.ControlServlet进行处理。
1 | <servlet> |
跟进org.apache.ofbiz.webapp.control.ControlServlet#doGet方法,先获取RequestHandler。
接着尝试从ServletContext中获取一个名为_REQUEST_HANDLER_的属性,可以看到读取了framework/webtools/webapp/webtools/WEB-INF/controller.xml文件。
1 | <request-map uri="xmlrpc" track-serverhit="false" track-visit="false"> |
可以看到对于xmlrpc路由,其security的值为false,即无需鉴权即可访问,接着进行一系列请求处理后调用org.apache.ofbiz.webapp.control.RequestHandler#doRequest方法来处理请求。
接着从framework/webtools/webapp/webtools/WEB-INF/controller.xml文件获取控制器配置信息。然后匹配访问的路由。
接着调用到org.apache.ofbiz.webapp.control.RequestHandler#runEvent方法,根据event的类型,在工厂类中获取对应的EventHandler并执行其invoke方法。
xmlrpc路由对应的EventHandler是XmlRpcEventHandler类,跟进org.apache.ofbiz.webapp.event.XmlRpcEventHandler#invoke方法,当请求中缺乏echo参数时进入else语句,调用org.apache.ofbiz.webapp.event.XmlRpcEventHandler#execute方法。
在org.apache.ofbiz.webapp.event.XmlRpcEventHandler#execute方法中,传入获取的XML-RPC配置和创建的HttpStreamConnection对象,执行XML-RPC调用。
跟进org.apache.ofbiz.webapp.event.XmlRpcEventHandler#getRequest方法,创建一个XmlRpcRequestParser对象,用于解析XML-RPC请求,使用SAXParsers#newXMLReader实例化一个新的XMLReader对象,接着利用XMLReader解析输入流中的XML数据。
继续跟进XmlRpcRequestParser,此时对输入流中的XML进行解析,包括startElement方法、endElement方法等,在startElement方法中会调用父类org.apache.xmlrpc.parser.RecursiveTypeParserImpl的startElement方法。
在org.apache.xmlrpc.parser.RecursiveTypeParserImpl#startElement方法中,扫描XML的标签的时候会调用getParser方法获取对应标签的parser。
当标签为serializable时会调用解析器SerializableParser,其父类是ByteArrayParser,先进行一次Base64解码,然后在SerializerParser#getResult方法中会触发反序列化。
需要注意的是,XmlRpcRequestParser的对于XML的解析中,处理过程是按照methodCall,methodName,params,param的顺序遍历标签进行的,当扫描完4个必须提供的标签后,才会调用父类的startElement方法进行处理,而typeParser就是在父类中完成赋值的,随后通过不同的解析器进入不同的解析流程。
因此,最后default中的解析是从value节点内开始的,而直接传入searializable标签是不存在getResult方法触发的,这里利用struct标签进行一层嵌套。
漏洞利用数据包如下:
1 | POST /webtools/control/xmlrpc |
官方第一次提交的修复补丁https://github.com/apache/ofbiz-framework/commit/4bdfb54ffb6e05215dd826ca2902c3e31420287a,此次补丁的主要作用是为XML-RPC的接口进行鉴权。
但是这种修复方式治标不治本,攻击者依旧可以实现Post-Auth攻击,因此官方进行了二次补丁,此次增加了关键词的检测。但是这样就安全了嘛?很明显,可以利用增加空格的方式来进行绕过,因此官方又进行了一次补丁https://github.com/apache/ofbiz-framework/commit/25293e4cf6f334a2ae33b3041acba45113dddce9,通过检测</serializable关键词来进行防御。
CVE-2021-26295
在上文分析CVE-2020-9496时,在controller.xml文件中还存在另一个路由SOAPService,其鉴权也是缺失的。
1 | <request-map uri="SOAPService"> |
可以看到,SOAPService路由对应的event为soap,寻找对应的SOAP Event Handler。在org.apache.ofbiz.webapp.event.SOAPEventHandler#invoke方法中,会利用SoapSerializer#deserialize方法,将SOAP请求中的XML数据反序列化为Java对象。
1 | public String invoke(Event event, RequestMap requestMap, HttpServletRequest request, HttpServletResponse response) throws EventHandlerException { |
在org.apache.ofbiz.service.engine.SoapSerializer#deserialize方法中,会利用XmlSerializer#deserialize方法来将XML数据反序列化为Java对象。
1 | public static Object deserialize(String content, Delegator delegator) throws SerializeException, SAXException, ParserConfigurationException, IOException { |
在org.apache.ofbiz.entity.serialize.XmlSerializer#deserialize方法中,调用org.apache.ofbiz.entity.serialize.XmlSerializer#deserializeSingle方法,根据标签进行解析,接着进一步调用org.apache.ofbiz.entity.serialize.XmlSerializer#deserializeCustom