Rework changes on top of HD's PR

This commit removes duplication, tidies up a couple of things and puts
some common code into the x509 module.
This commit is contained in:
oj@buffered.io
2015-03-18 11:10:31 +10:00
committed by OJ
parent 7b4161bdb4
commit fd4ad9bd2e
5 changed files with 57 additions and 103 deletions
+4 -41
View File
@@ -3,6 +3,7 @@ require 'rex/io/stream_abstraction'
require 'rex/sync/ref'
require 'msf/core/handler/reverse_http/uri_checksum'
require 'rex/payloads/meterpreter/patch'
require 'rex/parser/x509_certificate'
module Msf
module Handler
@@ -356,56 +357,18 @@ protected
port > 0 ? port : datastore['LPORT'].to_i
end
# TODO: remove all that is below this when HD's PR has been landed
def get_ssl_cert_hash
unless datastore['StagerVerifySslCert'].to_s =~ /^(t|y|1)/i
unless datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
return nil
end
unless datastore['HandlerSSLCert']
raise ArgumentError, "StagerVerifySslCert is enabled but no HandlerSSLCert is configured"
raise ArgumentError, "StagerVerifySSLCert is enabled but no HandlerSSLCert is configured"
end
# TODO: fix this up when HD's PR has landed.
#hcert = Rex::Parser::X509Certificate.parse_pem_file(datastore['HandlerSSLCert'])
hcert = parse_pem_file(datastore['HandlerSSLCert'])
unless hcert and hcert[0] and hcert[1]
raise ArgumentError, "Could not parse a private key and certificate from #{datastore['HandlerSSLCert']}"
end
hash = Rex::Text.sha1_raw(hcert[1].to_der)
hash = Rex::Parser::X509Certificate.get_cert_file_hash(datastore['HandlerSSLCert'])
print_status("Meterpreter will verify SSL Certificate with SHA1 hash #{hash.unpack("H*").first}")
hash
nil
end
def parse_pem(ssl_cert)
cert = nil
key = nil
chain = nil
certs = []
ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
if pem =~ /PRIVATE KEY/
key = OpenSSL::PKey::RSA.new(pem)
elsif pem =~ /CERTIFICATE/
certs << OpenSSL::X509::Certificate.new(pem)
end
end
cert = certs.shift
if certs.length > 0
chain = certs
end
[key, cert, chain]
end
def parse_pem_file(ssl_cert_file)
data = ''
::File.open(ssl_cert_file, 'rb') do |fd|
data << fd.read(fd.stat.size)
end
parse_pem(data)
end
end
@@ -108,8 +108,7 @@ module Payload::Windows::ReverseWinHttp
# @option opts [String] :url The URI to request during staging
# @option opts [String] :host The host to connect to
# @option opts [Fixnum] :port The port to connect to
# @option opts [Bool] :verify_ssl Whether or not to do SSL certificate validation
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify, or nil
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
# @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
#
@@ -121,7 +120,7 @@ module Payload::Windows::ReverseWinHttp
encoded_url = asm_generate_wchar_array(opts[:url])
encoded_host = asm_generate_wchar_array(opts[:host])
if opts[:ssl] && opts[:verify_cert] && opts[:verify_cert_hash]
if opts[:ssl] && opts[:verify_cert_hash]
verify_ssl = true
encoded_cert_hash = opts[:verify_cert_hash].unpack("C*").map{|c| "0x%.2x" % c }.join(",")
end
@@ -49,27 +49,12 @@ module Payload::Windows::ReverseWinHttps
#
def generate
verify_cert = false
verify_cert_hash = nil
if datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
unless datastore['HandlerSSLCert']
raise ArgumentError, "StagerVerifySSLCert is enabled but no HandlerSSLCert is configured"
else
verify_cert = true
hcert = Rex::Parser::X509Certificate.parse_pem_file(datastore['HandlerSSLCert'])
unless hcert and hcert[0] and hcert[1]
raise ArgumentError, "Could not parse a private key and certificate from #{datastore['HandlerSSLCert']}"
end
verify_cert_hash = Rex::Text.sha1_raw(hcert[1].to_der)
print_status("Stager will verify SSL Certificate with SHA1 hash #{verify_cert_hash.unpack("H*").first}")
end
end
verify_cert_hash = get_ssl_cert_hash
# Generate the simple version of this stager if we don't have enough space
if self.available_space.nil? || required_space > self.available_space
if datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
if verify_cert_hash
raise ArgumentError, "StagerVerifySSLCert is enabled but not enough payload space is available"
end
@@ -78,7 +63,6 @@ module Payload::Windows::ReverseWinHttps
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_small_uri,
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount'])
end
@@ -89,7 +73,6 @@ module Payload::Windows::ReverseWinHttps
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC'],
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount']
}
@@ -114,6 +97,23 @@ module Payload::Windows::ReverseWinHttps
space
end
#
# Get the SSL hash from the certificate, if required.
#
def get_ssl_cert_hash
unless datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
return nil
end
unless datastore['HandlerSSLCert']
raise ArgumentError, "StagerVerifySSLCert is enabled but no HandlerSSLCert is configured"
end
hash = Rex::Parser::X509Certificate.get_cert_file_hash(datastore['HandlerSSLCert'])
print_status("Meterpreter will verify SSL Certificate with SHA1 hash #{hash.unpack("H*").first}")
hash
end
end
end
+30
View File
@@ -56,6 +56,36 @@ class X509Certificate
parse_pem(data)
end
#
# Parse a certificate in unified PEM format and retrieve
# the SHA1 hash.
#
# @param [String] ssl_cert
# @return [String]
def self.get_cert_hash(ssl_cert)
hcert = parse_pem(ssl_cert)
unless hcert and hcert[0] and hcert[1]
raise ArgumentError, "Could not parse a private key and certificate"
end
Rex::Text.sha1_raw(hcert[1].to_der)
end
#
# Parse a file that contains a certificate in unified PEM
# format and retrieve the SHA1 hash.
#
# @param [String] ssl_cert_file
# @return [String]
def self.get_cert_file_hash(ssl_cert_file)
data = ''
::File.open(ssl_cert_file, 'rb') do |fd|
data << fd.read(fd.stat.size)
end
get_cert_hash(data)
end
end
end
@@ -8,8 +8,7 @@ require 'msf/core/handler/reverse_https'
require 'msf/core/payload/windows/stageless_meterpreter'
require 'msf/base/sessions/meterpreter_x86_win'
require 'msf/base/sessions/meterpreter_options'
# TODO: put this in when HD's PR has been landed.
#require 'rex/parser/x509_certificate'
require 'rex/parser/x509_certificate'
module Metasploit3
@@ -72,7 +71,6 @@ module Metasploit3
end
# TODO: remove all that is below this when HD's PR has been landed
def get_ssl_cert_hash
unless datastore['StagerVerifySSLCert'].to_s =~ /^(t|y|1)/i
return nil
@@ -82,46 +80,10 @@ module Metasploit3
raise ArgumentError, "StagerVerifySSLCert is enabled but no HandlerSSLCert is configured"
end
# TODO: fix this up when HD's PR has landed.
#hcert = Rex::Parser::X509Certificate.parse_pem_file(datastore['HandlerSSLCert'])
hcert = parse_pem_file(datastore['HandlerSSLCert'])
unless hcert and hcert[0] and hcert[1]
raise ArgumentError, "Could not parse a private key and certificate from #{datastore['HandlerSSLCert']}"
end
hash = Rex::Text.sha1_raw(hcert[1].to_der)
hash = Rex::Parser::X509Certificate.get_cert_file_hash(datastore['HandlerSSLCert'])
print_status("Meterpreter will verify SSL Certificate with SHA1 hash #{hash.unpack("H*").first}")
hash
end
def parse_pem(ssl_cert)
cert = nil
key = nil
chain = nil
certs = []
ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
if pem =~ /PRIVATE KEY/
key = OpenSSL::PKey::RSA.new(pem)
elsif pem =~ /CERTIFICATE/
certs << OpenSSL::X509::Certificate.new(pem)
end
end
cert = certs.shift
if certs.length > 0
chain = certs
end
[key, cert, chain]
end
def parse_pem_file(ssl_cert_file)
data = ''
::File.open(ssl_cert_file, 'rb') do |fd|
data << fd.read(fd.stat.size)
end
parse_pem(data)
end
end