Path: blob/master/core/main/rest/handlers/hookedbrowsers.rb
1154 views
#1# Copyright (c) 2006-2025 Wade Alcorn - [email protected]2# Browser Exploitation Framework (BeEF) - https://beefproject.com3# See the file 'doc/COPYING' for copying permission4#56module BeEF7module Core8module Rest9class HookedBrowsers < BeEF::Core::Router::Router10config = BeEF::Core::Configuration.instance1112before do13error 401 unless params[:token] == config.get('beef.api_token')14halt 401 unless BeEF::Core::Rest.permitted_source?(request.ip)15headers 'Content-Type' => 'application/json; charset=UTF-8',16'Pragma' => 'no-cache',17'Cache-Control' => 'no-cache',18'Expires' => '0'19end2021#22# @note Get online and offline hooked browsers details (like name, version, os, ip, port, ...)23# When websockets are enabled this will allow the ws_poll_timeout config to be used to check if the browser is online or not.24#25get '/' do26if config.get('beef.http.websocket.enable') == false27online_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen >= ?', (Time.new.to_i - 15)))28offline_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen <= ?', (Time.new.to_i - 15)))29# If we're using websockets use the designated threshold timeout to determine live, instead of hardcoded 1530# Why is it hardcoded 15?31else32timeout = config.get('beef.http.websocket.ws_poll_timeout')33online_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen >= ?', (Time.new.to_i - timeout)))34offline_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen <= ?', (Time.new.to_i - timeout)))35end3637output = {38'hooked-browsers' => {39'online' => online_hooks,40'offline' => offline_hooks41}42}43output.to_json44end4546get '/:session/delete' do47hb = BeEF::Core::Models::HookedBrowser.where(session: params[:session]).first48error 401 if hb.nil?4950details = BeEF::Core::Models::BrowserDetails.where(session_id: hb.session)51details.destroy_all5253logs = BeEF::Core::Models::Log.where(hooked_browser_id: hb.id)54logs.destroy_all5556commands = BeEF::Core::Models::Command.where(hooked_browser_id: hb.id)57commands.destroy_all5859results = BeEF::Core::Models::Result.where(hooked_browser_id: hb.id)60results.destroy_all6162begin63requester = BeEF::Core::Models::Http.where(hooked_browser_id: hb.id)64requester.destroy_all65rescue StandardError66# @todo why is this error swallowed?67# the requester module may not be enabled68end6970begin71xssraysscans = BeEF::Core::Models::Xssraysscan.where(hooked_browser_id: hb.id)72xssraysscans.destroy_all7374xssraysdetails = BeEF::Core::Models::Xssraysdetail.where(hooked_browser_id: hb.id)75xssraysdetails.destroy_all76rescue StandardError => e77# @todo why is this error swallowed?78# the xssraysscan module may not be enabled79end8081hb.destroy82end8384#85# @note returns all zombies86#87get '/all' do88hbs = []89BeEF::Core::Models::HookedBrowser.all.each do |hook|90hbs << get_hb_details(hook)91end9293output = {94'count' => hbs.length,95'zombies' => hbs96}9798output.to_json99end100101#102# @note Get all the hooked browser details (plugins enabled, technologies enabled, cookies)103#104get '/:session' do105hb = BeEF::Core::Models::HookedBrowser.where(session: params[:session]).first106error 401 if hb.nil?107108details = BeEF::Core::Models::BrowserDetails.where(session_id: hb.session)109result = {}110details.each do |property|111result[property.detail_key] = property.detail_value112end113result.to_json114end115116# useful when you inject the BeEF hook in MITM situations (see MITMf) and you want to feed back117# to BeEF a more accurate OS type/version and architecture information118post '/update/:session' do119body = JSON.parse request.body.read120os = body['os']121os_version = body['os_version']122arch = body['arch']123124hb = BeEF::Core::Models::HookedBrowser.where(session: params[:session]).first125error 401 if hb.nil?126127BeEF::Core::Models::BrowserDetails.where(session_id: hb.session, detail_key: 'host.os.name').destroy128BeEF::Core::Models::BrowserDetails.where(session_id: hb.session, detail_key: 'host.os.version').destroy129# BeEF::Core::Models::BrowserDetails.first(:session_id => hb.session, :detail_key => 'Arch').destroy130131BeEF::Core::Models::BrowserDetails.create(session_id: hb.session, detail_key: 'host.os.name', detail_value: os)132BeEF::Core::Models::BrowserDetails.create(session_id: hb.session, detail_key: 'host.os.version', detail_value: os_version)133BeEF::Core::Models::BrowserDetails.create(session_id: hb.session, detail_key: 'Arch', detail_value: arch)134135# TODO: if there where any ARE rules defined for this hooked browser,136# after updating OS/arch, force a retrigger of the rule.137{ 'success' => true }.to_json138end139140def hb_to_json(hbs)141hbs_hash = {}142i = 0143hbs.each do |hb|144hbs_hash[i] = get_hb_details(hb)145i += 1146end147hbs_hash148end149150def get_hb_details(hb)151details = BeEF::Core::Models::BrowserDetails152153{154'id' => hb.id,155'session' => hb.session,156'name' => details.get(hb.session, 'browser.name'),157'version' => details.get(hb.session, 'browser.version'),158'platform' => details.get(hb.session, 'browser.platform'),159'os' => details.get(hb.session, 'host.os.name'),160'os_version' => details.get(hb.session, 'host.os.version'),161'hardware' => details.get(hb.session, 'hardware.type'),162'ip' => hb.ip,163'domain' => details.get(hb.session, 'browser.window.hostname'),164'port' => hb.port.to_s,165'page_uri' => details.get(hb.session, 'browser.window.uri'),166'firstseen' => hb.firstseen,167'lastseen' => hb.lastseen,168'date_stamp' => details.get(hb.session, 'browser.date.datestamp'),169'city' => details.get(hb.session, 'location.city'),170'country' => details.get(hb.session, 'location.country'),171'country_code' => details.get(hb.session, 'location.country.isocode')172}173end174end175end176end177end178179180