@@ -56,19 +56,17 @@ ZombieTab_Requester = function(zombie) {
|
||||
********************************************/
|
||||
var history_panel_store = new Ext.ux.data.PagingJsonStore({
|
||||
storeId: 'requester-history-store-zombie-'+zombie.session,
|
||||
url: '<%= @base_path %>/requester/history.json',
|
||||
proxy: new Ext.data.HttpProxy({
|
||||
method: 'GET',
|
||||
url: '/api/requester/requests/' + zombie.session + '?token=' + beefwui.get_rest_token(),
|
||||
}),
|
||||
remoteSort: false,
|
||||
autoDestroy: true,
|
||||
autoLoad: false,
|
||||
root: 'history',
|
||||
root: 'requests',
|
||||
|
||||
fields: ['proto', 'domain', 'port', 'method', 'request_date', 'response_date','id', 'has_ran', 'path','response_status_code', 'response_status_text', 'response_port_status'],
|
||||
sortInfo: {field: 'request_date', direction: 'DESC'},
|
||||
|
||||
baseParams: {
|
||||
nonce: Ext.get("nonce").dom.value,
|
||||
zombie_session: zombie.session
|
||||
}
|
||||
});
|
||||
|
||||
var req_pagesize = 30;
|
||||
@@ -183,10 +181,9 @@ ZombieTab_Requester = function(zombie) {
|
||||
title: 'History',
|
||||
items:[history_panel_grid],
|
||||
layout: 'fit',
|
||||
|
||||
listeners: {
|
||||
activate: function(history_panel) {
|
||||
history_panel.items.items[0].store.reload({params:{url:'<%= @base_path %>/requester/history.json'}});
|
||||
history_panel.items.items[0].store.reload({params: {nonce: Ext.get("nonce").dom.value}});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -207,7 +204,7 @@ ZombieTab_Requester = function(zombie) {
|
||||
var form = new Ext.FormPanel({
|
||||
title: 'Forge Raw HTTP Request',
|
||||
id: 'requester-request-form-zombie'+zombie.session,
|
||||
url: '<%= @base_path %>/requester/send',
|
||||
url: '/api/requester/send/' + zombie.session + '?token=' + beefwui.get_rest_token(),
|
||||
hideLabels : true,
|
||||
border: false,
|
||||
padding: '3px 5px 0 5px',
|
||||
@@ -243,8 +240,7 @@ ZombieTab_Requester = function(zombie) {
|
||||
|
||||
form.submit({
|
||||
params: {
|
||||
nonce: Ext.get("nonce").dom.value,//insert the nonce with the form
|
||||
zombie_session: zombie.session,
|
||||
raw_request: Ext.getCmp('raw-request-zombie-'+zombie.session).getValue(),
|
||||
proto: proto
|
||||
},
|
||||
success: function() {
|
||||
@@ -277,14 +273,10 @@ ZombieTab_Requester = function(zombie) {
|
||||
function deleteResponse(request, zombie, bar) {
|
||||
|
||||
Ext.Ajax.request({
|
||||
url: '<%= @base_path %>/requester/delete',
|
||||
url: '/api/requester/response/' + request.id + '?token=' + beefwui.get_rest_token(),
|
||||
method: 'DELETE',
|
||||
loadMask: true,
|
||||
|
||||
params: {
|
||||
nonce: Ext.get("nonce").dom.value,
|
||||
http_id: request.id
|
||||
},
|
||||
|
||||
success: function(response) {
|
||||
var xhr = Ext.decode(response.responseText);
|
||||
if (xhr['success'] == 'true') {
|
||||
@@ -310,14 +302,8 @@ ZombieTab_Requester = function(zombie) {
|
||||
bar.update_sending('Getting response...');
|
||||
|
||||
Ext.Ajax.request({
|
||||
url: '<%= @base_path %>/requester/response.json',
|
||||
url: '/api/requester/response/' + request.id + '?token=' + beefwui.get_rest_token(),
|
||||
loadMask: true,
|
||||
|
||||
params: {
|
||||
nonce: Ext.get("nonce").dom.value,
|
||||
http_id: request.id
|
||||
},
|
||||
|
||||
success: function(response) {
|
||||
var xhr = Ext.decode(response.responseText);
|
||||
|
||||
|
||||
@@ -192,13 +192,18 @@ module BeEF
|
||||
|
||||
def get_tunneling_proxy
|
||||
proxy_browser = HB.first(:is_proxy => true)
|
||||
if (proxy_browser != nil)
|
||||
proxy_browser_id = proxy_browser.id.to_s
|
||||
else
|
||||
proxy_browser_id = 1
|
||||
print_debug "[PROXY] Proxy browser not set. Defaulting to browser id #1"
|
||||
unless proxy_browser.nil?
|
||||
return proxy_browser.session.to_s
|
||||
end
|
||||
proxy_browser_id
|
||||
|
||||
hooked_browser = HB.first
|
||||
unless hooked_browser.nil?
|
||||
print_debug "[Proxy] Proxy browser not set. Defaulting to first hooked browser [id: #{hooked_browser.session}]"
|
||||
return hooked_browser.session
|
||||
end
|
||||
|
||||
print_error '[Proxy] No hooked browsers'
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,30 +6,23 @@
|
||||
module BeEF
|
||||
module Extension
|
||||
module Requester
|
||||
|
||||
module RegisterHttpHandler
|
||||
|
||||
BeEF::API::Registrar.instance.register(BeEF::Extension::Requester::RegisterHttpHandler, BeEF::API::Server, 'mount_handler')
|
||||
|
||||
# We register the http handler for the requester.
|
||||
# This http handler will retrieve the http responses for all requests
|
||||
def self.mount_handler(beef_server)
|
||||
beef_server.mount('/requester', BeEF::Extension::Requester::Handler)
|
||||
beef_server.mount('/api/requester', BeEF::Extension::Requester::RequesterRest.new)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module RegisterPreHookCallback
|
||||
|
||||
BeEF::API::Registrar.instance.register(BeEF::Extension::Requester::RegisterPreHookCallback, BeEF::API::Server::Hook, 'pre_hook_send')
|
||||
|
||||
def self.pre_hook_send(hooked_browser, body, params, request, response)
|
||||
dhook = BeEF::Extension::Requester::API::Hook.new
|
||||
dhook.requester_run(hooked_browser, body)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,7 +20,7 @@ module BeEF
|
||||
@body = body
|
||||
# Generate all the requests and output them to the hooked browser
|
||||
output = []
|
||||
BeEF::Core::Models::Http.all(:hooked_browser_id => hb.id, :has_ran => "waiting").each { |h|
|
||||
BeEF::Core::Models::Http.all(:hooked_browser_id => hb.session, :has_ran => "waiting").each { |h|
|
||||
output << self.requester_parse_db_request(h)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2006-2019 Wade Alcorn - wade@bindshell.net
|
||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||
# See the file 'doc/COPYING' for copying permission
|
||||
#
|
||||
module BeEF
|
||||
module Extension
|
||||
module AdminUI
|
||||
module Controllers
|
||||
|
||||
#
|
||||
# HTTP Controller for the Requester component of BeEF.
|
||||
#
|
||||
class Requester < BeEF::Extension::AdminUI::HttpController
|
||||
|
||||
# Variable representing the Http DB model.
|
||||
H = BeEF::Core::Models::Http
|
||||
|
||||
def initialize
|
||||
super({
|
||||
'paths' => {
|
||||
'/send' => method(:send_request),
|
||||
'/delete' => method(:delete_zombie_response),
|
||||
'/history.json' => method(:get_zombie_history),
|
||||
'/response.json' => method(:get_zombie_response)
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
def err_msg(error)
|
||||
print_error "[REQUESTER] #{error}"
|
||||
end
|
||||
|
||||
# Send a new http request to the hooked browser.
|
||||
def send_request
|
||||
# validate that the hooked browser's session has been sent
|
||||
zombie_session = @params['zombie_session'] || nil
|
||||
(self.err_msg "Invalid session id";return @body = '{success : false}') if not BeEF::Filters.is_valid_hook_session_id?(zombie_session)
|
||||
|
||||
# validate that the hooked browser exists in the db
|
||||
zombie = Z.first(:session => zombie_session) || nil
|
||||
(self.err_msg "Invalid hooked browser session";return @body = '{success : false}') if zombie.nil?
|
||||
|
||||
# validate that the raw request has been sent
|
||||
raw_request = @params['raw_request'] || nil
|
||||
(self.err_msg "raw_request is nil";return @body = '{success : false}') if raw_request.nil?
|
||||
(self.err_msg "raw_request contains non-printable chars";return @body = '{success : false}') if not BeEF::Filters.has_non_printable_char?(raw_request)
|
||||
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
(self.err_msg "nonce is nil";return @body = '{success : false}') if nonce.nil?
|
||||
(self.err_msg "nonce incorrect";return @body = '{success : false}') if @session.get_nonce != nonce
|
||||
|
||||
# validate that the raw request is correct and can be used
|
||||
req_parts = raw_request.split(/ |\n/) # break up the request
|
||||
|
||||
verb = req_parts[0]
|
||||
self.err_msg 'Only HEAD, GET, POST, OPTIONS, PUT or DELETE requests are supported' if not BeEF::Filters.is_valid_verb?(verb) #check verb
|
||||
|
||||
uri = req_parts[1]
|
||||
(self.err_msg 'Invalid URI';return @body = '{success : false}') if not BeEF::Filters.is_valid_url?(uri) #check uri
|
||||
|
||||
version = req_parts[2]
|
||||
(self.err_msg 'Invalid HTTP version';return @body = '{success : false}') if not BeEF::Filters.is_valid_http_version?(version) # check http version - HTTP/1.0 or HTTP/1.1
|
||||
|
||||
host_str = req_parts[3]
|
||||
(self.err_msg 'Invalid HTTP Host Header';return @body = '{success : false}') if not BeEF::Filters.is_valid_host_str?(host_str) # check host string - Host:
|
||||
|
||||
host = req_parts[4]
|
||||
host_parts = host.split(/:/)
|
||||
hostname = host_parts[0]
|
||||
(self.err_msg 'Invalid HTTP HostName';return @body = '{success : false}') if not BeEF::Filters.is_valid_hostname?(hostname) #check the target hostname
|
||||
|
||||
hostport = host_parts[1] || nil
|
||||
if !hostport.nil?
|
||||
(self.err_msg 'Invalid HTTP HostPort';return @body = '{success : false}') if not BeEF::Filters.nums_only?(hostport) #check the target hostport
|
||||
end
|
||||
|
||||
proto = @params['proto'] || 'http'
|
||||
if proto !~ /\Ahttps?\z/
|
||||
(self.err_msg 'Invalid request protocol';return @body = '{success : false}')
|
||||
end
|
||||
|
||||
# Saves the new HTTP request.
|
||||
http = H.new(
|
||||
:request => raw_request,
|
||||
:method => verb,
|
||||
:proto => proto,
|
||||
:domain => hostname,
|
||||
:port => hostport,
|
||||
:path => uri,
|
||||
:request_date => Time.now,
|
||||
:hooked_browser_id => zombie.id,
|
||||
:allow_cross_domain => "true",
|
||||
)
|
||||
|
||||
if verb.eql? 'POST'
|
||||
req_parts.each_with_index do |value, index|
|
||||
if value.match(/^Content-Length/)
|
||||
http.content_length = req_parts[index+1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
http.save
|
||||
|
||||
@body = '{success : true}'
|
||||
end
|
||||
|
||||
# Returns a JSON object containing the history of requests sent to the zombie.
|
||||
def get_zombie_history
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
(self.err_msg "nonce is nil";return @body = '{success : false}') if nonce.nil?
|
||||
(self.err_msg "nonce incorrect";return @body = '{success : false}') if @session.get_nonce != nonce
|
||||
|
||||
# validate that the hooked browser's session has been sent
|
||||
zombie_session = @params['zombie_session'] || nil
|
||||
(self.err_msg "Zombie session is nil";return @body = '{success : false}') if zombie_session.nil?
|
||||
|
||||
# validate that the hooked browser exists in the db
|
||||
zombie = Z.first(:session => zombie_session) || nil
|
||||
(self.err_msg "Invalid hooked browser session";return @body = '{success : false}') if zombie.nil?
|
||||
|
||||
history = []
|
||||
H.all(:hooked_browser_id => zombie.id).each{|http|
|
||||
history << {
|
||||
'id' => http.id,
|
||||
'proto' => http.proto,
|
||||
'domain' => http.domain,
|
||||
'port' => http.port,
|
||||
'path' => http.path,
|
||||
'has_ran' => http.has_ran,
|
||||
'method' => http.method,
|
||||
'request_date' => http.request_date,
|
||||
'response_date' => http.response_date,
|
||||
'response_status_code' => http.response_status_code,
|
||||
'response_status_text' => http.response_status_text,
|
||||
'response_port_status' => http.response_port_status
|
||||
}
|
||||
}
|
||||
|
||||
@body = {'success' => 'true', 'history' => history}.to_json
|
||||
end
|
||||
|
||||
# Returns a JSON objecting containing the response of a request.
|
||||
def get_zombie_response
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
(self.err_msg "nonce is nil";return @body = '{success : false}') if nonce.nil?
|
||||
(self.err_msg "nonce incorrect";return @body = '{success : false}') if @session.get_nonce != nonce
|
||||
|
||||
# validate the http id
|
||||
http_id = @params['http_id'] || nil
|
||||
(self.err_msg "http_id is nil";return @body = '{success : false}') if http_id.nil?
|
||||
|
||||
# validate that the http object exist in the dabatase
|
||||
http_db = H.first(:id => http_id) || nil
|
||||
(self.err_msg "http object could not be found in the database";return @body = '{success : false}') if http_db.nil?
|
||||
|
||||
if http_db.response_data.length > (1024 * 100) #more thank 100K
|
||||
response_data = http_db.response_data[0..(1024*100)]
|
||||
response_data += "\n<---------- Response Data Truncated---------->"
|
||||
else
|
||||
response_data = http_db.response_data
|
||||
end
|
||||
|
||||
res = {
|
||||
'id' => http_db.id,
|
||||
'request' => http_db.request.force_encoding('UTF-8'),
|
||||
'response' => response_data.force_encoding('UTF-8'),
|
||||
'response_headers' => http_db.response_headers.force_encoding('UTF-8'),
|
||||
'proto' => http_db.proto.force_encoding('UTF-8'),
|
||||
'domain' => http_db.domain.force_encoding('UTF-8'),
|
||||
'port' => http_db.port.force_encoding('UTF-8'),
|
||||
'path' => http_db.path.force_encoding('UTF-8'),
|
||||
'date' => http_db.request_date,
|
||||
'has_ran' => http_db.has_ran.force_encoding('UTF-8')
|
||||
}
|
||||
|
||||
@body = {'success' => 'true', 'result' => res}.to_json
|
||||
end
|
||||
|
||||
# Deletes a response from the requester history
|
||||
def delete_zombie_response
|
||||
# validate nonce
|
||||
nonce = @params['nonce'] || nil
|
||||
(self.err_msg "nonce is nil";return @body = '{success : false}') if nonce.nil?
|
||||
(self.err_msg "nonce incorrect";return @body = '{success : false}') if @session.get_nonce != nonce
|
||||
|
||||
# validate the http id
|
||||
http_id = @params['http_id'] || nil
|
||||
(self.err_msg "http_id is nil";return @body = '{success : false}') if http_id.nil?
|
||||
|
||||
# validate that the http object exist in the dabatase
|
||||
http_db = H.first(:id => http_id) || nil
|
||||
(self.err_msg "http object could not be found in the database";return @body = '{success : false}') if http_db.nil?
|
||||
|
||||
# delete response
|
||||
http_db.destroy
|
||||
|
||||
@body = {'success' => 'true'}.to_json
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -15,3 +15,4 @@ require 'extensions/requester/models/http'
|
||||
require 'extensions/requester/api/hook'
|
||||
require 'extensions/requester/handler'
|
||||
require 'extensions/requester/api'
|
||||
require 'extensions/requester/rest/requester'
|
||||
|
||||
@@ -17,26 +17,39 @@ module BeEF
|
||||
|
||||
def initialize(data)
|
||||
@data = data
|
||||
setup()
|
||||
setup
|
||||
end
|
||||
|
||||
def setup()
|
||||
|
||||
def setup
|
||||
# validates the hook token
|
||||
beef_hook = @data['beefhook'] || nil
|
||||
(print_error "beefhook is null";return) if beef_hook.nil?
|
||||
if beef_hook.nil?
|
||||
print_error "beefhook is null"
|
||||
return
|
||||
end
|
||||
|
||||
# validates the request id
|
||||
request_id = @data['cid'] || nil
|
||||
(print_error "Original request id (command id) is null";return) if request_id.nil?
|
||||
request_id = @data['cid'].to_s
|
||||
if request_id == ''
|
||||
print_error "Original request id (command id) is null"
|
||||
return
|
||||
end
|
||||
|
||||
if !BeEF::Filters::nums_only?(request_id)
|
||||
print_error "Original request id (command id) is invalid"
|
||||
return
|
||||
end
|
||||
|
||||
# validates that a hooked browser with the beef_hook token exists in the db
|
||||
zombie_db = Z.first(:session => beef_hook) || nil
|
||||
(print_error "Invalid beefhook id: the hooked browser cannot be found in the database";return) if zombie_db.nil?
|
||||
|
||||
# validates that we have such a http request saved in the db
|
||||
http_db = H.first(:id => request_id.to_i, :hooked_browser_id => zombie_db.id) || nil
|
||||
(print_error "Invalid http_db: no such request found in the database";return) if http_db.nil?
|
||||
http_db = H.first(:id => request_id.to_i, :hooked_browser_id => zombie_db.session) || nil
|
||||
if http_db.nil?
|
||||
print_error "Invalid http_db: no such request found in the database"
|
||||
return
|
||||
end
|
||||
|
||||
# validates that the http request has not been run before
|
||||
(print_error "This http request has been saved before";return) if http_db.has_ran.eql? "complete"
|
||||
@@ -59,6 +72,7 @@ module BeEF
|
||||
if http_db.response_headers =~ /Content-Type: image/
|
||||
http_db.response_data = http_db.response_data.unpack('a*')
|
||||
end
|
||||
|
||||
http_db.save
|
||||
end
|
||||
end
|
||||
|
||||
@@ -69,8 +69,16 @@ module Models
|
||||
# The date at which the http request has been saved.
|
||||
property :request_date, DateTime, :lazy => false
|
||||
|
||||
#
|
||||
# Removes a request/response from the data store
|
||||
#
|
||||
def self.delete(id)
|
||||
(print_error "Failed to remove response. Invalid response ID."; return) if id.to_s !~ /\A\d+\z/
|
||||
r = BeEF::Core::Models::Http.get(id.to_i)
|
||||
(print_error "Failed to remove response [id: #{id}]. Response does not exist."; return) if r.nil?
|
||||
r.destroy
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,34 +13,263 @@ module BeEF
|
||||
# Filters out bad requests before performing any routing
|
||||
before do
|
||||
config = BeEF::Core::Configuration.instance
|
||||
@hb = BeEF::Core::Models::HookedBrowser
|
||||
|
||||
# Require a valid API token from a valid IP address
|
||||
halt 401 unless params[:token] == config.get('beef.api_token')
|
||||
halt 403 unless BeEF::Core::Rest.permitted_source?(request.ip)
|
||||
|
||||
H = BeEF::Core::Models::Http
|
||||
HB = BeEF::Core::Models::HookedBrowser
|
||||
|
||||
headers 'Content-Type' => 'application/json; charset=UTF-8',
|
||||
'Pragma' => 'no-cache',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Expires' => '0'
|
||||
end
|
||||
|
||||
# @TODO: Move methods from the requester controller here
|
||||
# Returns a request by ID
|
||||
get '/request/:id' do
|
||||
begin
|
||||
id = params[:id]
|
||||
raise InvalidParamError, 'id' unless BeEF::Filters::nums_only?(id)
|
||||
|
||||
requests = H.all(:id => id)
|
||||
halt 404 if requests.nil?
|
||||
|
||||
result = {}
|
||||
result[:count] = requests.length
|
||||
result[:requests] = []
|
||||
requests.each do |request|
|
||||
result[:requests] << request2hash(request)
|
||||
end
|
||||
|
||||
result.to_json
|
||||
rescue InvalidParamError => e
|
||||
print_error e.message
|
||||
halt 400
|
||||
rescue StandardError => e
|
||||
print_error "Internal error while retrieving request with id #{id} (#{e.message})"
|
||||
halt 500
|
||||
end
|
||||
end
|
||||
|
||||
# Returns all requestes given a specific hooked browser id
|
||||
get '/requests/:id' do
|
||||
begin
|
||||
id = params[:id]
|
||||
raise InvalidParamError, 'id' unless BeEF::Filters.is_valid_hook_session_id?(id)
|
||||
|
||||
requests = H.all(:hooked_browser_id => id)
|
||||
halt 404 if requests.nil?
|
||||
|
||||
result = {}
|
||||
result[:count] = requests.length
|
||||
result[:requests] = []
|
||||
requests.each do |request|
|
||||
result[:requests] << request2hash(request)
|
||||
end
|
||||
|
||||
result.to_json
|
||||
rescue InvalidParamError => e
|
||||
print_error e.message
|
||||
halt 400
|
||||
rescue StandardError => e
|
||||
print_error "Internal error while retrieving request list for hooked browser with id #{id} (#{e.message})"
|
||||
halt 500
|
||||
end
|
||||
end
|
||||
|
||||
# Return a response by ID
|
||||
get '/response/:id' do
|
||||
begin
|
||||
id = params[:id]
|
||||
raise InvalidParamError, 'id' unless BeEF::Filters::nums_only?(id)
|
||||
|
||||
responses = H.first(:id => id) || nil
|
||||
halt 404 if responses.nil?
|
||||
|
||||
result = {}
|
||||
result[:success] = 'true'
|
||||
result[:result] = response2hash(responses)
|
||||
|
||||
result.to_json
|
||||
rescue InvalidParamError => e
|
||||
print_error e.message
|
||||
halt 400
|
||||
rescue StandardError => e
|
||||
print_error "Internal error while retrieving response with id #{id} (#{e.message})"
|
||||
halt 500
|
||||
end
|
||||
end
|
||||
|
||||
# Deletes a specific response given its id
|
||||
delete '/response/:id' do
|
||||
begin
|
||||
id = params[:id]
|
||||
raise InvalidParamError, 'id' unless BeEF::Filters::nums_only?(id)
|
||||
|
||||
responses = H.first(:id => id) || nil
|
||||
halt 404 if responses.nil?
|
||||
|
||||
result = {}
|
||||
result['success'] = H.delete(id)
|
||||
result.to_json
|
||||
rescue InvalidParamError => e
|
||||
print_error e.message
|
||||
halt 400
|
||||
rescue StandardError => e
|
||||
print_error "Internal error while removing response with id #{id} (#{e.message})"
|
||||
halt 500
|
||||
end
|
||||
end
|
||||
|
||||
# Send a new HTTP request to the hooked browser
|
||||
post '/send/:id' do
|
||||
begin
|
||||
id = params[:id]
|
||||
proto = params[:proto].to_s || 'http'
|
||||
raw_request = params['raw_request'].to_s
|
||||
|
||||
zombie = HB.first(:session => id) || nil
|
||||
halt 404 if zombie.nil?
|
||||
|
||||
|
||||
|
||||
# @TODO: move most of this to the model
|
||||
|
||||
if raw_request == ''
|
||||
raise InvalidParamError, 'raw_request'
|
||||
end
|
||||
|
||||
if proto !~ /\Ahttps?\z/
|
||||
raise InvalidParamError, 'raw_request: Invalid request URL scheme'
|
||||
end
|
||||
|
||||
req_parts = raw_request.split(/ |\n/)
|
||||
|
||||
verb = req_parts[0]
|
||||
if not BeEF::Filters.is_valid_verb?(verb)
|
||||
raise InvalidParamError, 'raw_request: Only HEAD, GET, POST, OPTIONS, PUT or DELETE requests are supported'
|
||||
end
|
||||
|
||||
uri = req_parts[1]
|
||||
if not BeEF::Filters.is_valid_url?(uri)
|
||||
raise InvalidParamError, 'raw_request: Invalid URI'
|
||||
end
|
||||
|
||||
version = req_parts[2]
|
||||
if not BeEF::Filters.is_valid_http_version?(version)
|
||||
raise InvalidParamError, 'raw_request: Invalid HTTP version'
|
||||
end
|
||||
|
||||
host_str = req_parts[3]
|
||||
if not BeEF::Filters.is_valid_host_str?(host_str)
|
||||
raise InvalidParamError, 'raw_request: Invalid HTTP version'
|
||||
end
|
||||
|
||||
# Validate target hsot
|
||||
host = req_parts[4]
|
||||
host_parts = host.split(/:/)
|
||||
host_name = host_parts[0]
|
||||
host_port = host_parts[1] || nil
|
||||
|
||||
unless BeEF::Filters.is_valid_hostname?(host_name)
|
||||
raise InvalidParamError, 'raw_request: Invalid HTTP HostName'
|
||||
end
|
||||
|
||||
host_port = host_parts[1] || nil
|
||||
if host_port.nil? || !BeEF::Filters::nums_only?(host_port)
|
||||
host_port = proto.eql?('https') ? 443 : 80
|
||||
end
|
||||
|
||||
# Save the new HTTP request
|
||||
http = H.new(
|
||||
:hooked_browser_id => zombie.session,
|
||||
:request => raw_request,
|
||||
:method => verb,
|
||||
:proto => proto,
|
||||
:domain => host_name,
|
||||
:port => host_port,
|
||||
:path => uri,
|
||||
:request_date => Time.now,
|
||||
:allow_cross_domain => "true",
|
||||
)
|
||||
|
||||
if verb.eql?('POST') || verb.eql?('PUT')
|
||||
req_parts.each_with_index do |value, index|
|
||||
if value.match(/^Content-Length/i)
|
||||
http.content_length = req_parts[index+1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
http.save
|
||||
|
||||
result = request2hash(http)
|
||||
print_debug "[Requester] Sending HTTP request through zombie [ip: #{zombie.ip}] : #{result}"
|
||||
|
||||
#result.to_json
|
||||
rescue InvalidParamError => e
|
||||
print_error e.message
|
||||
halt 400
|
||||
rescue StandardError => e
|
||||
print_error "Internal error while removing network host with id #{id} (#{e.message})"
|
||||
halt 500
|
||||
end
|
||||
end
|
||||
|
||||
# Convert a request object to Hash
|
||||
def request2hash(http)
|
||||
{
|
||||
:id => http.id,
|
||||
:proto => http.proto,
|
||||
:domain => http.domain,
|
||||
:port => http.port,
|
||||
:path => http.path,
|
||||
:has_ran => http.has_ran,
|
||||
:method => http.method,
|
||||
:request_date => http.request_date,
|
||||
:response_date => http.response_date,
|
||||
:response_status_code => http.response_status_code,
|
||||
:response_status_text => http.response_status_text,
|
||||
:response_port_status => http.response_port_status
|
||||
}
|
||||
end
|
||||
|
||||
# Convert a response object to Hash
|
||||
def response2hash(http)
|
||||
if http.response_data.length > (1024 * 100) # more thank 100K
|
||||
response_data = http.response_data[0..(1024*100)]
|
||||
response_data += "\n<---------- Response Data Truncated---------->"
|
||||
else
|
||||
response_data = http.response_data
|
||||
end
|
||||
|
||||
{
|
||||
:id => http.id,
|
||||
:request => http.request.force_encoding('UTF-8'),
|
||||
:response => response_data.force_encoding('UTF-8'),
|
||||
:response_headers => http.response_headers.force_encoding('UTF-8'),
|
||||
:proto => http.proto.force_encoding('UTF-8'),
|
||||
:domain => http.domain.force_encoding('UTF-8'),
|
||||
:port => http.port.force_encoding('UTF-8'),
|
||||
:path => http.path.force_encoding('UTF-8'),
|
||||
:date => http.request_date,
|
||||
:has_ran => http.has_ran.force_encoding('UTF-8')
|
||||
}
|
||||
end
|
||||
|
||||
# Raised when invalid JSON input is passed to an /api/requester handler.
|
||||
class InvalidJsonError < StandardError
|
||||
|
||||
DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/requester handler'
|
||||
|
||||
def initialize(message = nil)
|
||||
super(message || DEFAULT_MESSAGE)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Raised when an invalid named parameter is passed to an /api/requester handler.
|
||||
class InvalidParamError < StandardError
|
||||
|
||||
DEFAULT_MESSAGE = 'Invalid parameter passed to /api/requester handler'
|
||||
|
||||
def initialize(message = nil)
|
||||
@@ -48,11 +277,8 @@ module BeEF
|
||||
message = sprintf str, message unless message.nil?
|
||||
super(message)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user