Skip to content

Commit 18f3815

Browse files
author
RageLtMan
committed
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.
1 parent 8c2c30c commit 18f3815

File tree

3 files changed

+104
-0
lines changed

3 files changed

+104
-0
lines changed

lib/msf/core/exploit/ssl.rb

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
module Msf
2+
module Exploit::Remote::Ssl
3+
require 'rex/socket/ssl'
4+
require 'faker'
5+
module CertProvider
6+
7+
def self.rand_vars(opts = {})
8+
opts ||= {}
9+
opts[:cc] ||= 'US'
10+
opts[:st] ||= Faker::Address.state_abbr
11+
opts[:loc] ||= Faker::Address.city
12+
opts[:org] ||= Faker::Company.name
13+
opts[:ou] ||= Faker::Hacker.send(%w{noun verb adjective}.sample.to_sym).gsub(/\W+/,'.')
14+
opts[:cn] ||= opts[:org].downcase.gsub(/and/,'').gsub(/\W+/,'.') + '.' + Faker::Internet.domain_suffix
15+
opts[:email] ||= "#{opts[:ou]}@#{opts[:cn]}"
16+
opts
17+
end
18+
19+
def self.ssl_generate_subject(opts = {})
20+
opts = self.rand_vars(opts)
21+
subject = ""
22+
subject << "/C=#{opts[:cc]}" if opts[:cc]
23+
subject << "/ST=#{opts[:st]}" if opts[:st]
24+
subject << "/O=#{opts[:org]}" if opts[:org]
25+
subject << "/OU=#{opts[:ou]}" if opts[:ou]
26+
subject << "/CN=#{opts[:cn]}" if opts[:cn]
27+
subject << "/emailAddress=#{opts[:email]}" if opts[:email]
28+
subject
29+
end
30+
31+
# Not used, for API compatibility
32+
def self.ssl_generate_issuer(
33+
cc: 'US',
34+
org: Faker::Company.name,
35+
cn: Faker::Internet.domain_name
36+
)
37+
"#{cc}/O=#{org}/CN=#{cn}"
38+
end
39+
40+
#
41+
# Generate a realistic-looking but obstensibly fake SSL
42+
# certificate. Use Faker gem to mimic other self-signed
43+
# certificates on the web to reduce the chance of sig
44+
# identification by NIDS and the like.
45+
#
46+
# @return [String, String, Array]
47+
def self.ssl_generate_certificate(opts = {}, ksize = 2048)
48+
yr = 24*3600*365
49+
vf = opts[:not_before] || Time.at(Time.now.to_i - rand(yr * 3) - yr)
50+
vt = opts[:not_after] || Time.at(vf.to_i + (rand(9)+1) * yr)
51+
cvars = opts[:cert_vars] || self.rand_vars
52+
subject = opts[:subject] || ssl_generate_subject(cvars)
53+
ctype = opts[:cert_type] || opts[:ca_cert].nil? ? :ca : :server
54+
key = opts[:key] || OpenSSL::PKey::RSA.new(ksize){ }
55+
cert = OpenSSL::X509::Certificate.new
56+
57+
cert.version = opts[:version] || 2
58+
cert.serial = opts[:serial] || (rand(0xFFFFFFFF) << 32) + rand(0xFFFFFFFF)
59+
cert.subject = OpenSSL::X509::Name.new([["C", subject]])
60+
cert.issuer = opts[:ca_cert] || cert.subject
61+
cert.not_before = vf
62+
cert.not_after = vt
63+
cert.public_key = key.public_key
64+
65+
bconst, kuse, ekuse = case ctype
66+
when :ca
67+
['CA:TRUE', 'cRLSign,keyCertSign']
68+
when :server
69+
['CA:FALSE', 'digitalSignature,keyEncipherment', 'serverAuth']
70+
when :client
71+
['CA:FALSE', 'nonRepudiation,digitalSignature,keyEncipherment', 'clientAuth,emailProtection']
72+
when :ocsp
73+
['CA:FALSE', 'nonRepudiation,digitalSignature', 'serverAuth,OCSPSigning']
74+
when :tsca
75+
['CA:TRUE,pathlen:0', 'cRLSign,keyCertSign']
76+
end
77+
78+
ef = OpenSSL::X509::ExtensionFactory.new
79+
ef.subject_certificate = cert
80+
ef.issuer_certificate = cert
81+
cert.extensions = [
82+
ef.create_extension("basicConstraints", bconst, true),
83+
ef.create_extension("subjectKeyIdentifier", "hash")
84+
]
85+
if kuse and !kuse.empty?
86+
cert.extensions << ef.create_extension("keyUsage", kuse)
87+
end
88+
89+
if ekuse and !ekuse.empty?
90+
cert.extensions << ef.create_extension("extendedKeyUsage", ekuse)
91+
end
92+
93+
cert.sign(key, OpenSSL::Digest::SHA256.new)
94+
95+
[key, cert, nil]
96+
end
97+
end
98+
end
99+
end

lib/msf/core/framework.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ def initialize(options={})
8484
# Configure the thread factory
8585
Rex::ThreadFactory.provider = Metasploit::Framework::ThreadFactoryProvider.new(framework: self)
8686

87+
# Configure the SSL certificate generator
88+
Rex::Socket::Ssl.cert_provider = Msf::Exploit::Remote::Ssl::CertProvider
89+
8790
subscriber = FrameworkEventSubscriber.new(self)
8891
events.add_exploit_subscriber(subscriber)
8992
events.add_session_subscriber(subscriber)

metasploit-framework.gemspec

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,6 @@ Gem::Specification.new do |spec|
187187
spec.add_runtime_dependency 'nexpose'
188188
# Needed for NDMP sockets
189189
spec.add_runtime_dependency 'xdr'
190+
# Needed for ::Msf...CertProvider
191+
spec.add_runtime_dependency 'faker'
190192
end

0 commit comments

Comments
 (0)