Skip to content

Commit a64dd4a

Browse files
committed
Land rapid7#4871, Postgres PTH support
MSP-12244
2 parents 1676d98 + 8d6ba0e commit a64dd4a

File tree

9 files changed

+33
-13
lines changed

9 files changed

+33
-13
lines changed

Gemfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ PATH
2222
tzinfo
2323
metasploit-framework-db (4.11.0.pre.dev)
2424
activerecord (>= 3.2.21, < 4.0.0)
25-
metasploit-credential (~> 0.14.0)
25+
metasploit-credential (~> 0.14.2)
2626
metasploit-framework (= 4.11.0.pre.dev)
2727
metasploit_data_models (~> 0.23.0)
2828
pg (>= 0.11)
@@ -112,7 +112,7 @@ GEM
112112
metasploit-concern (0.3.0)
113113
activesupport (~> 3.0, >= 3.0.0)
114114
railties (< 4.0.0)
115-
metasploit-credential (0.14.0)
115+
metasploit-credential (0.14.2)
116116
metasploit-concern (~> 0.3.0)
117117
metasploit-model (~> 0.29.0)
118118
metasploit_data_models (~> 0.23.0)
@@ -123,7 +123,7 @@ GEM
123123
metasploit-model (0.29.0)
124124
activesupport
125125
railties (< 4.0.0)
126-
metasploit_data_models (0.23.0)
126+
metasploit_data_models (0.23.1)
127127
activerecord (>= 3.2.13, < 4.0.0)
128128
activesupport
129129
arel-helpers
@@ -199,7 +199,7 @@ GEM
199199
rspec-core (~> 2.99.0)
200200
rspec-expectations (~> 2.99.0)
201201
rspec-mocks (~> 2.99.0)
202-
rubyntlm (0.4.0)
202+
rubyntlm (0.5.0)
203203
rubyzip (1.1.7)
204204
shoulda-matchers (2.6.2)
205205
simplecov (0.5.4)

db/schema.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,9 +393,11 @@
393393
t.boolean "critical"
394394
t.boolean "seen"
395395
t.text "data"
396+
t.integer "vuln_id"
396397
end
397398

398399
add_index "notes", ["ntype"], :name => "index_notes_on_ntype"
400+
add_index "notes", ["vuln_id"], :name => "index_notes_on_vuln_id"
399401

400402
create_table "profiles", :force => true do |t|
401403
t.datetime "created_at", :null => false

lib/metasploit/framework/credential.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class Credential
5151
# These values should be #demodularized from subclasses of
5252
# `Metasploit::Credential::Private`
5353
validates :private_type,
54-
inclusion: { in: [ :password, :ntlm_hash, :ssh_key ] },
54+
inclusion: { in: [ :password, :ntlm_hash, :postgres_md5, :ssh_key ] },
5555
if: "private_type.present?"
5656

5757
# If we have no private we MUST have a public

lib/metasploit/framework/credential_collection.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ def each
210210
def private_type(private)
211211
if private =~ /[0-9a-f]{32}:[0-9a-f]{32}/
212212
:ntlm_hash
213+
elsif private =~ /^md5([a-f0-9]{32})$/
214+
:postgres_md5
213215
else
214216
:password
215217
end

lib/metasploit/framework/login_scanner/postgres.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ def attempt_login(credential)
6262
end
6363
rescue Rex::ConnectionError, EOFError, Timeout::Error => e
6464
result_options.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
65+
rescue Msf::Db::PostgresPR::AuthenticationMethodMismatch => e
66+
result_options.merge!({
67+
status: Metasploit::Model::Login::Status::INCORRECT,
68+
proof: e.message
69+
})
6570
end
6671

6772
if pg_conn

lib/postgres/postgres-pr/connection.rb

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ module PostgresPR
1919

2020
PROTO_VERSION = 3 << 16 #196608
2121

22+
class AuthenticationMethodMismatch < StandardError
23+
end
24+
2225
class Connection
2326

2427
# Allow easy access to these instance variables
@@ -58,7 +61,10 @@ def initialize(database, user, password=nil, uri = nil)
5861
@transaction_status = nil
5962
@params = {}
6063
establish_connection(uri)
61-
64+
65+
# Check if the password supplied is a Postgres-style md5 hash
66+
md5_hash_match = password.match(/^md5([a-f0-9]{32})$/)
67+
6268
@conn << StartupMessage.new(PROTO_VERSION, 'user' => user, 'database' => database).dump
6369

6470
loop do
@@ -67,19 +73,24 @@ def initialize(database, user, password=nil, uri = nil)
6773
case msg
6874
when AuthentificationClearTextPassword
6975
raise ArgumentError, "no password specified" if password.nil?
76+
raise AuthenticationMethodMismatch, "Server expected clear text password auth" if md5_hash_match
7077
@conn << PasswordMessage.new(password).dump
71-
7278
when AuthentificationCryptPassword
7379
raise ArgumentError, "no password specified" if password.nil?
80+
raise AuthenticationMethodMismatch, "Server expected crypt password auth" if md5_hash_match
7481
@conn << PasswordMessage.new(password.crypt(msg.salt)).dump
75-
7682
when AuthentificationMD5Password
7783
raise ArgumentError, "no password specified" if password.nil?
7884
require 'digest/md5'
7985

80-
m = Digest::MD5.hexdigest(password + user)
86+
if md5_hash_match
87+
m = md5_hash_match[1]
88+
else
89+
m = Digest::MD5.hexdigest(password + user)
90+
end
8191
m = Digest::MD5.hexdigest(m + msg.salt)
8292
m = 'md5' + m
93+
8394
@conn << PasswordMessage.new(m).dump
8495

8596
when AuthentificationKerberosV4, AuthentificationKerberosV5, AuthentificationSCMCredential

metasploit-framework-db.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
2929

3030
spec.add_runtime_dependency 'activerecord', *Metasploit::Framework::RailsVersionConstraint::RAILS_VERSION
3131
# Metasploit::Credential database models
32-
spec.add_runtime_dependency 'metasploit-credential', '~> 0.14.0'
32+
spec.add_runtime_dependency 'metasploit-credential', '~> 0.14.2'
3333
# Database models shared between framework and Pro.
3434
spec.add_runtime_dependency 'metasploit_data_models', '~> 0.23.0'
3535
# depend on metasploit-framewrok as the optional gems are useless with the actual code

modules/auxiliary/analyze/jtr_postgres_fast.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,12 @@ def wordlist_file
108108

109109
def hash_file
110110
hashlist = Rex::Quickfile.new("hashes_tmp")
111-
Metasploit::Credential::NonreplayableHash.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }, jtr_format: 'raw-md5,postgres').each do |hash|
111+
Metasploit::Credential::PostgresMD5.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }).each do |hash|
112112
hash.cores.each do |core|
113113
user = core.public.username
114114
@username_set << user
115115
hash_string = "#{hash.data}"
116+
hash_string.gsub!(/^md5/, '')
116117
id = core.id
117118
hashlist.puts "#{user}:#{hash_string}:#{id}:"
118119
end

modules/auxiliary/scanner/postgres/postgres_hashdump.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def run_host(ip)
112112
origin_type: :service,
113113
jtr_format: 'raw-md5,postgres',
114114
module_fullname: self.fullname,
115-
private_type: :nonreplayable_hash
115+
private_type: :postgres_md5
116116
}
117117

118118
credential_data.merge!(service_data)
@@ -122,7 +122,6 @@ def run_host(ip)
122122
next if row[0].nil? or row[1].nil?
123123
next if row[0].empty? or row[1].empty?
124124
password = row[1]
125-
password.slice!(0,3)
126125

127126
credential_data[:username] = row[0]
128127
credential_data[:private_data] = password

0 commit comments

Comments
 (0)