新聞中心
[[344961]]

創(chuàng)新互聯(lián)專(zhuān)注于棗陽(yáng)網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供棗陽(yáng)營(yíng)銷(xiāo)型網(wǎng)站建設(shè),棗陽(yáng)網(wǎng)站制作、棗陽(yáng)網(wǎng)頁(yè)設(shè)計(jì)、棗陽(yáng)網(wǎng)站官網(wǎng)定制、微信小程序定制開(kāi)發(fā)服務(wù),打造棗陽(yáng)網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供棗陽(yáng)網(wǎng)站排名全網(wǎng)營(yíng)銷(xiāo)落地服務(wù)。
漏洞分析
Apache OFBiz是一個(gè)開(kāi)源的企業(yè)資源規(guī)劃(ERP)系統(tǒng),它提供了一系列企業(yè)應(yīng)用程序來(lái)幫助企業(yè)自動(dòng)化實(shí)現(xiàn)很多業(yè)務(wù)流程。它包含了一個(gè)能提供常見(jiàn)數(shù)據(jù)模型和業(yè)務(wù)進(jìn)程的框架,企業(yè)內(nèi)所有的應(yīng)用程序都需要采用這個(gè)框架來(lái)使用常見(jiàn)數(shù)據(jù)、邏輯和業(yè)務(wù)處理組件。除了框架本身之外,Apache OFBiz還提供了包括會(huì)計(jì)(合同協(xié)議、票據(jù)、供應(yīng)商管理、總賬)、資產(chǎn)維護(hù)、項(xiàng)目分類(lèi)、產(chǎn)品管理、設(shè)備管理、倉(cāng)庫(kù)管理系統(tǒng)(WMS)、制造執(zhí)行/制造運(yùn)營(yíng)管理(MES/MOM)和訂單處理等功能,除此之外,還實(shí)現(xiàn)了庫(kù)存管理、自動(dòng)庫(kù)存補(bǔ)充、內(nèi)容管理系統(tǒng)(CMS)、人力資源(HR)、人員和團(tuán)隊(duì)管理、項(xiàng)目管理、銷(xiāo)售人員自動(dòng)化、工作量管理、電子銷(xiāo)售點(diǎn)(ePOS)、電子商務(wù)(電子商務(wù))和scrum(開(kāi)發(fā))等多種功能。
Apache OFBiz使用了一系列開(kāi)源技術(shù)和標(biāo)準(zhǔn),比如Java、JavaEE、XML和SOAP。
超文本傳輸協(xié)議是一種請(qǐng)求/響應(yīng)協(xié)議,該協(xié)議在 RFC 7230-7237中有詳細(xì)描述。請(qǐng)求由客戶(hù)端設(shè)備發(fā)送至服務(wù)器,服務(wù)器接收并處理請(qǐng)求后,會(huì)將響應(yīng)發(fā)送回客戶(hù)端。一個(gè)HTTP請(qǐng)求由請(qǐng)求內(nèi)容、各種Header、空行和可選消息體組成:
- Request = Request-Line headers CRLF [message-body]
- Request-Line = Method SP Request-URI SP HTTP-Version CRLF
- Headers = *[Header]
- Header = Field-Name “:” Field-Value CRLF
CRLF代表新的行序列回車(chē)符(CR),后跟換行符(LF),SP表示空格字符。參數(shù)將以鍵值對(duì)的形式通過(guò)Request- URI或message-body由客戶(hù)端傳遞給服務(wù)器,具體將取決于Method和Content-Type頭中定義的參數(shù)。比如說(shuō)在下面的HTTP請(qǐng)求樣本中,有一個(gè)名為“param”的參數(shù),其值為“1”,使用的是POST方法:
- POST /my_webapp/mypage.htm HTTP/1.1
- Host: www.myhost.com
- Content-Type: application/x-www-form-urlencoded
- Content-Length: 7
- param=1
Java序列化
Java支持對(duì)對(duì)象進(jìn)行序列化操作,使它們額能夠被表示為緊湊和可移植的字節(jié)流,然后可以通過(guò)網(wǎng)絡(luò)傳輸這個(gè)字節(jié)流,并將其反序列化以供接收的servlet或applet使用。下面的示例演示了如何將一個(gè)類(lèi)進(jìn)行序列化并在隨后提取數(shù)據(jù):
- public static void main(String args[]) throws Exception{
- //This is the object we're going to serialize.
- MyObject1 myObj = new MyObject1();
- MyObject2 myObj2 = new MyObject2();
- myObj2.name = "calc";
- myObj.test = myObj2;
- //We'll write the serialized data to a file "object.ser"
- FileOutputStream fos = new FileOutputStream("object.ser");
- ObjectOutputStream os = new ObjectOutputStream(fos);
- os.writeObject(myObj);
- os.close();
- //Read the serialized data back in from the file "object.ser"
- FileInputStream fis = new FileInputStream("object.ser");
- ObjectInputStream ois = new ObjectInputStream(fis);
- //Read the object from the data stream, and convert it back to a String
- MyObject1 objectFromDisk = (MyObject1)ois.readObject();
- ois.close();
- }
所有的Java對(duì)象都需要通過(guò)Serializable或Externalizable接口來(lái)進(jìn)行序列化,這個(gè)接口實(shí)現(xiàn)了writeObject()/writeExternal()和readObject()/readExternal()方法,它們會(huì)在對(duì)象序列化或反序列化時(shí)被調(diào)用。這些方法能夠在序列化和反序列化過(guò)程中通過(guò)修改代碼來(lái)實(shí)現(xiàn)自定義行為。
XML-RPC
XML-RPC是一個(gè)遠(yuǎn)程過(guò)程調(diào)用(RPC)協(xié)議,它使用XML對(duì)其調(diào)用進(jìn)行編碼,并使用HTTP作為傳輸機(jī)制。它是一種標(biāo)準(zhǔn)規(guī)范,并提供了現(xiàn)成的實(shí)現(xiàn)方式,允許運(yùn)行在不同的操作系統(tǒng)和環(huán)境中。在在XML-RPC中,客戶(hù)機(jī)通過(guò)向?qū)崿F(xiàn)XML-RPC并接收HTTP響應(yīng)的服務(wù)器發(fā)送HTTP請(qǐng)求來(lái)執(zhí)行RPC。
每個(gè)XML-RPC請(qǐng)求都以XML元素“
如下樣例所示,常見(jiàn)的數(shù)據(jù)類(lèi)型可以被轉(zhuǎn)換成對(duì)應(yīng)的XML類(lèi)型:
1404 Something here 1
各種原語(yǔ)的編碼示例如下:
1 -12.53 42
字符串的編碼示例如下:
Hello world!
對(duì)結(jié)構(gòu)體的編碼示例如下:
foo 1 bar 2
序列化數(shù)據(jù)由””和””XML元素包裹來(lái)表示,在Apache OFBiz中,序列化代碼在org.apache.xmlrpc.parser.SerializableParser這個(gè)Java類(lèi)中實(shí)現(xiàn)。
但是,Apache OFBiz中存在一個(gè)不安全的反序列化漏洞,這個(gè)漏洞是由于OFBiz被配置為在發(fā)送到“/webtools/control/xmlrpc”URL時(shí)使用XML-RPC攔截和轉(zhuǎn)換HTTP主體中的XML數(shù)據(jù)所導(dǎo)致的。發(fā)送到此端點(diǎn)的請(qǐng)求最初由org.apache.ofbiz.webapp.control.RequestHandler這個(gè)Java類(lèi)來(lái)處理,它確定的URL的映射方式。接下來(lái),org.apache.ofbiz.webapp.event.XmlRpcEventHandler類(lèi)將調(diào)用execute()方法,XML解析首先需要通過(guò)XMLReader類(lèi)來(lái)調(diào)用parse()方法,而這個(gè)方法需要在org.apache.ofbiz.webapp.event.XmlRpcEventHandler類(lèi)的getRequest()方法中調(diào)用。
XML-RPC請(qǐng)求中的元素將會(huì)在下列類(lèi)中被解析:
- org.apache.xmlrpc.parser.XmlRpcRequestParser
- org.apache.xmlrpc.parser.RecursiveTypeParserImpl
- org.apache.xmlrpc.parser.MapParser
不安全的序列化問(wèn)題存在于org.apache.xmlrpc.parser.SerializableParser類(lèi)的getResult()方法之中。一個(gè)未經(jīng)身份驗(yàn)證的遠(yuǎn)程攻擊者可以利用該漏洞來(lái)發(fā)送包含了定制XML Payload的惡意HTTP請(qǐng)求。由于OFBiz使用了存在漏洞的Apache Commons BeanUtils庫(kù)和Apache ROME庫(kù),攻擊者將能夠使用ysoserial工具以XML格式來(lái)構(gòu)建惡意Payload。該漏洞的成功利用將導(dǎo)致攻擊者在目標(biāo)應(yīng)用程序中實(shí)現(xiàn)任意代碼執(zhí)行。
源代碼分析
下列代碼段取自Apache OFBiz v17.12.03版本,并添加了相應(yīng)的注釋。
org.apache.ofbiz.webapp.control.RequestHandler:
- public void doRequest(HttpServletRequest request, HttpServletResponse response, String chain,
- GenericValue userLogin, Delegator delegator) throws RequestHandlerException,
- RequestHandlerExceptionAllowExternalRequests {
- ConfigXMLReader.RequestResponse eventReturnBasedRequestResponse;
- if (!this.hostHeadersAllowed.contains(request.getServerName())) {
- Debug.logError("Domain " + request.getServerName() + " not accepted to prevent host header injection ", module);
- throw new RequestHandlerException("Domain " + request.getServerName() + " not accepted to prevent host header injection ");
- }
- boolean throwRequestHandlerExceptionOnMissingLocalRequest = EntityUtilProperties.propertyValueEqualsIgnoreCase("requestHandler", "throwRequestHandlerExceptionOnMissingLocalRequest", "Y", delegator);
- long startTime = System.currentTimeMillis();
- HttpSession session = request.getSession();
- ConfigXMLReader.ControllerConfig controllerConfig = getControllerConfig();
- Map
requestMapMap = null; - String statusCodeString = null;
- try {
- requestMapMap = controllerConfig.getRequestMapMap();
- statusCodeString = controllerConfig.getStatusCode();
- } catch (WebAppConfigurationException e) {
- Debug.logError((Throwable)e, "Exception thrown while parsing controller.xml file: ", module);
- throw new RequestHandlerException(e);
- }
- if (UtilValidate.isEmpty(statusCodeString))
- statusCodeString = this.defaultStatusCodeString;
- String cname = UtilHttp.getApplicationName(request);
- String defaultRequestUri = getRequestUri(request.getPathInfo());
- if (request.getAttribute("targetRequestUri") == null)
- if (request.getSession().getAttribute("_PREVIOUS_REQUEST_") != null) {
- request.setAttribute("targetRequestUri", request.getSession().getAttribute("_PREVIOUS_REQUEST_"));
org.apache.ofbiz.webapp.event.XmlRpcEventHandler:
- public void execute(XmlRpcStreamRequestConfig pConfig, ServerStreamConnection pConnection) throws XmlRpcException {
- try {
- ByteArrayOutputStream baos;
- OutputStream initialStream;
- 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;
- }
- 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");
- }
- }
- }
- protected XmlRpcRequest getRequest(final XmlRpcStreamRequestConfig pConfig, InputStream pStream) throws XmlRpcException {
- final XmlRpcRequestParser parser =
- new XmlRpcRequestParser((XmlRpcStreamConfig)pConfig, getTypeFactory());
- XMLReader xr = SAXParsers.newXMLReader();
- xr.setContentHandler((ContentHandler)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);
- //the parsing of XML in the HTTP body starts in this function
- xr.parse(new InputSource(pStream));
- //truncated
- }
- }
org.apache.xmlrpc.parser.XmlRpcRequestParser:
- public void endElement(String pURI, String pLocalName, String pQName) throws SAXException {
- //XML-RPC parsing happens here
- switch(--level) {
- case 0:
- break;
- case 1:
- if (inMethodName) {
- if ("".equals(pURI) && "methodName".equals(pLocalName)) {
- if (methodName == null) {
- methodName = "";
- }
- } else {
- throw new SAXParseException("Expected /methodName, got " + new QName(pURI, pLocalName), getDocumentLocator());
- }
- inMethodName = false;
- } else if (!"".equals(pURI) || !"params".equals(pLocalName)) {
- throw new SAXParseException("Expected /params, got " + new QName(pURI, pLocalName), getDocumentLocator());
- }
- break;
- case 2:
- if (!"".equals(pURI) || !"param".equals(pLocalName)) {
- throw new SAXParseException("Expected /param, got " + new QName(pURI, pLocalName), getDocumentLocator());
- }
- break;
- case 3:
- if (!"".equals(pURI) || !"value".equals(pLocalName)) {
- throw new SAXParseException("Expected /value, got " + new QName(pURI, pLocalName), getDocumentLocator());
- }
- endValueTag();
- break;
- default:
- super.endElement(pURI, pLocalName, pQName);
- break;
- }
- }
org.apache.xmlrpc.parser.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);
- //insecure deserialization happens here
- 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);
- }
- }
- }
為了觸發(fā)該漏洞,攻擊者需要以XML格式在HTTP請(qǐng)求中攜帶定制的序列化對(duì)象,并發(fā)送給存在漏洞的目標(biāo)應(yīng)用程序,當(dāng)服務(wù)器端在序列化XML數(shù)據(jù)時(shí),便會(huì)觸發(fā)該漏洞。
網(wǎng)頁(yè)名稱(chēng):APACHE OFBIZ XMLRPC遠(yuǎn)程代碼執(zhí)行漏洞分析
網(wǎng)頁(yè)網(wǎng)址:http://www.5511xx.com/article/cdieice.html


咨詢(xún)
建站咨詢(xún)
