Skip to content

Commit

Permalink
Merge pull request #1858 from beefproject/fix-1851
Browse files Browse the repository at this point in the history
fixing #1851
  • Loading branch information
jcrew99 authored Jan 17, 2020
2 parents ac26273 + 9a59297 commit b84872e
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 9 deletions.
2 changes: 1 addition & 1 deletion core/main/ar-migrations/015_create_http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions extensions/requester/api/hook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ def requester_run(hb, body)
@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
Expand Down Expand Up @@ -52,6 +54,7 @@ def requester_run(hb, body)
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
Expand Down Expand Up @@ -95,6 +98,9 @@ def requester_parse_db_request(http_db_object)
@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+)/)
Expand Down Expand Up @@ -155,6 +161,9 @@ def requester_parse_db_request(http_db_object)

#@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
Expand Down
41 changes: 33 additions & 8 deletions extensions/requester/rest/requester.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,23 +82,39 @@ class RequesterRest < BeEF::Core::Router::Router
# 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
print_error e.message
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

Expand Down Expand Up @@ -195,6 +211,9 @@ class RequesterRest < BeEF::Core::Router::Router
: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)
Expand Down Expand Up @@ -238,18 +257,24 @@ def request2hash(http)

# 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'),
Expand Down
106 changes: 106 additions & 0 deletions spec/beef/extensions/requester_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,110 @@
expect(requester).to respond_to(:requester_parse_db_request)
end

# default skipped because browser hooking not working properly in travis-CI
xit '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 3


response = RestClient.get "#{RESTAPI_HOOKS}", {:params => {:token => @token}}
puts "hooks response: #{response}"
hb_details = JSON.parse(response.body)
puts "hb_details is empty: #{hb_details.empty?}"
while hb_details["hooked-browsers"]["online"].empty?
# get victim session
response = RestClient.get "#{RESTAPI_HOOKS}", {:params => {:token => @token}}
puts "hooks response: #{response}"
hb_details = JSON.parse(response.body)
puts "json: #{hb_details}"
puts "online hooked browsers empty: #{hb_details["hooked-browsers"]["online"].empty?}"


end

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
1 change: 1 addition & 0 deletions spec/support/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
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"

0 comments on commit b84872e

Please sign in to comment.