Skip to content

Commit 16fa3b9

Browse files
committed
Land rapid7#9350, Improve fake SSL cert details
2 parents a98de2d + c32ef4a commit 16fa3b9

File tree

4 files changed

+110
-1
lines changed

4 files changed

+110
-1
lines changed

Gemfile.lock

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ PATH
1010
bcrypt_pbkdf
1111
bit-struct
1212
dnsruby
13+
faker
1314
filesize
1415
jsobfu
1516
json
@@ -122,6 +123,8 @@ GEM
122123
factory_girl_rails (4.9.0)
123124
factory_girl (~> 4.9.0)
124125
railties (>= 3.0.0)
126+
faker (1.8.7)
127+
i18n (>= 0.7)
125128
faraday (0.13.1)
126129
multipart-post (>= 1.2, < 3)
127130
ffi (1.9.18)
@@ -287,7 +290,7 @@ GEM
287290
metasm
288291
rex-core
289292
rex-text
290-
rex-socket (0.1.9)
293+
rex-socket (0.1.10)
291294
rex-core
292295
rex-sslscan (0.1.5)
293296
rex-core

lib/msf/core/cert_provider.rb

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

lib/msf/core/framework.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ module Offspring
6161
require 'msf/core/db_manager'
6262
require 'msf/core/event_dispatcher'
6363
require 'rex/json_hash_file'
64+
require 'msf/core/cert_provider'
6465

6566
#
6667
# Creates an instance of the framework context.
@@ -84,6 +85,9 @@ def initialize(options={})
8485
# Configure the thread factory
8586
Rex::ThreadFactory.provider = Metasploit::Framework::ThreadFactoryProvider.new(framework: self)
8687

88+
# Configure the SSL certificate generator
89+
Rex::Socket::Ssl.cert_provider = Msf::Ssl::CertProvider
90+
8791
subscriber = FrameworkEventSubscriber.new(self)
8892
events.add_exploit_subscriber(subscriber)
8993
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)