Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add arch/platform detection for Postgres #19080

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taken from https://postgrespro.com/docs/postgresql/16/supported-platforms

I have bucket these by what I have covered versus not. Wanted to call this out in case anyone has thoughts or opinions.

Historical versions. Not covered and not present in lib/msf/core/module/platform.rb:

  • 4.3BSD
  • BEOS
  • BSD/OS
  • DG/UX
  • Dynix
  • NeXTSTEP
  • QNX
  • SCO
  • SINIX
  • Sprite
  • SunOS
  • Tru64 UNIX
  • ULTRIX

Historical versions. Covered and present in lib/msf/core/module/platform.rb:

  • HP-UX
  • IRIX

17.6 supported but not covered in lib/msf/core/module/platform.rb:

  • DragonFlyBSD
  • illumos

17.6 supported and covered in lib/msf/core/module/platform.rb:

  • Linux
  • Windows
  • Solaris
  • macOS
  • FreeBSD
  • OpenBSD
  • NetBSD
  • AIX

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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this to return whatever the query result is, evening if we don't mp it, I think it would be more useful to give the user the data instead of just Msf::Platform::Unknown returning unknown.

Maybe we need to return unknown here, happy to change it if needed 👍

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)
Copy link
Contributor Author

@cgranleese-r7 cgranleese-r7 Apr 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taken from https://postgrespro.com/docs/postgresql/16/supported-platforms

I have bucket these by what I have covered versus not. Wanted to call this out in case anyone has thoughts or opinions.

Historical versions. Not covered and not present in rex/arch.rb:

  • Alpha
  • Itanium
  • M32R
  • M68K
  • M88K
  • NS32K
  • SuperH
  • VAX

17.6 supported but not covered in rex/arch.rb:

  • S/390
  • RISC-V
  • PA-RISC

17.6 supported and covered in rex/arch.rb:

  • x86
  • SPARC
  • ARM
  • MIPS
  • PowerPC

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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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'

cgranleese-r7 marked this conversation as resolved.
Show resolved Hide resolved
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