From 8f7d0eae0c6fc69fb415690bba3224f97b01e20e Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 2 Aug 2016 14:44:58 -0500 Subject: [PATCH 1/7] Fix #7155 - Add post module to compress (zip) a file or directory Fix #7155 --- data/post/zip/zip.vbs | 60 ++++++++++++++++++++ modules/post/multi/manage/zip.rb | 94 ++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 data/post/zip/zip.vbs create mode 100644 modules/post/multi/manage/zip.rb diff --git a/data/post/zip/zip.vbs b/data/post/zip/zip.vbs new file mode 100644 index 0000000000..47fc6193c1 --- /dev/null +++ b/data/post/zip/zip.vbs @@ -0,0 +1,60 @@ +Function WindowsZip(sFile, sZipFile) + 'This script is provided under the Creative Commons license located + 'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not + 'be used for commercial purposes with out the expressed written consent + 'of NateRice.com + + Set oZipShell = CreateObject("WScript.Shell") + Set oZipFSO = CreateObject("Scripting.FileSystemObject") + + If Not oZipFSO.FileExists(sZipFile) Then + NewZip(sZipFile) + End If + + Set oZipApp = CreateObject("Shell.Application") + + sZipFileCount = oZipApp.NameSpace(sZipFile).items.Count + + aFileName = Split(sFile, "\") + sFileName = (aFileName(Ubound(aFileName))) + + 'listfiles + sDupe = False + For Each sFileNameInZip In oZipApp.NameSpace(sZipFile).items + If LCase(sFileName) = LCase(sFileNameInZip) Then + sDupe = True + Exit For + End If + Next + + If Not sDupe Then + oZipApp.NameSpace(sZipFile).Copyhere sFile + + 'Keep script waiting until Compressing is done + On Error Resume Next + sLoop = 0 + Do Until sZipFileCount < oZipApp.NameSpace(sZipFile).Items.Count + Wscript.Sleep(100) + sLoop = sLoop + 1 + Loop + On Error GoTo 0 + End If +End Function + +Sub NewZip(sNewZip) + 'This script is provided under the Creative Commons license located + 'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not + 'be used for commercial purposes with out the expressed written consent + 'of NateRice.com + + Set oNewZipFSO = CreateObject("Scripting.FileSystemObject") + Set oNewZipFile = oNewZipFSO.CreateTextFile(sNewZip) + + oNewZipFile.Write Chr(80) & Chr(75) & Chr(5) & Chr(6) & String(18, 0) + + oNewZipFile.Close + Set oNewZipFSO = Nothing + + Wscript.Sleep(500) +End Sub + diff --git a/modules/post/multi/manage/zip.rb b/modules/post/multi/manage/zip.rb new file mode 100644 index 0000000000..b1b6bd98ec --- /dev/null +++ b/modules/post/multi/manage/zip.rb @@ -0,0 +1,94 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Post + + include Msf::Post::File + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Multi Manage File Compressor', + 'Description' => %q{ + This module zips a directory or a directory. On Linux, it uses the zip command. + On Windows, it will try to use remote target's 7Zip if found. If not, it falls + back to its own VBScript. + }, + 'License' => MSF_LICENSE, + 'Author' => [ 'sinn3r' ], + 'Platform' => [ 'win', 'linux' ], + 'SessionTypes' => [ 'meterpreter', 'shell' ] + )) + + register_options( + [ + OptString.new('DESTINATION', [false, 'The destination path']), + OptString.new('SOURCE', [true, 'The directory or file to compress']) + ], self.class) + end + + def get_program_file_path + @program_file_path ||= lambda { + session.sys.config.getenvs("ProgramFiles")['ProgramFiles'] + }.call + end + + def has_7zip? + file?("#{get_program_file_path}\\7-Zip\\7z.exe") + end + + def vbs(dest, src) + vbs_file = File.read(File.join(Msf::Config.data_directory, "post", "zip", "zip.vbs")) + vbs_file << "WindowsZip \"#{src}\",\"#{dest}\"" + vbs_file + end + + def upload_exec_vbs_zip + script = vbs(datastore['DESTINATION'], datastore['SOURCE']) + tmp_path = "#{session.sys.config.getenvs('TEMP')['TEMP']}\\zip.vbs" + print_status("VBS file uploaded to #{tmp_path}") + write_file(tmp_path, script) + cmd_exec("wscript.exe #{tmp_path}") + end + + def do_7zip + program_file_path = get_program_file_path + output = cmd_exec("#{program_file_path}\\7-Zip\\7z.exe a -tzip \"#{datastore['DESTINATION']}\" \"#{datastore['SOURCE']}\"") + vprint_line(output) + end + + def do_zip + output = cmd_exec("zip -D -d -q -r #{datastore['DESTINATION']} #{datastore['SOURCE']}") + vprint_line(output) + end + + def windows_zip + if has_7zip? + print_status("Compressing #{datastore['DESTINATION']} via 7zip") + do_7zip + else + print_status("Compressing #{datastore['DESTINATION']} via VBS") + upload_exec_vbs_zip + end + end + + def linux_zip + print_status("Compressing #{datastore['DESTINATION']} via zip") + do_zip + end + + def run + os = get_target_os + case os + when Msf::Module::Platform::Windows.realname.downcase + windows_zip + else + linux_zip + end + end + +end + From bddf5edcf10de5a43654d9372e564e1ada01acb7 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 3 Aug 2016 11:04:53 -0500 Subject: [PATCH 2/7] Fix typo --- modules/post/multi/manage/zip.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/post/multi/manage/zip.rb b/modules/post/multi/manage/zip.rb index b1b6bd98ec..c18f9b434d 100644 --- a/modules/post/multi/manage/zip.rb +++ b/modules/post/multi/manage/zip.rb @@ -13,7 +13,7 @@ class MetasploitModule < Msf::Post super(update_info(info, 'Name' => 'Multi Manage File Compressor', 'Description' => %q{ - This module zips a directory or a directory. On Linux, it uses the zip command. + This module zips a file or a directory. On Linux, it uses the zip command. On Windows, it will try to use remote target's 7Zip if found. If not, it falls back to its own VBScript. }, From 45801bc44eebf2d28dcaa36f83e2b8900c7e1f59 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 3 Aug 2016 11:11:34 -0500 Subject: [PATCH 3/7] get_env --- modules/post/multi/manage/zip.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/post/multi/manage/zip.rb b/modules/post/multi/manage/zip.rb index c18f9b434d..ed7ed38413 100644 --- a/modules/post/multi/manage/zip.rb +++ b/modules/post/multi/manage/zip.rb @@ -31,9 +31,7 @@ class MetasploitModule < Msf::Post end def get_program_file_path - @program_file_path ||= lambda { - session.sys.config.getenvs("ProgramFiles")['ProgramFiles'] - }.call + get_env('ProgramFiles') end def has_7zip? @@ -48,7 +46,7 @@ class MetasploitModule < Msf::Post def upload_exec_vbs_zip script = vbs(datastore['DESTINATION'], datastore['SOURCE']) - tmp_path = "#{session.sys.config.getenvs('TEMP')['TEMP']}\\zip.vbs" + tmp_path = "#{get_env('TEMP')}\\zip.vbs" print_status("VBS file uploaded to #{tmp_path}") write_file(tmp_path, script) cmd_exec("wscript.exe #{tmp_path}") From 60937ec5e9f5d0f69328eb91c334c3efa0176d59 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 17 Aug 2016 16:56:09 -0500 Subject: [PATCH 4/7] If user is SYSTEM, then steal a token before decompression --- modules/post/multi/manage/zip.rb | 53 ++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/modules/post/multi/manage/zip.rb b/modules/post/multi/manage/zip.rb index ed7ed38413..8268111a29 100644 --- a/modules/post/multi/manage/zip.rb +++ b/modules/post/multi/manage/zip.rb @@ -8,6 +8,7 @@ require 'msf/core' class MetasploitModule < Msf::Post include Msf::Post::File + include Msf::Post::Windows::Priv def initialize(info={}) super(update_info(info, @@ -44,7 +45,48 @@ class MetasploitModule < Msf::Post vbs_file end + def find_pid_by_user(username) + computer_name = get_env('COMPUTERNAME') + print_status("Searching for PID for #{computer_name}\\\\#{username}") + session.sys.process.processes.each do |p| + if p['user'] == "#{computer_name}\\#{username}" + return p['pid'] + end + end + + nil + end + + def steal_token + current_user = get_env('USERNAME') + pid = find_pid_by_user(current_user) + + unless pid + fail_with(Failure::Unknown, "Unable to find a PID for #{current_user} to execute .vbs") + end + + print_status("Stealing token from PID #{pid} for #{current_user}") + begin + session.sys.config.steal_token(pid) + rescue Rex::Post::Meterpreter::RequestError => e + # It could raise an exception even when the token is successfully stolen, + # so we will just log the exception and move on. + elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") + end + + @token_stolen = true + end + def upload_exec_vbs_zip + if is_system? + unless session + print_error('Unable to decompress with VBS technique without Meterpreter') + return + end + + steal_token + end + script = vbs(datastore['DESTINATION'], datastore['SOURCE']) tmp_path = "#{get_env('TEMP')}\\zip.vbs" print_status("VBS file uploaded to #{tmp_path}") @@ -78,7 +120,18 @@ class MetasploitModule < Msf::Post do_zip end + def cleanup + if @token_stolen && session + session.sys.config.revert_to_self + print_status('Token restored.') + end + + super + end + def run + @token_stolen = false + os = get_target_os case os when Msf::Module::Platform::Windows.realname.downcase From e154aafaaa6cf3caaaec52c5409504eb159ceb44 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 17 Aug 2016 17:08:38 -0500 Subject: [PATCH 5/7] On Error Resume Next for zip.vbs --- data/post/zip/zip.vbs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/post/zip/zip.vbs b/data/post/zip/zip.vbs index 47fc6193c1..8ae2cfbbf3 100644 --- a/data/post/zip/zip.vbs +++ b/data/post/zip/zip.vbs @@ -1,3 +1,5 @@ +On Error Resume Next + Function WindowsZip(sFile, sZipFile) 'This script is provided under the Creative Commons license located 'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not From b081dbf70327501f2435bcbde99ac75868172cc9 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Aug 2016 15:56:16 -0500 Subject: [PATCH 6/7] Make destination required --- modules/post/multi/manage/zip.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/post/multi/manage/zip.rb b/modules/post/multi/manage/zip.rb index 8268111a29..8ad0638833 100644 --- a/modules/post/multi/manage/zip.rb +++ b/modules/post/multi/manage/zip.rb @@ -26,7 +26,7 @@ class MetasploitModule < Msf::Post register_options( [ - OptString.new('DESTINATION', [false, 'The destination path']), + OptString.new('DESTINATION', [true, 'The destination path']), OptString.new('SOURCE', [true, 'The directory or file to compress']) ], self.class) end From 89c3b6f399c214aaef745e6334a663d46fc2458e Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 23 Aug 2016 18:43:50 -0500 Subject: [PATCH 7/7] Remove the -d flag for Linux machines --- modules/post/multi/manage/zip.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/post/multi/manage/zip.rb b/modules/post/multi/manage/zip.rb index 8ad0638833..ae7f50b90e 100644 --- a/modules/post/multi/manage/zip.rb +++ b/modules/post/multi/manage/zip.rb @@ -101,7 +101,7 @@ class MetasploitModule < Msf::Post end def do_zip - output = cmd_exec("zip -D -d -q -r #{datastore['DESTINATION']} #{datastore['SOURCE']}") + output = cmd_exec("zip -D -q -r #{datastore['DESTINATION']} #{datastore['SOURCE']}") vprint_line(output) end