metasploit-framework/lib/msf/core/exploit/oracle.rb

180 lines
4.9 KiB
Ruby

# -*- coding: binary -*-
###
#
# This module provides methods for communicating with a host running oracle.
# Dependencies:
# - Oracle Instant Client
# - ruby-oci8
#
# Rory McCune <rorym@nmrconsult.net>
# MC <mc@metasploit.com>
#
###
module Msf
module Exploit::ORACLE
def initialize(info = {})
super
register_options(
[
OptString.new('RHOST', [ true, 'The Oracle host.', '']),
OptPort.new('RPORT', [ true, 'The TNS port.', 1521]),
OptString.new('SID', [ true, 'The sid to authenticate with.', 'ORCL']),
OptString.new('DBUSER', [ true, 'The username to authenticate with.', 'SCOTT']),
OptString.new('DBPASS', [ true, 'The password to authenticate with.', 'TIGER']),
], Msf::Exploit::ORACLE
)
begin
olang = ENV['NLS_LANG']
ENV['NLS_LANG'] = 'AMERICAN_AMERICA.WE8ISO8859P1'
require 'oci8'
ENV['NLS_LANG'] = olang
@oci8_loaded = true
rescue ::Exception => e
@oci8_loaded = false
@oci8_error = e
end
end
def check_dependencies
if not @oci8_loaded
print_error("Failed to load the OCI library: #{@oci8_error}")
print_error("Try 'gem install ruby-oci8'")
return false
end
return true
end
def connect
handle = nil
if(not @oci8_loaded)
raise RuntimeError, "Could not load the Oracle driver (oci8): #{@oci8_error}"
end
# Create a Connection to the Database
if datastore['DBUSER'] == 'SYS' || datastore['DBUSER'] == 'SYSTEM'
begin
handle = OCI8.new(
datastore['DBUSER'],
datastore['DBPASS'],
"//#{datastore['RHOST']}:#{datastore['RPORT']}/#{datastore['SID']}",
:SYSDBA
)
rescue ::OCIError
# Try again without a request for SYSDBA
vprint_status('Insufficient privileges, trying without SYSDBA')
handle = OCI8.new(
datastore['DBUSER'],
datastore['DBPASS'],
"//#{datastore['RHOST']}:#{datastore['RPORT']}/#{datastore['SID']}"
)
end
else
handle = OCI8.new(
datastore['DBUSER'],
datastore['DBPASS'],
"//#{datastore['RHOST']}:#{datastore['RPORT']}/#{datastore['SID']}"
)
end
handle
end
def disconnect
connect.logoff
end
def prepare_exec(sql)
begin
sploit = connect.parse(sql)
rescue ::OCIError => e
print_error("#{e.to_s}")
return
end
# DEBUG
# print_status("did the parse sploit type is " + sploit.type.to_s)
begin
sploit.exec
rescue ::OCIError => e
if ( e.to_s =~ /ORA-00942: table or view does not exist/ )
print_status("ORA-00942: table or view does not exist")
raise RuntimeError, "ORA-00942: table or view does not exist"
end
print_status e.to_s
end
# The Handling is a little different for certain types of query
# Mainly Select needs a fetch statement to get the data
# Also return types are a little different (some return rows changed so we can used that)
# The case statement could probably be collapsed a bit but leaving it as is for the moment
# in case it's useful later...
# Select Queries
case sploit.type
when 1, :select_stmt
# Create an array to return to the calling function
results = Array.new
while r = sploit.fetch()
str = r.join(',')
# Removed this as it should really be down to the exploit to decide what to print
# eg leaving this in messes up oraenum.
# print_status(str)
results << str
end
return results
# Update Queries
when 2, :update_stmt
connect.commit
# If we were successful our return should be a Integer with the number of rows updated
result = ['UPDATE Successful ' + sploit.row_count.to_s + ' Rows Updated']
return result
# Delete Queries
when 3, :delete_stmt
connect.commit
# If we were successful our return should be a Integer with the number of rows updated
result = ['DELETE Successful ' + sploit.row_count.to_s + ' Rows Deleted']
return result
# Insert Queries
when 4, :insert_stmt
connect.commit
# If we were successful our return should be a Integer with the number of rows updated
result = ['INSERT Successful ' + sploit.row_count.to_s + ' Rows Inserted']
return result
# Create Queries
when 5, :create_stmt
connect.commit
if sploit
print_status('CREATE successful')
end
when 6, :drop_stmt
connect.commit
if sploit
print_status('DROP successful')
end
when 7, :alter_stmt
connect.commit
if sploit
print_status('Alter successful')
end
when 8, :begin_stmt
connect.commit
when 9, :declare_stmt
connect.commit
else
print_status("Didn't match Query Type!")
print_status("Query type passed was " + sploit.type.to_s)
end
end
end
end