d3050de862
See #4400. This should be all of them, except for, of course, the module that targets Redmine itself. Note that this also updates the README.md with more current information as well.
169 lines
4.6 KiB
Ruby
169 lines
4.6 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>
|
|
#
|
|
###
|
|
|
|
require 'msf/core'
|
|
|
|
module Msf
|
|
module Exploit::ORACLE
|
|
|
|
|
|
def initialize(info = {})
|
|
super
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('RHOST', [ true, 'The Oracle host.', '']),
|
|
OptString.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
|
|
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'
|
|
handle = OCI8.new(
|
|
datastore['DBUSER'],
|
|
datastore['DBPASS'],
|
|
"//#{datastore['RHOST']}:#{datastore['RPORT']}/#{datastore['SID']}",
|
|
:SYSDBA
|
|
)
|
|
else
|
|
handle = OCI8.new(
|
|
datastore['DBUSER'],
|
|
datastore['DBPASS'],
|
|
"//#{datastore['RHOST']}:#{datastore['RPORT']}/#{datastore['SID']}"
|
|
)
|
|
end
|
|
|
|
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 probaby 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 Fixnum 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 Fixnum 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 Fixnum 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
|
|
|