Share
## https://sploitus.com/exploit?id=PACKETSTORM:180938
##  
# 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