class BeefRestAPI # initialize def initialize proto = 'https', host = '127.0.0.1', port = '3000', user = 'beef', pass = 'beef' @user = user @pass = pass @url = "#{proto}://#{host}:#{port}/api/" @token = nil end ################################################################################ ### BeEF core API ################################################################################ # authenticate and get API token def auth print_verbose "Retrieving authentication token" begin response = RestClient.post "#{@url}admin/login", { 'username' => "#{@user}", 'password' => "#{@pass}" }.to_json, :content_type => :json, :accept => :json result = JSON.parse(response.body) @token = result['token'] print_good "Retrieved RESTful API token: #{@token}" rescue => e print_error "Could not retrieve RESTful API token: #{e.message}" end end # get BeEF version def version begin response = RestClient.get "#{@url}server/version", {:params => {:token => @token}} result = JSON.parse(response.body) print_good "Retrieved BeEF version: #{result['version']}" result['version'] rescue => e print_error "Could not retrieve BeEF version: #{e.message}" end end # get server mounts def mounts begin response = RestClient.get "#{@url}server/mounts", {:params => {:token => @token}} result = JSON.parse(response.body) print_good "Retrieved BeEF server mounts: #{result['mounts']}" result['mounts'] rescue => e print_error "Could not retrieve BeEF version: #{e.message}" end end # get online hooked browsers def online_browsers begin print_verbose "Retrieving online browsers" response = RestClient.get "#{@url}hooks", {:params => {:token => @token}} result = JSON.parse(response.body) browsers = result["hooked-browsers"]["online"] print_good "Retrieved online browser list [#{browsers.size} online]" browsers rescue => e print_error "Could not retrieve browser details: #{e.message}" end end # get offline hooked browsers def offline_browsers begin print_verbose "Retrieving offline browsers" response = RestClient.get "#{@url}hooks", {:params => {:token => @token}} result = JSON.parse(response.body) browsers = result["hooked-browsers"]["offline"] print_good "Retrieved offline browser list [#{browsers.size} offline]" browsers rescue => e print_error "Could not retrieve browser details: #{e.message}" end end # get hooked browser details by session def browser_details session begin print_verbose "Retrieving browser details for hooked browser [session: #{session}]" response = RestClient.get "#{@url}browserdetails/#{session}", {:params => {:token => @token}} result = JSON.parse(response.body) details = result['details'] print_good "Retrieved #{details.size} browser details" details rescue => e print_error "Could not retrieve browser details: #{e.message}" end end # delete a browser by session def delete_browser session begin print_verbose "Removing hooked browser [session: #{session}]" response = RestClient.get "#{@url}hooks/#{session}/delete", {:params => {:token => @token}} print_good "Removed browser [session: #{session}]" if response.code == 200 response rescue => e print_error "Could not delete hooked browser: #{e.message}" end end # get BeEF logs def logs begin print_verbose "Retrieving logs" response = RestClient.get "#{@url}logs", {:params => {:token => @token}} logs = JSON.parse(response.body) print_good "Retrieved #{logs['logs_count']} log entries" logs rescue => e print_error "Could not retrieve logs: #{e.message}" end end # get hooked browser logs by session def browser_logs session begin print_verbose "Retrieving browser logs [session: #{session}]" response = RestClient.get "#{@url}logs/#{session}", {:params => {:token => @token}} logs = JSON.parse(response.body) print_good "Retrieved #{logs['logs'].size} browser logs" logs rescue => e print_error "Could not retrieve browser logs: #{e.message}" end end ################################################################################ ### command module API ################################################################################ # get command module categories def categories begin print_verbose "Retrieving module categories" response = RestClient.get "#{@url}categories", {:params => {:token => @token}} categories = JSON.parse(response.body) print_good "Retrieved #{categories.size} module categories" categories rescue => e print_error "Could not retrieve logs: #{e.message}" end end # get command modules def modules begin print_verbose "Retrieving modules" response = RestClient.get "#{@url}modules", {:params => {:token => @token}} @modules = JSON.parse(response.body) print_good "Retrieved #{@modules.size} available command modules" @modules rescue => e print_error "Could not retrieve modules: #{e.message}" end end # get module id by module short name def get_module_id mod_name print_verbose "Retrieving id for module [name: #{mod_name}]" @modules.each do |mod| # normal modules if mod_name.capitalize == mod[1]["class"] return mod[1]["id"] break # metasploit modules elsif mod[1]["class"] == "Msf_module" && mod_name.capitalize == mod[1]["name"] return mod[1]["id"] break end end nil end # get command module details def module_details id begin print_verbose "Retrieving details for command module [id: #{id}]" response = RestClient.get "#{@url}modules/#{id}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved details for module [#{details['name']}]" details rescue => e print_error "Could not retrieve modules: #{e.message}" end end # execute module def execute_module session, mod_id, options print_verbose "Executing module [id: #{mod_id}, #{options}]" begin response = RestClient.post "#{@url}modules/#{session}/#{mod_id}?token=#{@token}", options.to_json, :content_type => :json, :accept => :json result = JSON.parse(response.body) if result['success'] == 'true' print_good "Executed module [id: #{mod_id}]" else print_error "Could not execute module [id: #{mod_id}]" end result rescue => e print_error "Could not start payload handler: #{e.message}" end end ################################################################################ ### Metasploit API ################################################################################ # get metasploit version def msf_version begin response = RestClient.get "#{@url}msf/version", {:params => {:token => @token}} result = JSON.parse(response.body) version = result['version']['version'] print_good "Retrieved Metasploit version: #{version}" version rescue => e print_error "Could not retrieve Metasploit version: #{e.message}" end end # get metasploit jobs def msf_jobs begin response = RestClient.get "#{@url}msf/jobs", {:params => {:token => @token}} result = JSON.parse(response.body) jobs = result['jobs'] print_good "Retrieved job list [#{jobs.size} jobs]" jobs rescue => e print_error "Could not retrieve Metasploit job list: #{e.message}" end end # get metasploit job info def msf_job_info id begin response = RestClient.get "#{@url}msf/job/#{id}/info", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved job information [id: #{id}]" details rescue => e print_error "Could not retrieve job info: #{e.message}" end end # start metasploit payload handler def msf_handler options print_verbose "Starting Metasploit payload handler [#{options}]" begin response = RestClient.post "#{@url}msf/handler?token=#{@token}", options.to_json, :content_type => :json, :accept => :json result = JSON.parse(response.body) job_id = result['id'] if job_id.nil? print_error "Could not start payload handler: Job id is nil" else print_good "Started payload handler [id: #{job_id}]" end job_id rescue => e print_error "Could not start payload handler: #{e.message}" end end # stop metasploit job def msf_job_stop id print_verbose "Stopping Metasploit job [id: #{id}]" begin response = RestClient.get "#{@url}msf/job/#{id}/stop", {:params => {:token => @token}} result = JSON.parse(response.body) if result['success'].nil? print_error "Could not stop Metasploit job [id: #{id}]: No such job ?" else print_good "Stopped job [id: #{id}]" end result rescue => e print_error "Could not stop Metasploit job [id: #{id}]: #{e.message}" end end ################################################################################ ### Network API ################################################################################ # get all network hosts def network_hosts_all begin print_verbose "Retrieving all network hosts" response = RestClient.get "#{@url}network/hosts", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} network hosts" details rescue => e print_error "Could not retrieve network hosts: #{e.message}" end end # get all network services def network_services_all begin print_verbose "Retrieving all network services" response = RestClient.get "#{@url}network/services", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} network services" details rescue => e print_error "Could not retrieve network services: #{e.message}" end end # get network hosts by session def network_hosts session begin print_verbose "Retrieving network hosts for hooked browser [session: #{session}]" response = RestClient.get "#{@url}network/hosts/#{session}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} network hosts" details rescue => e print_error "Could not retrieve network hosts: #{e.message}" end end # get network services by session def network_services session begin print_verbose "Retrieving network services for hooked browser [session: #{session}]" response = RestClient.get "#{@url}network/services/#{session}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} network services" details rescue => e print_error "Could not retrieve network services: #{e.message}" end end ################################################################################ ### XssRays API ################################################################################ # get all rays def xssrays_rays_all print_verbose "Retrieving all rays" response = RestClient.get "#{@url}xssrays/rays", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} rays" details rescue => e print_error "Could not retrieve rays: #{e.message}" end # get rays by session def xssrays_rays session print_verbose "Retrieving rays for hooked browser [session: #{session}]" response = RestClient.get "#{@url}xssrays/rays/#{session}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} rays" details rescue => e print_error "Could not retrieve rays: #{e.message}" end # get all scans def xssrays_scans_all print_verbose "Retrieving all scans" response = RestClient.get "#{@url}xssrays/scans", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} scans" details rescue => e print_error "Could not retrieve scans: #{e.message}" end # get scans by session def xssrays_scans session print_verbose "Retrieving scans for hooked browser [session: #{session}]" response = RestClient.get "#{@url}xssrays/scans/#{session}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} scans" details rescue => e print_error "Could not retrieve scans: #{e.message}" end ################################################################################ ### DNS API ################################################################################ # get ruleset def dns_ruleset begin print_verbose "Retrieving DNS ruleset" response = RestClient.get "#{@url}dns/ruleset", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} rules" details rescue => e print_error "Could not retrieve DNS ruleset: #{e.message}" end end # add a rule def dns_add_rule(dns_pattern, dns_resource, dns_response) dns_response = [dns_response] if dns_response.is_a?(String) print_verbose "Adding DNS rule [pattern: #{dns_pattern}, resource: #{dns_resource}, response: #{dns_response}]" response = RestClient.post "#{@url}dns/rule?token=#{@token}", { 'pattern' => dns_pattern, 'resource' => dns_resource, 'response' => dns_response }.to_json, :content_type => :json, :accept => :json details = JSON.parse(response.body) rule_id = details['id'] if rule_id.nil? print_error("Could not add DNS rule: #{details['error']}") return details end print_good "Added rule [id: #{details['id']}]" details rescue => e print_error "Could not add DNS rule: #{e.message}" end # get rule details def dns_get_rule(id) begin print_verbose "Retrieving DNS rule details [id: #{id}]" response = RestClient.get "#{@url}dns/rule/#{id}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved rule [id: #{details['id']}]" details rescue => e print_error "Could not retrieve DNS rule: #{e.message}" end end # delete a rule def dns_delete_rule(id) response = RestClient.delete "#{@url}dns/rule/#{id}?token=#{@token}" details = JSON.parse(response.body) print_good "Deleted rule [id: #{id}]" details rescue => e print_error "Could not delete DNS rule: #{e.message}" end ################################################################################ ### Autorun ################################################################################ def autorun_rules print_verbose "Retrieving Autorun rules" response = RestClient.get "#{@url}autorun/rules", {:params => {:token => @token}} details = JSON.parse(response.body) print_good("Retrieved #{details['count']} rules") details rescue => e print_error("Could not retrieve Autorun rules: #{e.message}") end def autorun_delete_rule(id) print_verbose "Deleting Autorun rule with ID: #{id}" response = RestClient.delete "#{@url}autorun/rule/#{id}?token=#{@token}" details = JSON.parse(response.body) print_good("Deleted rule [id: #{id}]") details rescue => e print_error("Could not delete Autorun rule: #{e.message}") end def autorun_add_rule(data) print_verbose "Adding Autorun rule: #{data}" response = RestClient.post "#{@url}autorun/rule/add?token=#{@token}", data.to_json, :content_type => :json, :accept => :json details = JSON.parse(response.body) rule_id = details['rule_id'] if rule_id.nil? print_error("Could not add Autorun rule: #{details['error']}") return details end print_good("Added rule [id: #{details['id']}]") details rescue => e print_error("Could not add Autorun rule: #{e.message}") end def autorun_run_rule_on_all_browsers(rule_id) print_verbose "Running Autorun rule #{rule_id} on all browsers" response = RestClient.get "#{@url}autorun/run/#{rule_id}", {:params => {:token => @token}} details = JSON.parse(response.body) print_debug details print_good('Done') details rescue => e print_error "Could not run Autorun rule #{rule_id}: #{e.message}" end def autorun_run_rule_on_browser(rule_id, hb_id) print_verbose "Running Autorun rule #{rule_id} on browser #{hb_id}" response = RestClient.get "#{@url}autorun/run/#{rule_id}/#{hb_id}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good('Done') details rescue => e print_error "Could not run Autorun rule #{rule_id}: #{e.message}" end ################################################################################ ### WebRTC ################################################################################ # get webrtc status for hooked browser by session def webrtc_status id begin print_verbose "Retrieving status for hooked browser [id: #{id}]" response = RestClient.get "#{@url}webrtc/status/#{id}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved status for hooked browser [id: #{id}]" details rescue => e print_error "Could not retrieve status: #{e.message}" end end ################################################################################ ### Social Engineering ################################################################################ # bind dropper to path def bind(fname, path) print_verbose "Binding 'extensions/social_engineering/droppers/#{fname}' to '#{path}'" begin response = RestClient.post "#{@url}/server/bind?token=#{@token}", { 'mount' => "#{path}", 'local_file' => "#{fname}" }.to_json, :content_type => :json, :accept => :json print_good "Bound '#{fname}' successfully" if response.code == 200 rescue => e print_error "Could not bind file #{fname}: #{e.message}" end end # clone page and bind to path def clone_page(url, path, use_existing, dns_spoof) print_verbose "Binding '#{url}' to '#{path}'" begin response = RestClient.post "#{@url}/seng/clone_page?token=#{@token}", { 'mount' => "#{path}", 'url' => "#{url}", 'use_existing' => use_existing, 'dns_spoof' => dns_spoof }.to_json, :content_type => :json, :accept => :json print_good "Bound '#{url}' successfully" if response.code == 200 rescue => e print_error "Could not bind URL #{url}: #{e.message}" end end end