Fixes #811 by implementing an enumerator for PostgreSQL.
git-svn-id: file:///home/svn/framework3/trunk@8371 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
@@ -27,7 +27,7 @@ module Exploit::Remote::Postgres
|
||||
Opt::RPORT(5432),
|
||||
OptString.new('DATABASE', [ true, 'The database to authenticate against', 'template1']),
|
||||
OptString.new('USERNAME', [ true, 'The username to authenticate as', 'postgres']),
|
||||
OptString.new('PASSWORD', [ true, 'The password for the specified username', '']),
|
||||
OptString.new('PASSWORD', [ false, 'The password for the specified username. Leave blank for a random password.', '']),
|
||||
OptBool.new('VERBOSE', [false, 'Enable verbose output', false]),
|
||||
OptString.new('SQL', [ false, 'The SQL query to execute', 'select version()']),
|
||||
OptBool.new('RETURN_ROWSET', [false, "Set to true to see query result sets", true])
|
||||
@@ -78,16 +78,19 @@ module Exploit::Remote::Postgres
|
||||
def postgres_logout
|
||||
ip = datastore['RHOST']
|
||||
port = datastore['RPORT']
|
||||
verbose = datastore['VERBOSE']
|
||||
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
|
||||
end
|
||||
print_status "#{ip}:#{port} Postgres - Disconnected" if datastore['VERBOSE']
|
||||
print_status "#{ip}:#{port} Postgres - Disconnected" if verbose
|
||||
end
|
||||
|
||||
# If not currently connected, postgres_query will attempt to connect. If an
|
||||
# error is encountered while executing the query, it will return with
|
||||
# :error ; otherwise, it will return with :complete.
|
||||
# TODO: move print_status up to the module; functions like this should just
|
||||
# return things like error codes and :status and the like.
|
||||
def postgres_query(sql=nil,doprint=false)
|
||||
ip = datastore['RHOST']
|
||||
port = datastore['RPORT']
|
||||
@@ -115,8 +118,8 @@ module Exploit::Remote::Postgres
|
||||
return :error
|
||||
end
|
||||
postgres_print_reply(resp,sql) if doprint
|
||||
print_good "#{ip}:#{port} Postgres - Command complete."
|
||||
return :complete
|
||||
print_good "#{ip}:#{port} Postgres - Command complete." if datastore['VERBOSE']
|
||||
return resp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -143,5 +146,80 @@ module Exploit::Remote::Postgres
|
||||
return :complete
|
||||
end
|
||||
|
||||
# postgres_fingerprint attempts to fingerprint a remote Postgresql instance,
|
||||
# inferring version number from the failed authentication messages.
|
||||
def postgres_fingerprint(args={})
|
||||
postgres_logout if self.postgres_conn
|
||||
db = args[:database] || datastore['DATABASE']
|
||||
username = args[:username] || datastore['USERNAME']
|
||||
password = args[:password] || datastore['PASSWORD']
|
||||
rhost = args[:server] || datastore['RHOST']
|
||||
rport = args[:port] || datastore['RPORT']
|
||||
uri = "tcp://#{rhost}:#{rport}"
|
||||
verbose = args[:verbose] || datastore['VERBOSE']
|
||||
begin
|
||||
self.postgres_conn = Connection.new(db,username,password,uri)
|
||||
rescue RuntimeError => e
|
||||
version_hash = analyze_auth_error e
|
||||
return version_hash
|
||||
end
|
||||
if self.postgres_conn # Just ask for the version.
|
||||
resp = postgres_query("select version()",false)
|
||||
ver = resp.rows[0][0].split(/\s/)[1]
|
||||
return {:auth => ver}
|
||||
end
|
||||
end
|
||||
|
||||
# Matches up filename, line number, and routine with a version.
|
||||
# These all come from source builds of Postgres. TODO: check
|
||||
# in on the binary distros, see if they're different.
|
||||
def analyze_auth_error(e)
|
||||
fname,fline,froutine = e.to_s.split("\t")[3,3]
|
||||
fingerprint = "#{fname}:#{fline}:#{froutine}"
|
||||
case fingerprint
|
||||
|
||||
when "Fauth.c:L395:Rauth_failed" ; return {:preauth => "7.4.26-27"} # Failed (bad db, bad credentials)
|
||||
when "Fpostinit.c:L264:RInitPostgres" ; return {:preauth => "7.4.26-27"} # Failed (bad db, good credentials)
|
||||
when "Fauth.c:L452:RClientAuthentication" ; return {:preauth => "7.4.26-27"} # Rejected (maybe good, but not allowed due to pg_hba.conf)
|
||||
|
||||
when "Fauth.c:L400:Rauth_failed" ; return {:preauth => "8.0.22-23"} # Failed (bad db, bad credentials)
|
||||
when "Fpostinit.c:L274:RInitPostgres" ; return {:preauth => "8.0.22-23"} # Failed (bad db, good credentials)
|
||||
when "Fauth.c:L457:RClientAuthentication" ; return {:preauth => "8.0.22-23"} # Rejected (maybe good)
|
||||
|
||||
when "Fauth.c:L337:Rauth_failed" ; return {:preauth => "8.1.18-19"} # Failed (bad db, bad credentials)
|
||||
when "Fpostinit.c:L354:RInitPostgres" ; return {:preauth => "8.1.18-19"} # Failed (bad db, good credentials)
|
||||
when "Fauth.c:L394:RClientAuthentication" ; return {:preauth => "8.1.18-19"} # Rejected (maybe good)
|
||||
|
||||
when "Fauth.c:L362:Rauth_failed" ; return {:preauth => "8.2.14-15"} # Failed (bad db, bad credentials)
|
||||
when "Fpostinit.c:L319:RInitPostgres" ; return {:preauth => "8.2.14-15"} # Failed (bad db, good credentials)
|
||||
when "Fauth.c:L419:RClientAuthentication" ; return {:preauth => "8.2.14-15"} # Rejected (maybe good)
|
||||
|
||||
when "Fauth.c:L1003:Rauth_failed" ; return {:preauth => "8.3.8"} # Failed (bad db, bad credentials)
|
||||
when "Fpostinit.c:L388:RInitPostgres" ; return {:preauth => "8.3.8-9"} # Failed (bad db, good credentials)
|
||||
when "Fauth.c:L1060:RClientAuthentication" ; return {:preauth => "8.3.8"} # Rejected (maybe good)
|
||||
|
||||
when "Fauth.c:L1017:Rauth_failed" ; return {:preauth => "8.3.9"} # Failed (bad db, bad credentials)
|
||||
when "Fauth.c:L1074:RClientAuthentication" ; return {:preauth => "8.3.9"} # Rejected (maybe good, but not allowed due to pg_hba.conf)
|
||||
|
||||
when "Fauth.c:L258:Rauth_failed" ; return {:preauth => "8.4.1"} # Failed (bad db, bad credentials)
|
||||
when "Fpostinit.c:L422:RInitPostgres" ; return {:preauth => "8.4.1-2"} # Failed (bad db, good credentials)
|
||||
when "Fauth.c:L349:RClientAuthentication" ; return {:preauth => "8.4.1"} # Rejected (maybe good)
|
||||
|
||||
when "Fauth.c:L273:Rauth_failed" ; return {:preauth => "8.4.2"} # Failed (bad db, bad credentials)
|
||||
when "Fauth.c:L364:RClientAuthentication" ; return {:preauth => "8.4.2"} # Rejected (maybe good)
|
||||
|
||||
else
|
||||
return {:unknown => fingerprint}
|
||||
end
|
||||
end
|
||||
|
||||
def postgres_password
|
||||
if datastore['PASSWORD'].to_s.size > 0
|
||||
datastore['PASSWORD'].to_s
|
||||
else
|
||||
Rex::Text.rand_text_english(rand(6)+2)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user