Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
beefproject
GitHub Repository: beefproject/beef
Path: blob/master/core/main/rest/handlers/hookedbrowsers.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 Core
9
module Rest
10
class HookedBrowsers < BeEF::Core::Router::Router
11
config = BeEF::Core::Configuration.instance
12
13
before do
14
error 401 unless params[:token] == config.get('beef.api_token')
15
halt 401 unless BeEF::Core::Rest.permitted_source?(request.ip)
16
headers 'Content-Type' => 'application/json; charset=UTF-8',
17
'Pragma' => 'no-cache',
18
'Cache-Control' => 'no-cache',
19
'Expires' => '0'
20
end
21
22
#
23
# @note Get online and offline hooked browsers details (like name, version, os, ip, port, ...)
24
# When websockets are enabled this will allow the ws_poll_timeout config to be used to check if the browser is online or not.
25
#
26
get '/' do
27
if config.get('beef.http.websocket.enable') == false
28
online_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen >= ?', (Time.new.to_i - 15)))
29
offline_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen <= ?', (Time.new.to_i - 15)))
30
# If we're using websockets use the designated threshold timeout to determine live, instead of hardcoded 15
31
# Why is it hardcoded 15?
32
else
33
timeout = config.get('beef.http.websocket.ws_poll_timeout')
34
online_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen >= ?', (Time.new.to_i - timeout)))
35
offline_hooks = hb_to_json(BeEF::Core::Models::HookedBrowser.where('lastseen <= ?', (Time.new.to_i - timeout)))
36
end
37
38
output = {
39
'hooked-browsers' => {
40
'online' => online_hooks,
41
'offline' => offline_hooks
42
}
43
}
44
output.to_json
45
end
46
47
get '/:session/delete' do
48
hb = BeEF::Core::Models::HookedBrowser.where(session: params[:session]).first
49
error 401 if hb.nil?
50
51
details = BeEF::Core::Models::BrowserDetails.where(session_id: hb.session)
52
details.destroy_all
53
54
logs = BeEF::Core::Models::Log.where(hooked_browser_id: hb.id)
55
logs.destroy_all
56
57
commands = BeEF::Core::Models::Command.where(hooked_browser_id: hb.id)
58
commands.destroy_all
59
60
results = BeEF::Core::Models::Result.where(hooked_browser_id: hb.id)
61
results.destroy_all
62
63
begin
64
requester = BeEF::Core::Models::Http.where(hooked_browser_id: hb.id)
65
requester.destroy_all
66
rescue StandardError
67
# @todo why is this error swallowed?
68
# the requester module may not be enabled
69
end
70
71
begin
72
xssraysscans = BeEF::Core::Models::Xssraysscan.where(hooked_browser_id: hb.id)
73
xssraysscans.destroy_all
74
75
xssraysdetails = BeEF::Core::Models::Xssraysdetail.where(hooked_browser_id: hb.id)
76
xssraysdetails.destroy_all
77
rescue StandardError => e
78
# @todo why is this error swallowed?
79
# the xssraysscan module may not be enabled
80
end
81
82
hb.destroy
83
end
84
85
#
86
# @note returns all zombies
87
#
88
get '/all' do
89
hbs = []
90
BeEF::Core::Models::HookedBrowser.all.each do |hook|
91
hbs << get_hb_details(hook)
92
end
93
94
output = {
95
'count' => hbs.length,
96
'zombies' => hbs
97
}
98
99
output.to_json
100
end
101
102
#
103
# @note Get all the hooked browser details (plugins enabled, technologies enabled, cookies)
104
#
105
get '/:session' do
106
hb = BeEF::Core::Models::HookedBrowser.where(session: params[:session]).first
107
error 401 if hb.nil?
108
109
details = BeEF::Core::Models::BrowserDetails.where(session_id: hb.session)
110
result = {}
111
details.each do |property|
112
result[property.detail_key] = property.detail_value
113
end
114
result.to_json
115
end
116
117
# useful when you inject the BeEF hook in MITM situations (see MITMf) and you want to feed back
118
# to BeEF a more accurate OS type/version and architecture information
119
post '/update/:session' do
120
body = JSON.parse request.body.read
121
os = body['os']
122
os_version = body['os_version']
123
arch = body['arch']
124
125
hb = BeEF::Core::Models::HookedBrowser.where(session: params[:session]).first
126
error 401 if hb.nil?
127
128
BeEF::Core::Models::BrowserDetails.where(session_id: hb.session, detail_key: 'host.os.name').destroy
129
BeEF::Core::Models::BrowserDetails.where(session_id: hb.session, detail_key: 'host.os.version').destroy
130
# BeEF::Core::Models::BrowserDetails.first(:session_id => hb.session, :detail_key => 'Arch').destroy
131
132
BeEF::Core::Models::BrowserDetails.create(session_id: hb.session, detail_key: 'host.os.name', detail_value: os)
133
BeEF::Core::Models::BrowserDetails.create(session_id: hb.session, detail_key: 'host.os.version', detail_value: os_version)
134
BeEF::Core::Models::BrowserDetails.create(session_id: hb.session, detail_key: 'Arch', detail_value: arch)
135
136
# TODO: if there where any ARE rules defined for this hooked browser,
137
# after updating OS/arch, force a retrigger of the rule.
138
{ 'success' => true }.to_json
139
end
140
141
def hb_to_json(hbs)
142
hbs_hash = {}
143
i = 0
144
hbs.each do |hb|
145
hbs_hash[i] = get_hb_details(hb)
146
i += 1
147
end
148
hbs_hash
149
end
150
151
def get_hb_details(hb)
152
details = BeEF::Core::Models::BrowserDetails
153
154
{
155
'id' => hb.id,
156
'session' => hb.session,
157
'name' => details.get(hb.session, 'browser.name'),
158
'version' => details.get(hb.session, 'browser.version'),
159
'platform' => details.get(hb.session, 'browser.platform'),
160
'os' => details.get(hb.session, 'host.os.name'),
161
'os_version' => details.get(hb.session, 'host.os.version'),
162
'hardware' => details.get(hb.session, 'hardware.type'),
163
'ip' => hb.ip,
164
'domain' => details.get(hb.session, 'browser.window.hostname'),
165
'port' => hb.port.to_s,
166
'page_uri' => details.get(hb.session, 'browser.window.uri'),
167
'firstseen' => hb.firstseen,
168
'lastseen' => hb.lastseen,
169
'date_stamp' => details.get(hb.session, 'browser.date.datestamp'),
170
'city' => details.get(hb.session, 'location.city'),
171
'country' => details.get(hb.session, 'location.country'),
172
'country_code' => details.get(hb.session, 'location.country.isocode')
173
}
174
end
175
end
176
end
177
end
178
end
179
180