move over functional msfrop tool

had to make a few inline tweaks to get the
msfrop tool to work without the rest of msf mostly around
the STDIO reimplementation

MS-1722
This commit is contained in:
David Maloney 2016-09-12 15:59:04 -05:00
parent 0a7f4730d3
commit b9476c4f43
No known key found for this signature in database
GPG Key ID: DEDBA9DC3A913DB2
5 changed files with 183 additions and 21 deletions

159
bin/msfrop Executable file
View File

@ -0,0 +1,159 @@
#!/usr/bin/env ruby
# -*- coding: binary -*-
#
# $Id$
#
# This tool will collect, export, and import ROP gadgets
# from various file formats (PE, ELF, Macho)
# $Revision$
#
require 'rex/rop_builder'
require 'rex/text/color'
require 'optparse'
def opt2i(o)
o.index("0x")==0 ? o.hex : o.to_i
end
opts = {}
color = true
opt = OptionParser.new
opt.banner = "Usage #{$PROGRAM_NAME} <option> [targets]"
opt.separator('')
opt.separator('Options:')
opt.on('-d', '--depth [size]', 'Number of maximum bytes to backwards disassemble from return instructions') do |d|
opts[:depth] = opt2i(d)
end
opt.on('-s', '--search [regex]', 'Search for gadgets matching a regex, match intel syntax or raw bytes') do |regex|
opts[:pattern] = regex
end
opt.on('-n', '--nocolor', 'Disable color. Useful for piping to other tools like the less and more commands') do
color = false
end
opt.on('-x', '--export [filename]', 'Export gadgets to CSV format') do |csv|
opts[:export] = csv
end
opt.on('-i', '--import [filename]', 'Import gadgets from previous collections') do |csv|
opts[:import] = csv
end
opt.on('-v', '--verbose', 'Output very verbosely') do
opts[:verbose] = true
end
opt.on_tail('-h', '--help', 'Show this message') do
puts opt
exit
end
begin
opt.parse!
rescue OptionParser::InvalidOption
puts "Invalid option, try -h for usage"
exit(1)
end
if opts.empty? and (ARGV.empty? or ARGV.nil?)
puts "no options"
puts opt
exit(1)
end
# set defaults
opts[:depth] ||= 5
gadgets = []
if opts[:import].nil?
files = []
ARGV.each do |file|
if(File.directory?(file))
dir = Dir.open(file)
dir.entries.each do |ent|
path = File.join(file, ent)
next if not File.file?(path)
files << File.join(path)
end
else
files << file
end
end
ropbuilder = Rex::RopBuilder::RopCollect.new
files.each do |file|
ret, retn = []
ropbuilder = Rex::RopBuilder::RopCollect.new(file)
ropbuilder.print_msg("Collecting gadgets from %bld%cya#{file}%clr\n", color)
retn = ropbuilder.collect(opts[:depth], "\xc2") # retn
ret = ropbuilder.collect(opts[:depth], "\xc3") # ret
ropbuilder.print_msg("Found %grn#{ret.count + retn.count}%clr gadgets\n\n", color)
# compile a list of all gadgets from all files
ret.each do |gadget|
gadgets << gadget
if opts[:verbose]
ropbuilder.print_msg("#{gadget[:file]} gadget: %bld%grn#{gadget[:address]}%clr\n", color)
ropbuilder.print_msg("#{gadget[:disasm]}\n", color)
end
end
retn.each do |gadget|
gadgets << gadget
if opts[:verbose]
ropbuilder.print_msg("#{gadget[:file]} gadget: %bld%grn#{gadget[:address]}%clr\n", color)
ropbuilder.print_msg("#{gadget[:disasm]}\n", color)
end
end
end
ropbuilder.print_msg("Found %bld%grn#{gadgets.count}%clr gadgets total\n\n", color)
end
if opts[:import]
ropbuilder = Rex::RopBuilder::RopCollect.new()
ropbuilder.print_msg("Importing gadgets from %bld%cya#{opts[:import]}\n", color)
gadgets = ropbuilder.import(opts[:import])
gadgets.each do |gadget|
ropbuilder.print_msg("gadget: %bld%cya#{gadget[:address]}%clr\n", color)
ropbuilder.print_msg(gadget[:disasm] + "\n", color)
end
ropbuilder.print_msg("Imported %grn#{gadgets.count}%clr gadgets\n", color)
end
if opts[:pattern]
matches = ropbuilder.pattern_search(opts[:pattern])
if opts[:verbose]
ropbuilder.print_msg("Found %grn#{matches.count}%clr matches\n", color)
end
end
if opts[:export]
ropbuilder.print_msg("Exporting %grn#{gadgets.count}%clr gadgets to %bld%cya#{opts[:export]}%clr\n", color)
csv = ropbuilder.to_csv(gadgets)
if csv.nil?
exit(1)
end
begin
fd = File.new(opts[:export], 'w')
fd.puts csv
fd.close
rescue
puts "Error writing #{opts[:export]} file"
exit(1)
end
ropbuilder.print_msg("%bld%redSuccess!%clr gadgets exported to %bld%cya#{opts[:export]}%clr\n", color)
end

View File

@ -1,4 +1,6 @@
require "rex/rop_builder/version"
require 'rex/rop_builder/rop'
require 'metasm'
module Rex
module RopBuilder

View File

@ -2,21 +2,20 @@
require 'metasm'
require 'rex/compat'
require 'rex/text/table'
require 'rex/ui/text/output/stdio'
require 'rex/text/color'
module Rex
module RopBuilder
class RopBase
include Rex::Text::Color
def initialize()
@stdio = Rex::Ui::Text::Output::Stdio.new
@gadgets = []
end
def to_csv(gadgets = [])
if gadgets.empty? and @gadgets.nil? or @gadgets.empty?
@stdio.print_error("No gadgets collected to convert to CSV format.")
print_error("No gadgets collected to convert to CSV format.")
return
end
@ -46,7 +45,7 @@ class RopBase
begin
data = File.new(file, 'r').read
rescue
@stdio.print_error("Error reading #{file}")
print_error("Error reading #{file}")
return []
end
@ -62,7 +61,7 @@ class RopBase
data.each_line do |line|
addr, raw, disasm = line.split(',', 3)
if addr.nil? or raw.nil? or disasm.nil?
@stdio.print_error("Import file format corrupted")
print_error("Import file format corrupted")
return []
end
disasm.gsub!(/: /, ":\t")
@ -73,23 +72,28 @@ class RopBase
@gadgets
end
def print_msg(msg, color=true)
if not @stdio
@stdio = Rex::Ui::Text::Output::Stdio.new
end
def supports_color?
true
end
if color == true
@stdio.auto_color
else
@stdio.disable_color
def print_error(msg = '')
print_msg("%bld%red[-]%clr #{msg}")
end
def print_msg(msg, color=true)
if color
msg = substitute_colors(msg)
end
@stdio.print_raw(@stdio.substitute_colors(msg))
puts msg
end
def print_status(msg = '')
print_msg("%bld%blu[*]%clr #{msg}")
end
end
class RopCollect < RopBase
def initialize(file="")
@stdio = Rex::Ui::Text::Output::Stdio.new
@file = file if not file.empty?
@bin = Metasm::AutoExe.decode_file(file) if not file.empty?
@disassembler = @bin.disassembler if not @bin.nil?
@ -156,7 +160,7 @@ class RopCollect < RopBase
end
end
matches.each do |match|
@stdio.print_status("gadget with address: %bld%cya#{match[:gadget][:address]}%clr matched")
print_status("gadget with address: %bld%cya#{match[:gadget][:address]}%clr matched")
color_pattern(match[:gadget], match[:disasm], match[:addrs], p)
end
matches

View File

@ -15,8 +15,8 @@ Gem::Specification.new do |spec|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.bindir = "bin"
spec.executables = ["msfrop"]
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler", "~> 1.12"

View File

@ -5,7 +5,4 @@ describe Rex::RopBuilder do
expect(Rex::RopBuilder::VERSION).not_to be nil
end
it 'does something useful' do
expect(false).to eq(true)
end
end