Skip to content

Commit

Permalink
Land #4871, Postgres PTH support
Browse files Browse the repository at this point in the history
MSP-12244
  • Loading branch information
wvu committed Mar 4, 2015
2 parents 1676d98 + 8d6ba0e commit a64dd4a
Show file tree
Hide file tree
Showing 9 changed files with 33 additions and 13 deletions.
8 changes: 4 additions & 4 deletions Gemfile.lock
Expand Up @@ -22,7 +22,7 @@ PATH
tzinfo
metasploit-framework-db (4.11.0.pre.dev)
activerecord (>= 3.2.21, < 4.0.0)
metasploit-credential (~> 0.14.0)
metasploit-credential (~> 0.14.2)
metasploit-framework (= 4.11.0.pre.dev)
metasploit_data_models (~> 0.23.0)
pg (>= 0.11)
Expand Down Expand Up @@ -112,7 +112,7 @@ GEM
metasploit-concern (0.3.0)
activesupport (~> 3.0, >= 3.0.0)
railties (< 4.0.0)
metasploit-credential (0.14.0)
metasploit-credential (0.14.2)
metasploit-concern (~> 0.3.0)
metasploit-model (~> 0.29.0)
metasploit_data_models (~> 0.23.0)
Expand All @@ -123,7 +123,7 @@ GEM
metasploit-model (0.29.0)
activesupport
railties (< 4.0.0)
metasploit_data_models (0.23.0)
metasploit_data_models (0.23.1)
activerecord (>= 3.2.13, < 4.0.0)
activesupport
arel-helpers
Expand Down Expand Up @@ -199,7 +199,7 @@ GEM
rspec-core (~> 2.99.0)
rspec-expectations (~> 2.99.0)
rspec-mocks (~> 2.99.0)
rubyntlm (0.4.0)
rubyntlm (0.5.0)
rubyzip (1.1.7)
shoulda-matchers (2.6.2)
simplecov (0.5.4)
Expand Down
2 changes: 2 additions & 0 deletions db/schema.rb
Expand Up @@ -393,9 +393,11 @@
t.boolean "critical"
t.boolean "seen"
t.text "data"
t.integer "vuln_id"
end

add_index "notes", ["ntype"], :name => "index_notes_on_ntype"
add_index "notes", ["vuln_id"], :name => "index_notes_on_vuln_id"

create_table "profiles", :force => true do |t|
t.datetime "created_at", :null => false
Expand Down
2 changes: 1 addition & 1 deletion lib/metasploit/framework/credential.rb
Expand Up @@ -51,7 +51,7 @@ class Credential
# These values should be #demodularized from subclasses of
# `Metasploit::Credential::Private`
validates :private_type,
inclusion: { in: [ :password, :ntlm_hash, :ssh_key ] },
inclusion: { in: [ :password, :ntlm_hash, :postgres_md5, :ssh_key ] },
if: "private_type.present?"

# If we have no private we MUST have a public
Expand Down
2 changes: 2 additions & 0 deletions lib/metasploit/framework/credential_collection.rb
Expand Up @@ -210,6 +210,8 @@ def each
def private_type(private)
if private =~ /[0-9a-f]{32}:[0-9a-f]{32}/
:ntlm_hash
elsif private =~ /^md5([a-f0-9]{32})$/
:postgres_md5
else
:password
end
Expand Down
5 changes: 5 additions & 0 deletions lib/metasploit/framework/login_scanner/postgres.rb
Expand Up @@ -62,6 +62,11 @@ def attempt_login(credential)
end
rescue Rex::ConnectionError, EOFError, Timeout::Error => e
result_options.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
rescue Msf::Db::PostgresPR::AuthenticationMethodMismatch => e
result_options.merge!({
status: Metasploit::Model::Login::Status::INCORRECT,
proof: e.message
})
end

if pg_conn
Expand Down
19 changes: 15 additions & 4 deletions lib/postgres/postgres-pr/connection.rb
Expand Up @@ -19,6 +19,9 @@ module PostgresPR

PROTO_VERSION = 3 << 16 #196608

class AuthenticationMethodMismatch < StandardError
end

class Connection

# Allow easy access to these instance variables
Expand Down Expand Up @@ -58,7 +61,10 @@ def initialize(database, user, password=nil, uri = nil)
@transaction_status = nil
@params = {}
establish_connection(uri)


# Check if the password supplied is a Postgres-style md5 hash
md5_hash_match = password.match(/^md5([a-f0-9]{32})$/)

@conn << StartupMessage.new(PROTO_VERSION, 'user' => user, 'database' => database).dump

loop do
Expand All @@ -67,19 +73,24 @@ def initialize(database, user, password=nil, uri = nil)
case msg
when AuthentificationClearTextPassword
raise ArgumentError, "no password specified" if password.nil?
raise AuthenticationMethodMismatch, "Server expected clear text password auth" if md5_hash_match
@conn << PasswordMessage.new(password).dump

when AuthentificationCryptPassword
raise ArgumentError, "no password specified" if password.nil?
raise AuthenticationMethodMismatch, "Server expected crypt password auth" if md5_hash_match
@conn << PasswordMessage.new(password.crypt(msg.salt)).dump

when AuthentificationMD5Password
raise ArgumentError, "no password specified" if password.nil?
require 'digest/md5'

m = Digest::MD5.hexdigest(password + user)
if md5_hash_match
m = md5_hash_match[1]
else
m = Digest::MD5.hexdigest(password + user)
end
m = Digest::MD5.hexdigest(m + msg.salt)
m = 'md5' + m

@conn << PasswordMessage.new(m).dump

when AuthentificationKerberosV4, AuthentificationKerberosV5, AuthentificationSCMCredential
Expand Down
2 changes: 1 addition & 1 deletion metasploit-framework-db.gemspec
Expand Up @@ -29,7 +29,7 @@ Gem::Specification.new do |spec|

spec.add_runtime_dependency 'activerecord', *Metasploit::Framework::RailsVersionConstraint::RAILS_VERSION
# Metasploit::Credential database models
spec.add_runtime_dependency 'metasploit-credential', '~> 0.14.0'
spec.add_runtime_dependency 'metasploit-credential', '~> 0.14.2'
# Database models shared between framework and Pro.
spec.add_runtime_dependency 'metasploit_data_models', '~> 0.23.0'
# depend on metasploit-framewrok as the optional gems are useless with the actual code
Expand Down
3 changes: 2 additions & 1 deletion modules/auxiliary/analyze/jtr_postgres_fast.rb
Expand Up @@ -108,11 +108,12 @@ def wordlist_file

def hash_file
hashlist = Rex::Quickfile.new("hashes_tmp")
Metasploit::Credential::NonreplayableHash.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }, jtr_format: 'raw-md5,postgres').each do |hash|
Metasploit::Credential::PostgresMD5.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }).each do |hash|
hash.cores.each do |core|
user = core.public.username
@username_set << user
hash_string = "#{hash.data}"
hash_string.gsub!(/^md5/, '')
id = core.id
hashlist.puts "#{user}:#{hash_string}:#{id}:"
end
Expand Down
3 changes: 1 addition & 2 deletions modules/auxiliary/scanner/postgres/postgres_hashdump.rb
Expand Up @@ -112,7 +112,7 @@ def run_host(ip)
origin_type: :service,
jtr_format: 'raw-md5,postgres',
module_fullname: self.fullname,
private_type: :nonreplayable_hash
private_type: :postgres_md5
}

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

credential_data[:username] = row[0]
credential_data[:private_data] = password
Expand Down

0 comments on commit a64dd4a

Please sign in to comment.