1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-10-29 18:07:27 +01:00

Update TLS certificate generation routines

Msf relies on Rex::Socket to create TLS certificates for services
hosted in the framework and used by some payloads. These certs are
flagged by NIDS - snort sid 1-34864 and such.

Now that Rex::Socket can accept a @@cert_provider from the Msf
namespace, a more robust generation routine can be used by all TLS
socket services, provided down from Msf to Rex, using dependencies
which Rex does not include.

This work adds the faker gem into runtime dependencies, creates an
Msf::Exploit::Remote::Ssl::CertProvider namespace, and provides
API compatible method invocations with the Rex version, but able
to generate higher entropy certs with more variables, options, etc.

This should reduce the hit rate against NIDS on the wire, reducing
pesky blue team interference until we slip up some other way. Also,
with the ability to generate different cert types, we may want to
look at extending this effort to probide a more comprehensive key
oracle to Framework and consumers.

Testing:
  None yet, internal tests pending.
  Travis should fail as this requires rex-socket #8.
This commit is contained in:
RageLtMan 2017-12-28 21:00:03 -05:00
parent 8c2c30c230
commit 18f3815147
3 changed files with 104 additions and 0 deletions

View File

@ -0,0 +1,99 @@
module Msf
module Exploit::Remote::Ssl
require 'rex/socket/ssl'
require 'faker'
module CertProvider
def self.rand_vars(opts = {})
opts ||= {}
opts[:cc] ||= 'US'
opts[:st] ||= Faker::Address.state_abbr
opts[:loc] ||= Faker::Address.city
opts[:org] ||= Faker::Company.name
opts[:ou] ||= Faker::Hacker.send(%w{noun verb adjective}.sample.to_sym).gsub(/\W+/,'.')
opts[:cn] ||= opts[:org].downcase.gsub(/and/,'').gsub(/\W+/,'.') + '.' + Faker::Internet.domain_suffix
opts[:email] ||= "#{opts[:ou]}@#{opts[:cn]}"
opts
end
def self.ssl_generate_subject(opts = {})
opts = self.rand_vars(opts)
subject = ""
subject << "/C=#{opts[:cc]}" if opts[:cc]
subject << "/ST=#{opts[:st]}" if opts[:st]
subject << "/O=#{opts[:org]}" if opts[:org]
subject << "/OU=#{opts[:ou]}" if opts[:ou]
subject << "/CN=#{opts[:cn]}" if opts[:cn]
subject << "/emailAddress=#{opts[:email]}" if opts[:email]
subject
end
# Not used, for API compatibility
def self.ssl_generate_issuer(
cc: 'US',
org: Faker::Company.name,
cn: Faker::Internet.domain_name
)
"#{cc}/O=#{org}/CN=#{cn}"
end
#
# Generate a realistic-looking but obstensibly fake SSL
# certificate. Use Faker gem to mimic other self-signed
# certificates on the web to reduce the chance of sig
# identification by NIDS and the like.
#
# @return [String, String, Array]
def self.ssl_generate_certificate(opts = {}, ksize = 2048)
yr = 24*3600*365
vf = opts[:not_before] || Time.at(Time.now.to_i - rand(yr * 3) - yr)
vt = opts[:not_after] || Time.at(vf.to_i + (rand(9)+1) * yr)
cvars = opts[:cert_vars] || self.rand_vars
subject = opts[:subject] || ssl_generate_subject(cvars)
ctype = opts[:cert_type] || opts[:ca_cert].nil? ? :ca : :server
key = opts[:key] || OpenSSL::PKey::RSA.new(ksize){ }
cert = OpenSSL::X509::Certificate.new
cert.version = opts[:version] || 2
cert.serial = opts[:serial] || (rand(0xFFFFFFFF) << 32) + rand(0xFFFFFFFF)
cert.subject = OpenSSL::X509::Name.new([["C", subject]])
cert.issuer = opts[:ca_cert] || cert.subject
cert.not_before = vf
cert.not_after = vt
cert.public_key = key.public_key
bconst, kuse, ekuse = case ctype
when :ca
['CA:TRUE', 'cRLSign,keyCertSign']
when :server
['CA:FALSE', 'digitalSignature,keyEncipherment', 'serverAuth']
when :client
['CA:FALSE', 'nonRepudiation,digitalSignature,keyEncipherment', 'clientAuth,emailProtection']
when :ocsp
['CA:FALSE', 'nonRepudiation,digitalSignature', 'serverAuth,OCSPSigning']
when :tsca
['CA:TRUE,pathlen:0', 'cRLSign,keyCertSign']
end
ef = OpenSSL::X509::ExtensionFactory.new
ef.subject_certificate = cert
ef.issuer_certificate = cert
cert.extensions = [
ef.create_extension("basicConstraints", bconst, true),
ef.create_extension("subjectKeyIdentifier", "hash")
]
if kuse and !kuse.empty?
cert.extensions << ef.create_extension("keyUsage", kuse)
end
if ekuse and !ekuse.empty?
cert.extensions << ef.create_extension("extendedKeyUsage", ekuse)
end
cert.sign(key, OpenSSL::Digest::SHA256.new)
[key, cert, nil]
end
end
end
end

View File

@ -84,6 +84,9 @@ class Framework
# Configure the thread factory # Configure the thread factory
Rex::ThreadFactory.provider = Metasploit::Framework::ThreadFactoryProvider.new(framework: self) Rex::ThreadFactory.provider = Metasploit::Framework::ThreadFactoryProvider.new(framework: self)
# Configure the SSL certificate generator
Rex::Socket::Ssl.cert_provider = Msf::Exploit::Remote::Ssl::CertProvider
subscriber = FrameworkEventSubscriber.new(self) subscriber = FrameworkEventSubscriber.new(self)
events.add_exploit_subscriber(subscriber) events.add_exploit_subscriber(subscriber)
events.add_session_subscriber(subscriber) events.add_session_subscriber(subscriber)

View File

@ -187,4 +187,6 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'nexpose' spec.add_runtime_dependency 'nexpose'
# Needed for NDMP sockets # Needed for NDMP sockets
spec.add_runtime_dependency 'xdr' spec.add_runtime_dependency 'xdr'
# Needed for ::Msf...CertProvider
spec.add_runtime_dependency 'faker'
end end