Skip to content

Commit

Permalink
Test passing
Browse files Browse the repository at this point in the history
  • Loading branch information
cgranleese-r7 committed Jan 19, 2024
1 parent 381de83 commit 6fee35c
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 29 deletions.
9 changes: 4 additions & 5 deletions lib/msf/base/sessions/mysql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,17 @@ class Msf::Sessions::MYSQL

# @param[Rex::IO::Stream] rstream
# @param [Hash] opts
# @param opts [MySQL::Client] :client
def initialize(rstream, opts = {})
@client = opts.fetch(:client)
@console = ::Rex::Post::MySQL::Ui::Console.new(self)
self.console = ::Rex::Post::MySQL::Ui::Console.new(self)
super(rstream, opts)
end

def bootstrap(datastore = {}, handler = nil)
session = self
session.init_ui(user_input, user_output)

@info = "MySQL #{datastore['USERNAME']} @ #{@peer_info}"
@info = "MySQL #{datastore['USERNAME']} @ #{client.socket.peerinfo}"
end

def process_autoruns(datastore)
Expand Down Expand Up @@ -69,15 +68,15 @@ def desc
def address
return @address if @address

@address, @port = @client.conn.peerinfo.split(':')
@address, @port = @client.socket.peerinfo.split(':')
@address
end

# @return [Object] The peer host
def port
return @port if @port

@address, @port = @client.conn.peerinfo.split(':')
@address, @port = @client.socket.peerinfo.split(':')
@port
end

Expand Down
6 changes: 3 additions & 3 deletions lib/rex/post/mysql/ui/console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def initialize(session)
self.session = session
self.client = session.client
self.cwd = client.database
prompt = "%undMySQL @ #{client.host}:#{client.port} (#{cwd})%clr"
prompt = "%undMySQL @ #{client.socket.peerinfo} (#{cwd})%clr"
history_manager = Msf::Config.mysql_session_history
super(prompt, '>', history_manager, nil, :mysql)

Expand Down Expand Up @@ -129,8 +129,8 @@ def log_error(msg)
# @param [Object] val
# @return [String]
def format_prompt(val)
cwd ||= client.database
prompt = "%undMySQL @ #{client.host}:#{client.port} (#{cwd})%clr > "
@cwd ||= client.database
prompt = "%undMySQL @ #{client.socket.peerinfo} (#{@cwd})%clr > "
substitute_colors(prompt, true)
end

Expand Down
6 changes: 5 additions & 1 deletion lib/rex/post/mysql/ui/console/command_dispatcher/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,13 @@ def cmd_shell(*args)
def cmd_query_help
print_line 'Usage: query'
print_line
print_line 'You can also use `sql`.'
print_line 'Run a raw SQL query on the target.'
print_line 'Examples:'
print_line
print_line ' query SHOW DATABASES;'
print_line ' query USE information_schema;'
print_line ' query SELECT * FROM SQL_FUNCTIONS;'
print_line ' query SELECT version();'
end

# @param [Array] result The result of an SQL query to format.
Expand Down
95 changes: 95 additions & 0 deletions lib/rex/post/mysql/ui/console/command_dispatcher/modules.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# -*- coding: binary -*-

require 'pathname'

module Rex
module Post
module MySQL
module Ui
###
#
# MySQL client commands for running modules
#
###
class Console::CommandDispatcher::Modules

include Rex::Post::MySQL::Ui::Console::CommandDispatcher


#
# List of supported commands.
#
def commands
cmds = {
'run' => 'Run a module'
}

reqs = {}

filter_commands(cmds, reqs)
end

#
# Modules
#
def name
'Modules'
end

def cmd_run_help
print_line 'Usage: Modules'
print_line
print_line 'Run a module.'
print_line
end

#
# Executes a module/script in the context of the MySQL session.
#
def cmd_run(*args)
if args.empty? || args.first == '-h' || args.first == '--help'
cmd_run_help
return true
end

# Get the script name
begin
script_name = args.shift
# First try it as a module if we have access to the Metasploit
# Framework instance. If we don't, or if no such module exists,
# fall back to using the scripting interface.
if msf_loaded? && (mod = session.framework.modules.create(script_name))
original_mod = mod
reloaded_mod = session.framework.modules.reload_module(original_mod)

unless reloaded_mod
error = session.framework.modules.module_load_error_by_path[original_mod.file_path]
print_error("Failed to reload module: #{error}")

return
end

opts = ''

opts << (args + [ "SESSION=#{session.sid}" ]).join(',')
result = reloaded_mod.run_simple(
'LocalInput' => shell.input,
'LocalOutput' => shell.output,
'OptionStr' => opts
)

print_status("Session #{result.sid} created in the background.") if result.is_a?(Msf::Session)
else
# the rest of the arguments get passed in through the binding
session.execute_script(script_name, args)
end
rescue StandardError => e
print_error("Error in script: #{script_name}")
elog("Error in script: #{script_name}", error: e)
end
end
end
end
end
end
end
1 change: 1 addition & 0 deletions metasploit-framework.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,6 @@ Gem::Specification.new do |spec|
# to generate PNG files, not to parse untrusted PNG files.
spec.add_runtime_dependency 'chunky_png'

# Needed for multiline REPL support for interactive SQL sessions
spec.add_runtime_dependency 'reline'
end
19 changes: 9 additions & 10 deletions spec/lib/msf/base/sessions/mysql_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@

require 'spec_helper'
require 'mysql'
# require 'postgres/postgres-pr/connection' # TODO

RSpec.describe Msf::Sessions::MYSQL do
let(:rstream) { instance_double(::Rex::Socket) }
let(:client) { instance_double(::Mysql) } # TODO
let(:client) { instance_double(::Mysql) }
let(:opts) { { client: client } }
let(:console_class) { Rex::Post::MySQL::Ui::Console }
let(:user_input) { instance_double(Rex::Ui::Text::Input::Readline) }
Expand All @@ -17,17 +16,17 @@
let(:description) { 'MySQL' }
let(:can_cleanup_files) { false }
let(:address) { '192.0.2.1' }
let(:port) { '5432' }
let(:peer_info) { "#{address}:#{port}" }
let(:mysql_db) { 'template1' }
let(:port) { '3306' }
let(:peerinfo) { "#{address}:#{port}" }
let(:database) { 'database_name' }

before(:each) do
allow(user_input).to receive(:intrinsic_shell?).and_return(true)
allow(user_input).to receive(:output=)
allow(rstream).to receive(:peerinfo).and_return(peer_info)
allow(client).to receive(:connect).and_return(rstream) # TODO: NEW
# allow(client).to receive(:conn).and_return(rstream)
# allow(client).to receive(:params).and_return({ 'database' => mysql_db })
allow(user_input).to receive(:intrinsic_shell?).and_return(true)
allow(rstream).to receive(:peerinfo).and_return(peerinfo)
allow(client).to receive(:socket).and_return(rstream)
allow(client).to receive(:database).and_return(database)
allow(::Mysql).to receive(:connect).and_return(client)
end

subject(:session) do
Expand Down
18 changes: 8 additions & 10 deletions spec/lib/rex/post/mysql/ui/console/command_dispatcher/core_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,26 @@

require 'spec_helper'
require 'rex/post/mysql/ui/console'
# require 'Mys/postgres-pr/connection' # TODO
require 'mysql'

RSpec.describe Rex::Post::MySQL::Ui::Console::CommandDispatcher::Core do
let(:rstream) { instance_double(::Rex::Socket) }
let(:client) { instance_double(::Mysql) } # TODO
let(:client) { instance_double(::Mysql) }
let(:database) { 'database_name' }
let(:address) { '192.0.2.1' }
let(:port) { '5432' }
let(:mysql_db) { 'template1' }
let(:peer_info) { "#{address}:#{port}" }
let(:session) { Msf::Sessions::MySQL.new(nil, { client: client }) }
let(:port) { '3306' }
let(:peerinfo) { "#{address}:#{port}" }
let(:session) { Msf::Sessions::MYSQL.new(rstream, { client: client }) }
let(:console) do
console = Rex::Post::MySQL::Ui::Console.new(session)
console.disable_output = true
console
end

before(:each) do
# allow(client).to receive(:conn).and_return(rstream)
# allow(client).to receive(:params).and_return({ 'database' => mysql_db })
allow(rstream).to receive(:peerinfo).and_return(peer_info)
allow(session).to receive(:client).and_return(client)
allow(rstream).to receive(:peerinfo).and_return(peerinfo)
allow(client).to receive(:database).and_return(database)
allow(client).to receive(:socket).and_return(rstream)
allow(session).to receive(:console).and_return(console)
allow(session).to receive(:name).and_return('test client name')
allow(session).to receive(:sid).and_return('test client sid')
Expand Down

0 comments on commit 6fee35c

Please sign in to comment.