Skip to content

Commit

Permalink
Land #98, 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 09eaae1 + f377437 commit 3bd4b4e
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 1 deletion.
41 changes: 41 additions & 0 deletions app/models/metasploit/credential/postgres_md5.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# A {Metasploit::Credential::PasswordHash password hash} that can be {Metasploit::Credential::ReplayableHash replayed}
# to authenticate to PostgreSQL servers. It is composed of a hexadecimal string of 32 charachters prepended by the string
# 'md5'
class Metasploit::Credential::PostgresMD5 < Metasploit::Credential::ReplayableHash

DATA_REGEXP = /md5([a-f0-9]{32})/

#
# Callbacks
#

before_validation :normalize_data

#
# Validations
#

validate :data_format

private

# Normalizes {#data} by making it all lowercase so that the unique validation and index on
# ({Metasploit::Credential::Private#type}, {#data}) catches collision in a case-insensitive manner without the need
# to use case-insensitive comparisons.
def normalize_data
if data
self.data = data.downcase
end
end

def data_format
unless DATA_REGEXP.match(data)
errors.add(:data, 'is not in Postgres MD5 Hash format')
end
end

public

Metasploit::Concern.run(self)

end
3 changes: 3 additions & 0 deletions lib/metasploit/credential/creation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ def create_credential_private(opts={})
when :ntlm_hash
private_object = Metasploit::Credential::NTLMHash.where(data: private_data).first_or_create
private_object.jtr_format = 'nt,lm'
when :postgres_md5
private_object = Metasploit::Credential::PostgresMD5.where(data: private_data).first_or_create
private_object.jtr_format = 'raw-md5,postgres'
when :nonreplayable_hash
private_object = Metasploit::Credential::NonreplayableHash.where(data: private_data).first_or_create
if opts[:jtr_format].present?
Expand Down
2 changes: 1 addition & 1 deletion lib/metasploit/credential/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Version
# The minor version number, scoped to the {MAJOR} version number.
MINOR = 14
# The patch number, scoped to the {MINOR} version number.
PATCH = 0
PATCH = 1

# The full version string, including the {MAJOR}, {MINOR}, {PATCH}, and optionally, the {PRERELEASE} in the
# {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0} format.
Expand Down
11 changes: 11 additions & 0 deletions spec/factories/metasploit/credential/postgres_md5.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FactoryGirl.define do
klass = Metasploit::Credential::PostgresMD5

factory :metasploit_credential_postgres_md5,
class: klass,
parent: :metasploit_credential_replayable_hash do
data {
"md5#{SecureRandom.hex(16)}"
}
end
end
124 changes: 124 additions & 0 deletions spec/models/metasploit/credential/postgres_md5_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
require 'spec_helper'

describe Metasploit::Credential::PostgresMD5 do
it_should_behave_like 'Metasploit::Concern.run'

it { should be_a Metasploit::Credential::ReplayableHash }

context 'CONSTANTS' do
context 'DATA_REGEXP' do
subject(:data_regexp) do
described_class::DATA_REGEXP
end

it 'is valid if the string is md5 and 32 hex chars' do
hash = "md5#{SecureRandom.hex(16)}"
expect(data_regexp).to match(hash)
end

it 'is not valid if it does not start with md5' do
expect(data_regexp).not_to match(SecureRandom.hex(16))
end

it 'is not valid for an invalid length' do
expect(data_regexp).not_to match(SecureRandom.hex(6))
end

it 'is not valid if it is not hex chars after the md5 tag' do
bogus = "md5#{SecureRandom.hex(15)}jk"
expect(data_regexp).not_to match(bogus)
end

end
end

context 'callbacks' do
context 'before_validation' do
context '#data' do
subject(:data) do
postgres_md5.data
end

let(:postgres_md5) do
FactoryGirl.build(
:metasploit_credential_postgres_md5,
data: given_data
)
end

before(:each) do
postgres_md5.valid?
end

context 'with nil' do
let(:given_data) do
nil
end

it { should be_nil }
end

context 'with upper case characters' do
let(:given_data) do
'ABCDEF1234567890'
end

it 'makes them lower case' do
expect(data).to eq(given_data.downcase)
end
end

context 'with all lower case characters' do
let(:given_data) do
'abcdef1234567890'
end

it 'does not change the case' do
expect(data).to eq(given_data)
end
end
end
end
end

context 'factories' do
context 'metasploit_credential_ntlm_hash' do
subject(:metasploit_credential_postgres_md5) do
FactoryGirl.build(:metasploit_credential_postgres_md5)
end

it { should be_valid }
end
end

context 'validations' do
context '#data_format' do
subject(:data_errors) do
postgres_md5.errors[:data]
end

let(:data) { "md5#{SecureRandom.hex(16)}" }

let(:postgres_md5) do
FactoryGirl.build(
:metasploit_credential_postgres_md5,
data: data
)
end

context 'with a valid postgres md5 hash' do
it 'should be valid' do
expect(postgres_md5).to be_valid
end
end

context 'with an invalid postgres md5 hash' do
let(:data) { "invalidstring" }
it 'should not be valid' do
expect(postgres_md5).to_not be_valid
end
end
end
end

end

0 comments on commit 3bd4b4e

Please sign in to comment.