Skip to content

Commit

Permalink
Land #19080, Add arch/platform detection for Postgres
Browse files Browse the repository at this point in the history
  • Loading branch information
adfoster-r7 authored Apr 19, 2024
2 parents 92592f9 + b83f2e3 commit cff9339
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 7 deletions.
2 changes: 2 additions & 0 deletions lib/msf/base/sessions/postgresql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class Msf::Sessions::PostgreSQL < Msf::Sessions::Sql
# @param opts [Msf::Db::PostgresPR::Connection] :client
def initialize(rstream, opts = {})
@client = opts.fetch(:client)
self.platform = opts.fetch(:platform)
self.arch = opts.fetch(:arch)
@console = ::Rex::Post::PostgreSQL::Ui::Console.new(self)
super(rstream, opts)
end
Expand Down
92 changes: 90 additions & 2 deletions lib/postgres/postgres-pr/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,100 @@ def peerport
@conn.peerport
end

def peerinfo
"#{peerhost}:#{peerport}"
end

def current_database
@params['database']
end

def peerinfo
"#{peerhost}:#{peerport}"
# List of supported PostgreSQL platforms & architectures:
# https://postgrespro.com/docs/postgresql/16/supported-platforms
def map_compile_os_to_platform(compile_os)
return Msf::Platform::Unknown.realname if compile_os.blank?

compile_os = compile_os.downcase.encode(::Encoding::BINARY)

if compile_os.match?('linux')
platform = Msf::Platform::Linux
elsif compile_os.match?(/(darwin|mac|osx)/)
platform = Msf::Platform::OSX
elsif compile_os.match?('win')
platform = Msf::Platform::Windows
elsif compile_os.match?('free')
platform = Msf::Platform::FreeBSD
elsif compile_os.match?('net')
platform = Msf::Platform::NetBSD
elsif compile_os.match?('open')
platform = Msf::Platform::OpenBSD
elsif compile_os.match?('solaris')
platform = Msf::Platform::Solaris
elsif compile_os.match?('aix')
platform = Msf::Platform::AIX
elsif compile_os.match?('hpux')
platform = Msf::Platform::HPUX
elsif compile_os.match?('irix')
platform = Msf::Platform::Irix
else
# Return the query result if the value can't be mapped
return compile_os
end

platform.realname
end

# List of supported PostgreSQL platforms & architectures:
# https://postgrespro.com/docs/postgresql/16/supported-platforms
def map_compile_arch_to_architecture(compile_arch)
return '' if compile_arch.blank?

compile_arch = compile_arch.downcase.encode(::Encoding::BINARY)

if compile_arch.match?('sparc')
if compile_arch.include?('64')
arch = ARCH_SPARC64
else
arch = ARCH_SPARC
end
elsif compile_arch.include?('mips')
arch = ARCH_MIPS
elsif compile_arch.include?('ppc')
arch = ARCH_PPC
elsif compile_arch.match?('arm')
if compile_arch.match?('64')
arch = ARCH_AARCH64
elsif compile_arch.match?('arm')
arch = ARCH_ARMLE
end
elsif compile_arch.match?('64')
arch = ARCH_X86_64
elsif compile_arch.match?('86') || compile_arch.match?('i686')
arch = ARCH_X86
else
# Return the query result if the value can't be mapped
arch = compile_arch
end

arch
end

# @return [Hash] Detect the platform and architecture of the PostgreSQL server:
# * :arch [String] The server architecture.
# * :platform [String] The server platform.
def detect_platform_and_arch
result = {}

query_result = query('select version()').rows.join.match(/on (?<architecture>\w+)-\w+-(?<platform>\w+)/)
server_vars = {
'version_compile_machine' => query_result[:architecture],
'version_compile_os' => query_result[:platform]
}

result[:arch] = map_compile_arch_to_architecture(server_vars['version_compile_machine'])
result[:platform] = map_compile_os_to_platform(server_vars['version_compile_os'])

result
end

def close
Expand Down
6 changes: 5 additions & 1 deletion lib/rex/proto/mysql/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ def map_compile_arch_to_architecture(compile_arch)
arch = ARCH_SPARC
end
elsif compile_arch.match?('arm')
arch = ARCH_AARCH64
if compile_arch.match?('64')
arch = ARCH_AARCH64
elsif compile_arch.match?('arm')
arch = ARCH_ARMLE
end
elsif compile_arch.match?('64')
arch = ARCH_X86_64
elsif compile_arch.match?('86') || compile_arch.match?('i686')
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/scanner/postgres/postgres_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def rport
def session_setup(result)
return unless (result.connection && result.proof)

my_session = Msf::Sessions::PostgreSQL.new(result.connection, { client: result.proof })
my_session = Msf::Sessions::PostgreSQL.new(result.connection, { client: result.proof, **result.proof.detect_platform_and_arch })
merge_me = {
'USERPASS_FILE' => nil,
'USER_FILE' => nil,
Expand Down
2 changes: 1 addition & 1 deletion spec/lib/msf/base/sessions/postgresql_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

RSpec.describe Msf::Sessions::PostgreSQL do
let(:client) { instance_double(Msf::Db::PostgresPR::Connection) }
let(:opts) { { client: client } }
let(:opts) { { client: client, platform: Msf::Platform::Linux.realname, arch: ARCH_X86_64 } }
let(:console_class) { Rex::Post::PostgreSQL::Ui::Console }
let(:user_input) { instance_double(Rex::Ui::Text::Input::Readline) }
let(:user_output) { instance_double(Rex::Ui::Text::Output::Stdio) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
let(:port) { '5432' }
let(:current_database) { 'template1' }
let(:peer_info) { "#{address}:#{port}" }
let(:session) { Msf::Sessions::PostgreSQL.new(nil, { client: client }) }
let(:session) { Msf::Sessions::PostgreSQL.new(nil, { client: client, platform: Msf::Platform::Linux.realname, arch: ARCH_X86_64 }) }
let(:console) do
console = Rex::Post::PostgreSQL::Ui::Console.new(session)
console.disable_output = true
Expand Down
2 changes: 1 addition & 1 deletion spec/lib/rex/proto/mysql/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
{ info: '86', expected: ARCH_X86 },
{ info: 'i686', expected: ARCH_X86 },
{ info: 'arm64', expected: ARCH_AARCH64 },
{ info: 'arm', expected: ARCH_AARCH64 },
{ info: 'arm', expected: ARCH_ARMLE },
{ info: 'sparc', expected: ARCH_SPARC },
{ info: 'sparc64', expected: ARCH_SPARC64 },
{ info: '', expected: '' },
Expand Down
60 changes: 60 additions & 0 deletions spec/lib/rex/proto/postgresql/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,64 @@
end

it_behaves_like 'session compatible SQL client'

describe '#map_compile_os_to_platform' do
[
{ info: 'linux', expected: Msf::Platform::Linux.realname },
{ info: 'linux2.6', expected: Msf::Platform::Linux.realname },
{ info: 'debian-linux-gnu', expected: Msf::Platform::Linux.realname },
{ info: 'win', expected: Msf::Platform::Windows.realname },
{ info: 'windows', expected: Msf::Platform::Windows.realname },
{ info: 'darwin', expected: Msf::Platform::OSX.realname },
{ info: 'osx', expected: Msf::Platform::OSX.realname },
{ info: 'macos', expected: Msf::Platform::OSX.realname },
{ info: 'solaris', expected: Msf::Platform::Solaris.realname },
{ info: 'aix', expected: Msf::Platform::AIX.realname },
{ info: 'hpux', expected: Msf::Platform::HPUX.realname },
{ info: 'irix', expected: Msf::Platform::Irix.realname },
].each do |test|
it "correctly identifies '#{test[:info]}' as '#{test[:expected]}'" do
expect(subject.map_compile_os_to_platform(test[:info])).to eq(test[:expected])
end
end
end

describe '#map_compile_arch_to_architecture' do
[
{ info: 'x86_64', expected: ARCH_X86_64 },
{ info: 'x86_x64', expected: ARCH_X86_64 },
{ info: 'x64', expected: ARCH_X86_64 },
{ info: '64', expected: ARCH_X86_64 },
{ info: 'x86', expected: ARCH_X86 },
{ info: '86', expected: ARCH_X86 },
{ info: 'i686', expected: ARCH_X86 },
{ info: 'arm64', expected: ARCH_AARCH64 },
{ info: 'arm', expected: ARCH_ARMLE },
{ info: 'sparc', expected: ARCH_SPARC },
{ info: 'sparc64', expected: ARCH_SPARC64 },
{ info: 'ppc', expected: ARCH_PPC },
{ info: 'mips', expected: ARCH_MIPS },
].each do |test|
it "correctly identifies '#{test[:info]}' as '#{test[:expected]}'" do
expect(subject.map_compile_arch_to_architecture(test[:info])).to eq(test[:expected])
end
end
end

describe '#detect_platform_and_arch' do
[
{ version: 'PostgreSQL 9.4.26 on x86_64-pc-linux-gnu (Debian 9.4.26-1.pgdg90+1), compiled by gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516, 64-bit', expected: { arch: 'x86_64', platform: 'Linux' } },
{ version: 'PostgreSQL 14.11 (Debian 14.11-1.pgdg120+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit', expected: { arch: 'x86_64', platform: 'Linux' } },
{ version: 'PostgreSQL 14.11 (Homebrew) on x86_64-apple-darwin22.6.0, compiled by Apple clang version 15.0.0 (clang-1500.1.0.2.5), 64-bit', expected: { arch: 'x86_64', platform: 'OSX' } }
].each do |test|
context "when the database is version #{test[:version]}" do
it "returns #{test[:expected]}" do
mock_query_result = instance_double Msf::Db::PostgresPR::Connection::Result, rows: [[test[:version]]]
allow(subject).to receive(:query).with('select version()').and_return(mock_query_result)

expect(subject.detect_platform_and_arch).to eq test[:expected]
end
end
end
end
end

0 comments on commit cff9339

Please sign in to comment.