Files
beef/extensions/admin_ui/controllers/authentication/authentication.rb
2024-12-25 11:40:55 +10:00

126 lines
4.8 KiB
Ruby

#
# Copyright (c) 2006-2025 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
module BeEF
module Extension
module AdminUI
module Controllers
#
# The authentication web page for BeEF.
#
class Authentication < BeEF::Extension::AdminUI::HttpController
#
# Constructor
#
def initialize
super({
'paths' => {
'/' => method(:index),
'/login' => method(:login),
'/logout' => method(:logout)
}
})
@session = BeEF::Extension::AdminUI::Session.instance
end
# Function managing the index web page
def index
@headers['Content-Type'] = 'text/html; charset=UTF-8'
@headers['X-Frame-Options'] = 'sameorigin'
end
#
# Function managing the login
#
def login
username = @params['username-cfrm'] || ''
password = @params['password-cfrm'] || ''
@headers['Content-Type'] = 'application/json; charset=UTF-8'
@headers['X-Frame-Options'] = 'sameorigin'
@body = { success: false }.to_json
config = BeEF::Core::Configuration.instance
ua_ip = config.get('beef.http.allow_reverse_proxy') ? @request.ip : @request.get_header('REMOTE_ADDR')
# check if source IP address is permitted to authenticate
unless permitted_source?(ua_ip)
BeEF::Core::Logger.instance.register('Authentication', "IP source address (#{ua_ip}) attempted to authenticate but is not within permitted subnet.")
return
end
# check if under brute force attack
return unless BeEF::Core::Rest.timeout?('beef.extension.admin_ui.login_fail_delay',
@session.get_auth_timestamp,
->(time) { @session.set_auth_timestamp(time) })
# check username and password
unless username.eql?(config.get('beef.credentials.user')) && password.eql?(config.get('beef.credentials.passwd'))
BeEF::Core::Logger.instance.register('Authentication', "User with ip #{ua_ip} has failed to authenticate in the application.")
return
end
# establish an authenticated session
@session.set_logged_in(ua_ip)
session_cookie_name = config.get('beef.extension.admin_ui.session_cookie_name') # get session cookie name
Rack::Utils.set_cookie_header!(@headers, session_cookie_name, { value: @session.get_id, path: '/', httponly: true })
BeEF::Core::Logger.instance.register('Authentication', "User with ip #{ua_ip} has successfully authenticated in the application.")
@body = { success: true }.to_json
end
#
# Function managing the logout
#
def logout
@body = { success: true }.to_json
unless @session.valid_nonce?(@request)
print_error 'invalid nonce'
return
end
unless @session.valid_session?(@request)
print_error 'invalid session'
return
end
@headers['Content-Type'] = 'application/json; charset=UTF-8'
@headers['X-Frame-Options'] = 'sameorigin'
# set the session to be log out
@session.set_logged_out
# clean up UA and expire the session cookie
config = BeEF::Core::Configuration.instance
session_cookie_name = config.get('beef.extension.admin_ui.session_cookie_name') # get session cookie name
Rack::Utils.set_cookie_header!(@headers, session_cookie_name, { value: '', path: '/', httponly: true, expires: Time.now })
ua_ip = config.get('beef.http.allow_reverse_proxy') ? @request.ip : @request.get_header('REMOTE_ADDR')
BeEF::Core::Logger.instance.register('Authentication', "User with ip #{ua_ip} has successfully logged out.")
end
#
# Check the UI browser source IP is within the permitted subnet
#
def permitted_source?(ip)
return false unless BeEF::Filters.is_valid_ip?(ip)
permitted_ui_subnet = BeEF::Core::Configuration.instance.get('beef.restrictions.permitted_ui_subnet')
return false if permitted_ui_subnet.nil?
return false if permitted_ui_subnet.empty?
permitted_ui_subnet.each do |subnet|
return true if IPAddr.new(subnet).include?(ip)
end
false
end
end
end
end
end
end