Path: blob/master/extensions/admin_ui/classes/httpcontroller.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#5module BeEF6module Extension7module AdminUI8#9# Handle HTTP requests and call the relevant functions in the derived classes10#11class HttpController12attr_accessor :headers, :status, :body, :paths, :currentuser, :params1314C = BeEF::Core::Models::Command15CM = BeEF::Core::Models::CommandModule16Z = BeEF::Core::Models::HookedBrowser1718#19# Class constructor. Takes data from the child class and populates itself with it.20#21def initialize(data = {})22@erubis = nil23@status = 200 if data['status'].nil?24@session = BeEF::Extension::AdminUI::Session.instance2526@config = BeEF::Core::Configuration.instance27@bp = @config.get 'beef.extension.admin_ui.base_path'2829@headers = { 'Content-Type' => 'text/html; charset=UTF-8' } if data['headers'].nil?3031@paths = if data['paths'].nil? && methods.include?('index')32{ 'index' => '/' }33else34data['paths']35end36end3738#39# Authentication check. Confirm the request to access the UI comes from a permitted IP address40#41def authenticate_request(ip)42auth = BeEF::Extension::AdminUI::Controllers::Authentication.new43auth.permitted_source?(ip)44rescue StandardError => e45print_error "authenticate_request failed: #{e.message}"46false47end4849#50# Check if reverse proxy has been enabled and return the correct client IP address51#52def get_ip(request)53if @config.get('beef.http.allow_reverse_proxy')54request.ip # Get client x-forwarded-for ip address55else56request.get_header('REMOTE_ADDR') # Get client remote ip address57end58end5960#61# Handle HTTP requests and call the relevant functions in the derived classes62#63def run(request, response)64@request = request65@params = request.params6667@body = ''6869# If access to the UI is not permitted for the request IP address return a 40470unless authenticate_request(get_ip(@request))71@status = 40472return73end7475# test if session is unauth'd and whether the auth functionality is requested76if !@session.valid_session?(@request) && !instance_of?(BeEF::Extension::AdminUI::Controllers::Authentication)77@status = 30278@headers = { 'Location' => "#{@bp}/authentication" }79return80end8182# get the mapped function (if it exists) from the derived class83path = request.path_info84unless BeEF::Filters.is_valid_path_info?(path)85print_error "[Admin UI] Path is not valid: #{path}"86return87end8889function = @paths[path] || @paths[path + '/'] # check hash for '<path>' and '<path>/'90if function.nil?91print_error "[Admin UI] Path does not exist: #{path}"92return93end9495# call the relevant mapped function96function.call9798# build the template filename and apply it - if the file exists99function_name = function.name # used for filename100class_s = self.class.to_s.sub('BeEF::Extension::AdminUI::Controllers::', '').downcase # used for directory name101template_ui = "#{$root_dir}/extensions/admin_ui/controllers/#{class_s}/#{function_name}.html"102if File.exist?(template_ui)103@eruby = Erubis::FastEruby.new(File.read(template_ui))104@body = @eruby.result(binding) unless @eruby.nil? # apply template and set the response105end106107# set appropriate content-type 'application/json' for .json files108@headers['Content-Type'] = 'application/json; charset=UTF-8' if request.path.to_s.end_with?('.json')109110# set content type111if @headers['Content-Type'].nil?112@headers['Content-Type'] = 'text/html; charset=UTF-8' # default content and charset type for all pages113end114rescue StandardError => e115print_error "Error handling HTTP request: #{e.message}"116print_error e.backtrace117end118119# Constructs a html script tag (from media/javascript directory)120def script_tag(filename)121"<script src=\"#{@bp}/media/javascript/#{filename}\" type=\"text/javascript\"></script>"122end123124# Constructs a html script tag (from media/javascript-min directory)125def script_tag_min(filename)126"<script src=\"#{@bp}/media/javascript-min/#{filename}\" type=\"text/javascript\"></script>"127end128129# Constructs a html stylesheet tag130def stylesheet_tag(filename)131"<link rel=\"stylesheet\" href=\"#{@bp}/media/css/#{filename}\" type=\"text/css\" />"132end133134# Constructs a hidden html nonce tag135def nonce_tag136"<input type=\"hidden\" name=\"nonce\" id=\"nonce\" value=\"#{@session.get_nonce}\"/>"137end138139def base_path140@bp.to_s141end142143private144145@eruby146147# Unescapes a URL-encoded string.148def unescape(s)149s.tr('+', ' ').gsub(/%([\da-f]{2})/in) { [Regexp.last_match(1)].pack('H*') }150end151end152end153end154end155156157