# # This plugin provides integration with OpenVAS. Written by kost and # averagesecurityguy. # # $Id$ # $Revision$ # # Distributed under MIT license: # http://www.opensource.org/licenses/mit-license.php # require 'openvas-omp' module Msf class Plugin::OpenVAS < Msf::Plugin class OpenVASCommandDispatcher include Msf::Ui::Console::CommandDispatcher def name "OpenVAS" end def commands { 'openvas_help' => "Displays help", 'openvas_version' => "Display the version of the OpenVAS server", 'openvas_debug' => "Enable/Disable debugging", 'openvas_connect' => "Connect to an OpenVAS manager using OMP", 'openvas_disconnect' => "Disconnect from OpenVAS manager", 'openvas_task_create' => "Create a task (name, comment, target, config)", 'openvas_task_delete' => "Delete task by ID", 'openvas_task_list' => "Display list of tasks", 'openvas_task_start' => "Start task by ID", 'openvas_task_stop' => "Stop task by ID", 'openvas_task_pause' => "Pause task by ID", 'openvas_task_resume' => "Resume task by ID", 'openvas_task_resume_or_start' => "Resume task or start task by ID", 'openvas_target_create' => "Create target (name, hosts, comment)", 'openvas_target_delete' => "Delete target by ID", 'openvas_target_list' => "Display list of targets", 'openvas_config_list' => "Quickly display list of configs", 'openvas_format_list' => "Display list of available report formats", 'openvas_report_list' => "Display a list of available report formats", 'openvas_report_delete' => "Delete a report specified by ID", 'openvas_report_download' => "Save a report to disk", 'openvas_report_import' => "Import report specified by ID into framework", } end def cmd_openvas_help() print_status("openvas_help Display this help") print_status("openvas_debug Enable/Disable debugging") print_status("openvas_version Display the version of the OpenVAS server") print_status print_status("CONNECTION") print_status("==========") print_status("openvas_connect Connects to OpenVAS") print_status("openvas_disconnect Disconnects from OpenVAS") print_status print_status("TARGETS") print_status("=======") print_status("openvas_target_create Create target") print_status("openvas_target_delete Deletes target specified by ID") print_status("openvas_target_list Lists targets") print_status print_status("TASKS") print_status("=====") print_status("openvas_task_create Create task") print_status("openvas_task_delete Delete a task and all associated reports") print_status("openvas_task_list Lists tasks") print_status("openvas_task_start Starts task specified by ID") print_status("openvas_task_stop Stops task specified by ID") print_status("openvas_task_pause Pauses task specified by ID") print_status("openvas_task_resume Resumes task specified by ID") print_status("openvas_task_resume_or_start Resumes or starts task specified by ID") print_status print_status("CONFIGS") print_status("=======") print_status("openvas_config_list Lists scan configurations") print_status print_status("FORMATS") print_status("=======") print_status("openvas_format_list Lists available report formats") print_status print_status("REPORTS") print_status("=======") print_status("openvas_report_list Lists available reports") print_status("openvas_report_delete Delete a report specified by ID") print_status("openvas_report_import Imports an OpenVAS report specified by ID") print_status("openvas_report_download Downloads an OpenVAS report specified by ID") end # Verify the database is connected and usable def database? if !(framework.db and framework.db.usable) return false else return true end end # Verify there is an active OpenVAS connection def openvas? if @ov return true else print_error("No OpenVAS connection available. Please use openvas_connect.") return false 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 not max then max = min end if (args.length < min or args.length > max or args[0] == "-h") return false end return true end #-------------------------- # Basic Functions #-------------------------- def cmd_openvas_debug(*args) return unless openvas? if args?(args) begin resp = @ov.debug(args[0].to_i) print_good(resp) rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage:") print_status("openvas_debug integer") end end def cmd_openvas_version() return unless openvas? begin ver = @ov.version_get print_good("Using OMP version #{ver}") rescue OpenVASOMP::OMPError => e print_error(e.to_s) end end #-------------------------- # Connection Functions #-------------------------- def cmd_openvas_connect(*args) # Is the database configured? if not database? print_error("No database has been configured.") return end # Don't allow duplicate sessions if @ov then print_error("Session already open, please use openvas_disconnect first.") return end # Make sure the correct number of arguments are present. if args?(args, 4, 5) user, pass, host, port, sslv = args # SSL warning. User is required to confirm. if(host != "localhost" and host != "127.0.0.1" and sslv != "ok") print_error("Warning: SSL connections are not verified in this release, it is possible for an attacker") print_error(" with the ability to man-in-the-middle the OpenVAS traffic to capture the OpenVAS") print_error(" credentials. If you are running this on a trusted network, please pass in 'ok'") print_error(" as an additional parameter to this command.") return end begin print_status("Connecting to OpenVAS instance at #{host}:#{port} with username #{user}...") ov = OpenVASOMP::OpenVASOMP.new('user' => user, 'password' => pass, 'host' => host, 'port' => port) rescue OpenVASOMP::OMPAuthError => e print_error("Authentication failed: #{e.reason}") return rescue OpenVASOMP::OMPConnectionError => e print_error("Connection failed: #{e.reason}") return end print_good("OpenVAS connection successful") @ov = ov else print_status("Usage:") print_status("openvas_connect username password host port ") end end # Disconnect from an OpenVAS manager def cmd_openvas_disconnect() return unless openvas? @ov.logout @ov = nil end #-------------------------- # Target Functions #-------------------------- def cmd_openvas_target_create(*args) return unless openvas? if args?(args, 3) begin resp = @ov.target_create('name' => args[0], 'hosts' => args[1], 'comment' => args[2]) print_status(resp) cmd_openvas_target_list rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_target_create ") end end def cmd_openvas_target_delete(*args) return unless openvas? if args?(args) begin resp = @ov.target_delete(args[0]) print_status(resp) cmd_openvas_target_list rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_target_delete ") end end def cmd_openvas_target_list(*args) return unless openvas? begin tbl = Rex::Text::Table.new( 'Columns' => ["ID", "Name", "Hosts", "Max Hosts", "In Use", "Comment"]) @ov.target_get_all().each do |target| tbl << [ target["id"], target["name"], target["hosts"], target["max_hosts"], target["in_use"], target["comment"] ] end print_good("OpenVAS list of targets") print_line print_line tbl.to_s print_line rescue OpenVASOMP::OMPError => e print_error(e.to_s) end end #-------------------------- # Task Functions #-------------------------- def cmd_openvas_task_create(*args) return unless openvas? if args?(args, 4) begin resp = @ov.task_create('name' => args[0], 'comment' => args[1], 'config' => args[2], 'target'=> args[3]) print_status(resp) cmd_openvas_task_list rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_task_create ") end end def cmd_openvas_task_delete(*args) return unless openvas? if args?(args, 2) # User is required to confirm before deleting task. if(args[1] != "ok") print_error("Warning: Deleting a task will also delete all reports associated with the ") print_error("task, please pass in 'ok' as an additional parameter to this command.") return end begin resp = @ov.task_delete(args[0]) print_status(resp) cmd_openvas_task_list rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_task_delete ok") print_error("This will delete the task and all associated reports.") end end def cmd_openvas_task_list(*args) return unless openvas? begin tbl = Rex::Text::Table.new( 'Columns' => ["ID", "Name", "Comment", "Status", "Progress"]) @ov.task_get_all().each do |task| tbl << [ task["id"], task["name"], task["comment"], task["status"], task["progress"] ] end print_good("OpenVAS list of tasks") print_line print_line tbl.to_s print_line rescue OpenVASOMP::OMPError => e print_error(e.to_s) end end def cmd_openvas_task_start(*args) return unless openvas? if args?(args) begin resp = @ov.task_start(args[0]) print_status(resp) rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_task_start ") end end def cmd_openvas_task_stop(*args) return unless openvas? if args?(args) begin resp = @ov.task_stop(args[0]) print_status(resp) rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_task_stop ") end end def cmd_openvas_task_pause(*args) return unless openvas? if args?(args) begin resp = @ov.task_pause(args[0]) print_status(resp) rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_task_pause ") end end def cmd_openvas_task_resume(*args) return unless openvas? if args?(args) begin resp = @ov.task_resume_paused(args[0]) print_status(resp) rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_task_resume ") end end def cmd_openvas_task_resume_or_start(*args) return unless openvas? if args?(args) begin resp = @ov.task_resume_or_start(args[0]) print_status(resp) rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_task_resume_or_start ") end end #-------------------------- # Config Functions #-------------------------- def cmd_openvas_config_list(*args) return unless openvas? begin tbl = Rex::Text::Table.new( 'Columns' => [ "ID", "Name" ]) @ov.config_get_all.each do |config| tbl << [ config["id"], config["name"] ] end print_good("OpenVAS list of configs") print_line print_line tbl.to_s print_line rescue OpenVASOMP::OMPError => e print_error(e.to_s) end end #-------------------------- # Format Functions #-------------------------- def cmd_openvas_format_list(*args) return unless openvas? begin tbl = Rex::Text::Table.new( 'Columns' => ["ID", "Name", "Extension", "Summary"]) format_get_all.each do |format| tbl << [ format["id"], format["name"], format["extension"], format["summary"] ] end print_good("OpenVAS list of report formats") print_line print_line tbl.to_s print_line rescue OpenVASOMP::OMPError => e print_error(e.to_s) end end #-------------------------- # Report Functions #-------------------------- def cmd_openvas_report_list(*args) return unless openvas? begin tbl = Rex::Text::Table.new( 'Columns' => ["ID", "Task Name", "Start Time", "Stop Time"]) resp = @ov.report_get_raw resp.elements.each("//get_reports_response/report") do |report| report_id = report.elements["report"].attributes["id"] report_task = report.elements["task/name"].get_text report_start_time = report.elements["creation_time"].get_text report_stop_time = report.elements["modification_time"].get_text tbl << [ report_id, report_task, report_start_time, report_stop_time ] end print_good("OpenVAS list of reports") print_line print_line tbl.to_s print_line rescue OpenVASOMP::OMPError => e print_error(e.to_s) end end def cmd_openvas_report_delete(*args) return unless openvas? if args?(args) begin resp = @ov.report_delete(args[0]) print_status(resp) cmd_openvas_report_list rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_report_delete ") end end def cmd_openvas_report_download(*args) return unless openvas? if args?(args, 4) begin report = @ov.report_get_raw("report_id"=>args[0],"format"=>args[1]) ::FileUtils.mkdir_p(args[2]) name = ::File.join(args[2], args[3]) print_status("Saving report to #{name}") output = ::File.new(name, "w") data = nil report.elements.each("//get_reports_response"){|r| data = r.to_s} output.puts(data) output.close rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_report_download ") end end def cmd_openvas_report_import(*args) return unless openvas? if args?(args, 2) begin report = @ov.report_get_raw("report_id"=>args[0],"format"=>args[1]) data = nil report.elements.each("//get_reports_response"){|r| data = r.to_s} print_status("Importing report to database.") framework.db.import({:data => data}) rescue OpenVASOMP::OMPError => e print_error(e.to_s) end else print_status("Usage: openvas_report_import ") print_status("Only the NBE and XML formats are supported for importing.") end end #-------------------------- # Format Functions #-------------------------- # Get a list of report formats def format_get_all begin resp = @ov.omp_request_xml("") if @debug then print resp end list = Array.new resp.elements.each('//get_report_formats_response/report_format') do |report| td = Hash.new td["id"] = report.attributes["id"] td["name"] = report.elements["name"].text td["extension"] = report.elements["extension"].text td["summary"] = report.elements["summary"].text list.push td end @formats = list return list rescue raise OMPResponseError end end end # End OpenVAS class #------------------------------ # Plugin initialization #------------------------------ def initialize(framework, opts) super add_console_dispatcher(OpenVASCommandDispatcher) print_status("Welcome to OpenVAS integration by kost and averagesecurityguy.") print_status print_status("OpenVAS integration requires a database connection. Once the ") print_status("database is ready, connect to the OpenVAS server using openvas_connect.") print_status("For additional commands use openvas_help.") print_status @ov = nil @formats = nil @debug = nil end def cleanup remove_console_dispatcher('OpenVAS') end def name "OpenVAS" end def desc "Integrates with the OpenVAS - open source vulnerability management" end end end