Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/tools/exploit/pattern_offset.rb
Views: 11766
#!/usr/bin/env ruby12##3# This module requires Metasploit: https://metasploit.com/download4# Current source: https://github.com/rapid7/metasploit-framework5##6begin7msfbase = __FILE__8while File.symlink?(msfbase)9msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))10end1112$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))13$LOAD_PATH.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']1415gem 'rex-text'1617require 'optparse'1819module PatternOffset20class OptsConsole21def self.parse(args)22options = {}23parser = OptionParser.new do |opt|24opt.banner = "Usage: #{__FILE__} [options]\nExample: #{__FILE__} -q Aa3A\n[*] Exact match at offset 9"25opt.separator ''26opt.separator 'Options:'2728opt.on('-q', '--query Aa0A', String, "Query to Locate") do |query|29options[:query] = query30end3132opt.on('-l', '--length <length>', Integer, "The length of the pattern") do |len|33options[:length] = len34end3536opt.on('-s', '--sets <ABC,def,123>', Array, "Custom Pattern Sets") do |sets|37options[:sets] = sets38end3940opt.on_tail('-h', '--help', 'Show this message') do41$stdout.puts opt42exit43end44end4546parser.parse!(args)4748if options.empty?49raise OptionParser::MissingArgument, 'No options set, try -h for usage'50elsif options[:query].nil?51raise OptionParser::MissingArgument, '-q <query> is required'52elsif options[:length].nil? && options[:sets]53raise OptionParser::MissingArgument, '-l <length> is required'54end5556options[:sets] = nil unless options[:sets]57options[:length] = 8192 unless options[:length]5859options60end61end6263class Driver64def initialize65begin66@opts = OptsConsole.parse(ARGV)67rescue OptionParser::ParseError => e68$stderr.puts "[x] #{e.message}"69exit70end71end7273def run74require 'rex/text'7576query = (@opts[:query])7778if query.length >= 8 && query.hex > 079query = query.hex80# However, you can also specify a four-byte string81elsif query.length == 482query = query.unpack("V").first83else84# Or even a hex query that isn't 8 bytes long85query = query.to_i(16)86end8788buffer = Rex::Text.pattern_create(@opts[:length], @opts[:sets])89offset = Rex::Text.pattern_offset(buffer, query)9091# Handle cases where there is no match by looking for "close" matches92unless offset93found = false94$stderr.puts "[*] No exact matches, looking for likely candidates..."9596# Look for shifts by a single byte970.upto(3) do |idx|980.upto(255) do |c|99nvb = [query].pack("V")100nvb[idx, 1] = [c].pack("C")101nvi = nvb.unpack("V").first102103off = Rex::Text.pattern_offset(buffer, nvi)104if off105mle = query - buffer[off, 4].unpack("V").first106mbe = query - buffer[off, 4].unpack("N").first107puts "[+] Possible match at offset #{off} (adjusted [ little-endian: #{mle} | big-endian: #{mbe} ] ) byte offset #{idx}"108found = true109end110end111end112113exit! if found114115# Look for 16-bit offsets116[0, 2].each do |idx|1170.upto(65535) do |c|118nvb = [query].pack("V")119nvb[idx, 2] = [c].pack("v")120nvi = nvb.unpack("V").first121122off = Rex::Text.pattern_offset(buffer, nvi)123if off124mle = query - buffer[off, 4].unpack("V").first125mbe = query - buffer[off, 4].unpack("N").first126puts "[+] Possible match at offset #{off} (adjusted [ little-endian: #{mle} | big-endian: #{mbe} ] )"127found = true128end129end130end131end132133while offset134puts "[*] Exact match at offset #{offset}"135offset = Rex::Text.pattern_offset(buffer, query, offset + 1)136end137end138end139end140141if __FILE__ == $PROGRAM_NAME142driver = PatternOffset::Driver.new143begin144driver.run145rescue ::StandardError => e146$stderr.puts "[x] #{e.class}: #{e.message}"147$stderr.puts "[*] If necessary, please refer to framework.log for more details."148149end150end151rescue SignalException => e152puts("Aborted!")153end154155156