Skip to content

Commit b36c502

Browse files
authored
Merge pull request #3517 from beefproject/red/fix_xss
Patch XSS vulnerability
2 parents 56b32f5 + b98eff1 commit b36c502

4 files changed

Lines changed: 51 additions & 23 deletions

File tree

core/filters/base.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def self.is_valid_domain?(domain)
187187
def self.has_valid_browser_details_chars?(str)
188188
return false unless is_non_empty_string?(str)
189189

190-
!(str =~ %r{[^\w\d\s()-.,;:_/!\302\256]}).nil?
190+
(str =~ %r{[^\w\d\s()-.,;:_/!\302\256]}).nil?
191191
end
192192

193193
# Check for valid base details characters

core/filters/browser.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module Filters
1111
def self.is_valid_browsername?(str) # rubocop:disable Naming/PredicatePrefix
1212
return false unless is_non_empty_string?(str)
1313
return false if str.length > 2
14-
return false if has_non_printable_char?(str)
14+
return false unless has_valid_browser_details_chars?(str)
1515

1616
true
1717
end
@@ -21,7 +21,7 @@ def self.is_valid_browsername?(str) # rubocop:disable Naming/PredicatePrefix
2121
# @return [Boolean] If the string has valid Operating System name characters
2222
def self.is_valid_osname?(str) # rubocop:disable Naming/PredicatePrefix
2323
return false unless is_non_empty_string?(str)
24-
return false if has_non_printable_char?(str)
24+
return false unless has_valid_browser_details_chars?(str)
2525
return false if str.length < 2
2626

2727
true
@@ -32,7 +32,7 @@ def self.is_valid_osname?(str) # rubocop:disable Naming/PredicatePrefix
3232
# @return [Boolean] If the string has valid Hardware name characters
3333
def self.is_valid_hwname?(str) # rubocop:disable Naming/PredicatePrefix
3434
return false unless is_non_empty_string?(str)
35-
return false if has_non_printable_char?(str)
35+
return false unless has_valid_browser_details_chars?(str)
3636
return false if str.length < 2
3737

3838
true
@@ -71,7 +71,7 @@ def self.is_valid_osversion?(str) # rubocop:disable Naming/PredicatePrefix
7171
# @return [Boolean] If the string has valid browser / ua string characters
7272
def self.is_valid_browserstring?(str) # rubocop:disable Naming/PredicatePrefix
7373
return false unless is_non_empty_string?(str)
74-
return false if has_non_printable_char?(str)
74+
return false unless has_valid_browser_details_chars?(str)
7575
return false if str.length > 300
7676

7777
true
@@ -93,7 +93,7 @@ def self.is_valid_cookies?(str) # rubocop:disable Naming/PredicatePrefix
9393
# @return [Boolean] If the string has valid system platform characters
9494
def self.is_valid_system_platform?(str) # rubocop:disable Naming/PredicatePrefix
9595
return false unless is_non_empty_string?(str)
96-
return false if has_non_printable_char?(str)
96+
return false unless has_valid_browser_details_chars?(str)
9797
return false if str.length > 200
9898

9999
true

core/main/handlers/browserdetails.rb

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def setup
4444

4545
# hooked window host name
4646
log_zombie_port = 0
47-
if !@data['results']['browser.window.hostname'].nil?
47+
if !@data['results']['browser.window.hostname'].nil? && BeEF::Filters.is_valid_hostname?(@data['results']['browser.window.hostname'])
4848
log_zombie_domain = @data['results']['browser.window.hostname']
4949
elsif !@data['request'].referer.nil? and !@data['request'].referer.empty?
5050
referer = @data['request'].referer
@@ -59,7 +59,7 @@ def setup
5959
end
6060

6161
# hooked window host port
62-
if @data['results']['browser.window.hostport'].nil?
62+
if @data['results']['browser.window.hostport'].nil? || !BeEF::Filters.is_valid_port?(@data['results']['browser.window.hostport'].to_s)
6363
log_zombie_domain_parts = log_zombie_domain.split(':')
6464
log_zombie_port = log_zombie_domain_parts[1].to_i if log_zombie_domain_parts.length > 1
6565
else
@@ -92,6 +92,7 @@ def setup
9292
BD.set(session_id, 'browser.name.friendly', browser_friendly_name)
9393
else
9494
err_msg "Invalid browser name returned from the hook browser's initial connection."
95+
browser_name = 'Unknown'
9596
end
9697

9798
if BeEF::Filters.is_valid_ip?(zombie.ip)
@@ -242,11 +243,17 @@ def setup
242243
X_FORWARDED
243244
X_FORWARDED_FOR
244245
].each do |header|
245-
proxy_clients << (JSON.parse(zombie.httpheaders)[header]).to_s unless JSON.parse(zombie.httpheaders)[header].nil?
246+
val = JSON.parse(zombie.httpheaders)[header]
247+
unless val.nil?
248+
val.to_s.split(',').each do |ip|
249+
proxy_clients << ip.strip if BeEF::Filters.is_valid_ip?(ip.strip)
250+
end
251+
end
246252
end
247253

248254
# retrieve proxy server
249255
proxy_server = JSON.parse(zombie.httpheaders)['VIA'] unless JSON.parse(zombie.httpheaders)['VIA'].nil?
256+
proxy_server = nil unless proxy_server.nil? || BeEF::Filters.has_valid_browser_details_chars?(proxy_server)
250257

251258
# store and log proxy details
252259
if using_proxy == true
@@ -273,6 +280,7 @@ def setup
273280
BD.set(session_id, 'browser.version', browser_version)
274281
else
275282
err_msg "Invalid browser version returned from the hook browser's initial connection."
283+
browser_version = 'Unknown'
276284
end
277285

278286
# get and store browser string
@@ -293,7 +301,11 @@ def setup
293301

294302
# get and store browser language
295303
browser_lang = get_param(@data['results'], 'browser.language')
296-
BD.set(session_id, 'browser.language', browser_lang)
304+
if BeEF::Filters.has_valid_browser_details_chars?(browser_lang)
305+
BD.set(session_id, 'browser.language', browser_lang)
306+
else
307+
err_msg "Invalid browser language returned from the hook browser's initial connection."
308+
end
297309

298310
# get and store the cookies
299311
cookies = get_param(@data['results'], 'browser.window.cookies')
@@ -309,6 +321,7 @@ def setup
309321
BD.set(session_id, 'host.os.name', os_name)
310322
else
311323
err_msg "Invalid operating system name returned from the hook browser's initial connection."
324+
os_name = 'Unknown'
312325
end
313326

314327
# get and store the OS family
@@ -322,15 +335,28 @@ def setup
322335
# get and store the OS version
323336
# - without checks as it can be very different, for instance on linux/bsd)
324337
os_version = get_param(@data['results'], 'host.os.version')
325-
BD.set(session_id, 'host.os.version', os_version)
338+
if BeEF::Filters.has_valid_browser_details_chars?(os_version)
339+
BD.set(session_id, 'host.os.version', os_version)
340+
else
341+
err_msg "Invalid operating system version returned from the hook browser's initial connection."
342+
os_version = 'Unknown'
343+
end
326344

327-
# get and store the OS arch - without checks
345+
# get and store the OS arch
328346
os_arch = get_param(@data['results'], 'host.os.arch')
329-
BD.set(session_id, 'host.os.arch', os_arch)
347+
if BeEF::Filters.has_valid_browser_details_chars?(os_arch)
348+
BD.set(session_id, 'host.os.arch', os_arch)
349+
else
350+
err_msg "Invalid operating system architecture returned from the hook browser's initial connection."
351+
end
330352

331353
# get and store default browser
332354
default_browser = get_param(@data['results'], 'host.software.defaultbrowser')
333-
BD.set(session_id, 'host.software.defaultbrowser', default_browser)
355+
if BeEF::Filters.has_valid_browser_details_chars?(default_browser)
356+
BD.set(session_id, 'host.software.defaultbrowser', default_browser)
357+
else
358+
err_msg "Invalid default browser returned from the hook browser's initial connection."
359+
end
334360

335361
# get and store the hardware type
336362
hw_type = get_param(@data['results'], 'hardware.type')

extensions/admin_ui/media/javascript/ui/panel/zombiesTreeList.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -467,36 +467,38 @@ try{
467467
}
468468

469469
// set zombie hover balloon text for tree node
470+
// Use Ext.util.Format.htmlEncode() to prevent XSS via malicious browser properties
471+
var encode = Ext.util.Format.htmlEncode;
470472
var balloon_text = "";
471-
balloon_text += hooked_browser.ip;
473+
balloon_text += encode(hooked_browser.ip);
472474
balloon_text += "<hr/>"
473475
balloon_text += "<img width='13px' height='13px' class='zombie-tree-icon' src='<%= @base_path %>/media/images/favicon.png' /> ";
474-
balloon_text += "Origin: " + hooked_browser.domain + ":" + hooked_browser.port;
476+
balloon_text += "Origin: " + encode(hooked_browser.domain) + ":" + encode(hooked_browser.port);
475477
balloon_text += "<br/>";
476478
balloon_text += "<img width='13px' height='13px' class='zombie-tree-icon' src='<%= @base_path %>/media/images/icons/" + escape(browser_icon) + "' /> ";
477-
balloon_text += "Browser: " + hooked_browser.browser_name + " " + hooked_browser.browser_version;
479+
balloon_text += "Browser: " + encode(hooked_browser.browser_name) + " " + encode(hooked_browser.browser_version);
478480
balloon_text += "<br/>";
479481
balloon_text += " <img width='13px' height='13px' class='zombie-tree-icon' src='<%= @base_path %>/media/images/icons/" + escape(os_icon) + "' /> ";
480482
if (hooked_browser.os_version == 'Unknown') {
481-
balloon_text += "OS: " + hooked_browser.os_name;
483+
balloon_text += "OS: " + encode(hooked_browser.os_name);
482484
} else {
483-
balloon_text += "OS: " + hooked_browser.os_name + ' ' + hooked_browser.os_version;
485+
balloon_text += "OS: " + encode(hooked_browser.os_name) + ' ' + encode(hooked_browser.os_version);
484486
}
485487
balloon_text += "<br/>";
486488
balloon_text += " <img width='13px' height='13px' class='zombie-tree-icon' src='<%= @base_path %>/media/images/icons/" + escape(hw_icon) + "' /> ";
487-
balloon_text += "Hardware: " + hooked_browser.hw_name;
489+
balloon_text += "Hardware: " + encode(hooked_browser.hw_name);
488490
balloon_text += "<br/>";
489491

490492
if ( !hooked_browser.country || !hooked_browser.country_code || hooked_browser.country == 'Unknown' ) {
491493
balloon_text += " <img width='13px' height='13px' class='zombie-tree-icon' src='<%= @base_path %>/media/images/icons/unknown.png' /> ";
492494
balloon_text += "Location: Unknown";
493495
} else {
494496
balloon_text += " <img width='13px' height='13px' class='zombie-tree-icon' src='<%= @base_path %>/media/images/icons/country-squared/" + escape(hooked_browser.country_code.toLowerCase()) + ".svg' /> ";
495-
balloon_text += "Location: " + hooked_browser.city + ", " + hooked_browser.country;
497+
balloon_text += "Location: " + encode(hooked_browser.city) + ", " + encode(hooked_browser.country);
496498
}
497499

498500
balloon_text += "<hr/>";
499-
balloon_text += "Local Date: " + hooked_browser.date;
501+
balloon_text += "Local Date: " + encode(hooked_browser.date);
500502
hooked_browser.qtip = balloon_text;
501503

502504
// set zombie text label for tree node
@@ -511,7 +513,7 @@ try{
511513
text += "<img width='13px' height='13px' class='zombie-tree-icon' src='<%= @base_path %>/media/images/icons/country-squared/" + escape(hooked_browser.country_code.toLowerCase()) + ".svg' /> ";
512514
}
513515

514-
text += hooked_browser.ip;
516+
text += encode(hooked_browser.ip);
515517
hooked_browser.text = text;
516518

517519
//save a new online HB

0 commit comments

Comments
 (0)