diff --git a/core/bootstrap.rb b/core/bootstrap.rb index 148136e79..290b4a554 100644 --- a/core/bootstrap.rb +++ b/core/bootstrap.rb @@ -50,4 +50,5 @@ require 'core/hbmanager' require 'core/main/rest/handlers/hookedbrowsers' require 'core/main/rest/handlers/modules' require 'core/main/rest/handlers/logs' +require 'core/main/rest/handlers/admin' require 'core/main/rest/api' diff --git a/core/main/rest/api.rb b/core/main/rest/api.rb index c6bfafa59..0f8ce0b7c 100644 --- a/core/main/rest/api.rb +++ b/core/main/rest/api.rb @@ -35,9 +35,29 @@ module BeEF end end + module RegisterAdminHandler + def self.mount_handler(server) + server.mount('/api/admin', BeEF::Core::Rest::Admin.new) + end + end + BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterHooksHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterModulesHandler, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterLogsHandler, BeEF::API::Server, 'mount_handler') + BeEF::API::Registrar.instance.register(BeEF::Core::Rest::RegisterAdminHandler, BeEF::API::Server, 'mount_handler') + + # + # Check the source IP is within the permitted subnet + # This is from extensions/admin_ui/controllers/authentication/authentication.rb + # + def self.permitted_source?(ip) + # get permitted subnet + permitted_ui_subnet = BeEF::Core::Configuration.instance.get("beef.restrictions.permitted_ui_subnet") + target_network = IPAddr.new(permitted_ui_subnet) + + # test if ip within subnet + return target_network.include?(ip) + end end end diff --git a/core/main/rest/handlers/admin.rb b/core/main/rest/handlers/admin.rb new file mode 100644 index 000000000..ac1e6c046 --- /dev/null +++ b/core/main/rest/handlers/admin.rb @@ -0,0 +1,73 @@ +# +# Copyright 2012 Wade Alcorn wade@bindshell.net +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +module BeEF + module Core + module Rest + class Admin < BeEF::Core::Router::Router + + config = BeEF::Core::Configuration.instance + + before do + # error 401 unless params[:token] == config.get('beef.api_token') + halt 401 if not BeEF::Core::Rest.permitted_source?(request.ip) + headers 'Content-Type' => 'application/json; charset=UTF-8', + 'Pragma' => 'no-cache', + 'Cache-Control' => 'no-cache', + 'Expires' => '0' + end + + # @note Authenticate using the config set username/password to retrieve the "token" used for subsquent calls. + # Return the secret token used for subsquene tAPI calls. + # + # Input must be specified in JSON format + # + # +++ Example: +++ + #POST /api/admin/login HTTP/1.1 + #Host: 127.0.0.1:3000 + #Content-Type: application/json; charset=UTF-8 + #Content-Length: 18 + # + #{"username":"beef", "password":"beef"} + #===response (snip)=== + #HTTP/1.1 200 OK + #Content-Type: application/json; charset=UTF-8 + #Content-Length: 35 + # + #{"success":"true","token":"122323121"} + # + post '/login' do + request.body.rewind + begin + data = JSON.parse request.body.read + # check username and password + if not (data['username'].eql? config.get('beef.extension.admin_ui.username') and data['password'].eql? config.get('beef.extension.admin_ui.password') ) + BeEF::Core::Logger.instance.register('Authentication', "User with ip #{request.ip} has failed to authenticate in the application.") + halt 401 + else + '{"success":"true","token":"' + config.get('beef.api_token') + '"' + end + rescue Exception => e + error 400 + end + end + + private + + end + end + end +end \ No newline at end of file diff --git a/core/main/rest/handlers/hookedbrowsers.rb b/core/main/rest/handlers/hookedbrowsers.rb index aa269ff88..89379ac7f 100644 --- a/core/main/rest/handlers/hookedbrowsers.rb +++ b/core/main/rest/handlers/hookedbrowsers.rb @@ -23,6 +23,7 @@ module BeEF before do error 401 unless params[:token] == config.get('beef.api_token') + halt 401 if not BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', diff --git a/core/main/rest/handlers/logs.rb b/core/main/rest/handlers/logs.rb index 52a64e089..848e1fd2e 100644 --- a/core/main/rest/handlers/logs.rb +++ b/core/main/rest/handlers/logs.rb @@ -23,6 +23,7 @@ module BeEF before do error 401 unless params[:token] == config.get('beef.api_token') + halt 401 if not BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', diff --git a/core/main/rest/handlers/modules.rb b/core/main/rest/handlers/modules.rb index 5afa85482..61e78209c 100644 --- a/core/main/rest/handlers/modules.rb +++ b/core/main/rest/handlers/modules.rb @@ -23,6 +23,7 @@ module BeEF before do error 401 unless params[:token] == config.get('beef.api_token') + halt 401 if not BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache',