122 lines
5.0 KiB
Ruby
122 lines
5.0 KiB
Ruby
require 'postgres/postgres-pr/connection'
|
|
|
|
RSpec.describe Msf::Db::PostgresPR::Connection do
|
|
describe '#negotiate_sasl' do
|
|
subject { described_class.allocate }
|
|
let(:user) { 'postgres' }
|
|
let(:password) { 'mysecretpassword' }
|
|
let(:server_responses) { [] }
|
|
|
|
before(:each) do
|
|
allow(subject).to receive(:write_message)
|
|
read_message_mock = allow(Msf::Db::PostgresPR::Message).to receive(:read)
|
|
read_message_mock.and_return(*server_responses) if server_responses.any?
|
|
allow(SecureRandom).to receive(:bytes).with(32).and_return(("\x01" * 32).b)
|
|
end
|
|
|
|
context 'when the mechanism contains SCRAM-SHA-256' do
|
|
context 'and the negotiation is a success' do
|
|
let(:server_responses) do
|
|
[
|
|
# server-first, containing server nonce, salt, and iteration count
|
|
Msf::Db::PostgresPR::AuthenticationSASLContinue.new(
|
|
value: 'r=AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=FUeV3rVpQpa2s8ECj3aXa6vw,s=RwsYP2UCANr95SzCJfmP4A==,i=4096'
|
|
),
|
|
# server-final, server signature
|
|
Msf::Db::PostgresPR::AuthenticationSASLFinal.new(
|
|
value: 'v=V4CwoEsGBGMe2jGf5lpKbapnqiooWXnoyuHT3VDl6WY='
|
|
)
|
|
]
|
|
end
|
|
|
|
it 'negotaites successfully' do
|
|
message = Msf::Db::PostgresPR::AuthenticationSASL.new(
|
|
mechanisms: ['SCRAM-SHA-256']
|
|
)
|
|
subject.negotiate_sasl(message, user, password)
|
|
expect(subject).to have_received(:write_message).with(
|
|
Msf::Db::PostgresPR::SaslInitialResponseMessage.new(
|
|
mechanism: 'SCRAM-SHA-256',
|
|
value: 'n,,n=postgres,r=AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE='
|
|
)
|
|
).ordered
|
|
expect(subject).to have_received(:write_message).with(
|
|
Msf::Db::PostgresPR::SASLResponseMessage.new(
|
|
value: 'c=biws,r=AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=FUeV3rVpQpa2s8ECj3aXa6vw,p=MN8FiTy5Aqut/H/TOggmlOWXHmpI/+RrnNgQFBk1eBs='
|
|
)
|
|
).ordered
|
|
end
|
|
end
|
|
|
|
context 'and server-final does not contain the expected calculated server proof' do
|
|
let(:server_responses) do
|
|
[
|
|
# server-first, containing server nonce, salt, and iteration count
|
|
Msf::Db::PostgresPR::AuthenticationSASLContinue.new(
|
|
value: 'r=AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=FUeV3rVpQpa2s8ECj3aXa6vw,s=RwsYP2UCANr95SzCJfmP4A==,i=4096'
|
|
),
|
|
# server-final, server signature
|
|
Msf::Db::PostgresPR::AuthenticationSASLFinal.new(
|
|
value: 'v=invalid_server_proof'
|
|
)
|
|
]
|
|
end
|
|
|
|
it 'raises an error' do
|
|
message = Msf::Db::PostgresPR::AuthenticationSASL.new(
|
|
mechanisms: ['SCRAM-SHA-256']
|
|
)
|
|
expect { subject.negotiate_sasl(message, user, password) }.to raise_error 'Server proof failed'
|
|
end
|
|
end
|
|
|
|
context 'and the password is invalid' do
|
|
let(:server_responses) do
|
|
[
|
|
# server-first, containing server nonce, salt, and iteration count
|
|
Msf::Db::PostgresPR::AuthenticationSASLContinue.new(
|
|
value: 'r=2kRpTcHEFyoG+UgDEpRBdVcJLTWh5WtxARhYOHcG27i7YxAi,s=GNpgixWS5E4INbrMf665Kw==,i=4096'
|
|
),
|
|
# For auth failure; server-final isn't AuthenticationSASLFinal - but just a generic Postgres ErrorResponse
|
|
Msf::Db::PostgresPR::ErrorResponse.new(
|
|
83,
|
|
["FATAL", "VFATAL", "C28P01", "Mpassword authentication failed for user \"user\"", "Fauth.c", "L326", "Rauth_failed"]
|
|
)
|
|
]
|
|
end
|
|
|
|
it 'raises an error' do
|
|
message = Msf::Db::PostgresPR::AuthenticationSASL.new(
|
|
mechanisms: ['SCRAM-SHA-256']
|
|
)
|
|
# Runtime error raised for consistency with login scanner expectations, but could be changed to a better exception in the future
|
|
expect { subject.negotiate_sasl(message, user, password) }.to raise_error RuntimeError, "FATAL\tVFATAL\tC28P01\tMpassword authentication failed for user \"user\"\tFauth.c\tL326\tRauth_failed"
|
|
end
|
|
end
|
|
|
|
context 'and a AuthenticationSASLContinue is not returned' do
|
|
let(:server_responses) do
|
|
[
|
|
nil
|
|
]
|
|
end
|
|
it 'raises' do
|
|
message = Msf::Db::PostgresPR::AuthenticationSASL.new(
|
|
mechanisms: ['SCRAM-SHA-256']
|
|
)
|
|
expect { subject.negotiate_sasl(message, user, password) }.to raise_error Msf::Db::PostgresPR::AuthenticationMethodMismatch, /Did not receive AuthenticationSASLContinue/
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when the mechanism is not supported' do
|
|
it 'raises an exception' do
|
|
message = Msf::Db::PostgresPR::AuthenticationSASL.new(
|
|
mechanisms: ['SCRAM-SHA-256-PLUS']
|
|
)
|
|
expect { subject.negotiate_sasl(message, user, password) }.to raise_error Msf::Db::PostgresPR::AuthenticationMethodMismatch, /unsupported SASL mechanisms/
|
|
end
|
|
end
|
|
end
|
|
end
|