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:
Tod Beardsley
2010-02-05 15:20:59 +00:00
parent aeba7e0429
commit c8cdf9c938
2 changed files with 219 additions and 4 deletions
+82 -4
View File
@@ -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