# # This plugin provides integration with beSECURE. Written by Noam Rathaus. # # Distributed under MIT license: # http://www.opensource.org/licenses/mit-license.php # # Version 10.5.17 require 'base64' require 'zlib' require 'tempfile' require 'pathname' module Msf class Plugin::BeSECURE < Msf::Plugin class BeSECURECommandDispatcher include Msf::Ui::Console::CommandDispatcher def name 'beSECURE' end def commands { 'besecure_help' => 'Displays help', 'besecure_version' => 'Display the version of the beSECURE server', 'besecure_apikey' => 'Set the beSECURE API Key', 'besecure_hostname' => 'Set the beSECURE Hostname', 'besecure_debug' => 'Enable/Disable debugging', 'besecure_ssl_verify' => 'Enable/Disable SSL verification', 'besecure_report_list' => 'Display list of reports', 'besecure_report_download' => 'Save a report to disk', 'besecure_report_import' => 'Import report specified by ID into framework' } end def cmd_besecure_help print_status('besecure_help Display this help') print_status('besecure_debug Enable/Disable debugging') print_status('besecure_version Display the version of the beSECURE server') print_status('besecure_apikey Set the beSECURE API Key') print_status('besecure_ssl_verify Set whether to verify or not SSL') print_status('besecure_hostname Set the beSECURE Hostname') print_status print_status('REPORTS') print_status('=======') print_status('besecure_report_list Lists reports') print_status('besecure_report_download Downloads an beSECURE report specified by ID') print_status('besecure_report_import Import report specified by ID into framework') end # Verify the database is connected and usable def database? if !(framework.db && framework.db.usable) return false else return true end end # Verify correct number of arguments and verify -h was not given. Return # true if correct number of arguments and help was not requested. def args?(args, min = 1, max = nil) if !max then max = min end if ((args.length < min) || (args.length > max) || (args[0] == '-h')) return false end return true end #-------------------------- # Basic Functions #-------------------------- def cmd_besecure_hostname(*args) if args?(args) @hostname = args[0] print_good(@hostname) else print_status('Usage:') print_status('besecure_hostname string') end end def cmd_besecure_apikey(*args) if args?(args) @apikey = args[0] print_good(@apikey) else print_status('Usage:') print_status('besecure_apikey string') end end def cmd_besecure_ssl_verify(*args) if args?(args) @ssl_verify = args[0] if (@ssl_verify != 'yes') && (@ssl_verify != 'no') @ssl_verify = 'yes' end print_good(@ssl_verify) else print_status('Usage:') print_status("besecure_ssl_verify 'yes'/'no' (default is yes)") end end def cmd_besecure_debug(*args) if args?(args) @debug = args[0].to_i print_good(@debug) else print_status('Usage:') print_status('besecure_debug integer') end end def cmd_besecure_version req = Net::HTTP::Post.new('/json.cgi', { 'Host' => @hostname }) req.set_form_data({ 'apikey' => @apikey, 'primary' => 'interface' }) if @debug print_status(req.body) end http = Net::HTTP.new(@hostname, 443) if @debug http.set_debug_output($stdout) # Logger.new("foo.log") works too end http.use_ssl = true if @ssl_verify == 'no' http.verify_mode = OpenSSL::SSL::VERIFY_NONE end res = http.start { |h| h.request(req) } unless res print_error("#{@hostname} - Connection timed out") return '' end body = '' begin body = JSON.parse(res.body) rescue JSON::ParserError print_error("#{@hostname} - Unable to parse the response") return '' end if body['error'] print_error("#{@hostname} - An error occurred:") print_error(body) return '' end print_good(body['version']) end #-------------------------- # Report Functions #-------------------------- def cmd_besecure_report_list(*_args) tbl = Rex::Text::Table.new( 'Columns' => ['ID', 'Name', 'Hosts'] ) if @hostname.empty? print_error('Missing host value') return '' end req = Net::HTTP::Post.new('/json.cgi', { 'Host' => @hostname }) req.set_form_data({ 'apikey' => @apikey, 'primary' => 'admin', 'secondary' => 'networks', 'action' => 'returnnetworks', 'search_limit' => 10000 }) if @debug print_status(req.body) end http = Net::HTTP.new(@hostname, 443) if @debug http.set_debug_output($stdout) # Logger.new("foo.log") works too end http.use_ssl = true if @ssl_verify == 'no' http.verify_mode = OpenSSL::SSL::VERIFY_NONE end res = http.start { |h| h.request(req) } unless res print_error("#{@hostname} - Connection timed out") return '' end body = '' begin body = JSON.parse(res.body) rescue JSON::ParserError print_error("#{@hostname} - Unable to parse the response") return '' end if body['error'] print_error("#{@hostname} - An error occurred:") print_error(body) return '' end data = body['data'] data.each do |item| tbl << [ item['ID'], item['Name'], item['PrettyRange']] end # print_good(body) print_good('beSECURE list of reports') print_line print_line tbl.to_s print_line end def cmd_besecure_report_download(*args) if args?(args, 4) req = Net::HTTP::Post.new('/json.cgi', { 'Host' => @hostname }) format_file = args[1] req.set_form_data({ 'apikey' => @apikey, 'primary' => 'vulnerabilities', 'secondary' => 'report', 'action' => 'getreport', 'network' => args[0], 'format' => format_file }) http = Net::HTTP.new(@hostname, 443) if @debug http.set_debug_output($stdout) # Logger.new("foo.log") works too end http.use_ssl = true if @ssl_verify == 'no' http.verify_mode = OpenSSL::SSL::VERIFY_NONE end res = http.start { |h| h.request(req) } unless res print_error("#{@hostname} - Connection timed out") return '' end body = '' begin body = JSON.parse(res.body) rescue JSON::ParserError print_error("#{@hostname} - Unable to parse the response") return '' end if body['error'] print_error("#{@hostname} - An error occurred:") print_error(body) return '' end decompressed = '' if format_file != 'json' compressed_base64 = body['compresseddata'] compressed = Base64.decode64(compressed_base64) decompressed = Zlib::Inflate.inflate(compressed) else decompressed = body end if @debug print_status(decompressed) end ::FileUtils.mkdir_p(args[2]) name = ::File.join(args[2], args[3]) print_status("Saving report to #{name}") output = ::File.new(name, 'w') output.puts(decompressed) output.close ### # Return the report return decompressed else print_status('Usage: besecure_report_download ') end return '' end def cmd_besecure_report_import(*args) if args?(args, 2) if !database? print_error('Database not ready') return '' end tempfile = Tempfile.new('results') res = cmd_besecure_report_download(args[0], 'nbe', File.dirname(tempfile) + '/', File.basename(tempfile)) if res.empty? print_error('An empty report has been received') return '' end print_status('Importing report to database.') framework.db.import_file({ filename: tempfile }) tempfile.unlink else print_status('Usage: besecure_report_import ') print_status('Only the NBE and XML formats are supported for importing.') end end end #------------------------------ # Plugin initialization #------------------------------ def initialize(framework, opts) super add_console_dispatcher(BeSECURECommandDispatcher) print_status('Welcome to beSECURE integration by Noam Rathaus.') print_status print_status('beSECURE integration requires a database connection. Once the ') print_status('database is ready, connect to the beSECURE server using besecure_connect.') print_status('For additional commands use besecure_help.') print_status @debug = nil end def cleanup remove_console_dispatcher('beSECURE') end def name 'beSECURE' end def desc 'Integrates with the beSECURE - open source vulnerability management' end end end