ADD: module dynamic specs per section

This commit is contained in:
Jake Webster
2026-02-05 14:12:41 +10:00
parent 6ffc9cd192
commit 57c615daf8
12 changed files with 1200 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/browser/ (including hooked_origin).
# Branch coverage: extra post_execute for modules that set BrowserDetails when results match.
#
require_relative '../../../spec_helper'
project_root = File.expand_path('../../../../', __dir__)
browser_module_paths = Dir[File.join(project_root, 'modules/browser/**/module.rb')].sort
BRANCH_COVERAGE = {
'modules/browser/detect_wmp' => { datastore: { 'results' => 'wmp=Yes', 'wmp' => '', 'result' => '', 'cid' => '0', 'beefhook' => '1' } },
'modules/browser/detect_vlc' => { datastore: { 'results' => 'vlc=Yes', 'vlc' => '', 'result' => '', 'cid' => '0', 'beefhook' => '1' } },
'modules/browser/detect_office' => { datastore: { 'results' => 'office=Office 2016', 'result' => '', 'cid' => '0', 'beefhook' => '1' } },
'modules/browser/detect_foxit' => { datastore: { 'results' => 'foxit=Yes', 'result' => '', 'cid' => '0', 'beefhook' => '1' } },
'modules/browser/detect_activex' => { datastore: { 'results' => 'activex=Yes', 'activex' => '', 'result' => '', 'cid' => '0', 'beefhook' => '1' } }
}.freeze
browser_module_paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
branch_key = File.dirname(path).sub("#{project_root}/", '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_proto).and_return('http')
allow(config).to receive(:beef_port).and_return('3000')
allow(config).to receive(:beef_url_str).and_return('http://127.0.0.1:3000')
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
opts = described_class.options
expect(opts).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(handler).to receive(:bind_raw)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_post_execute(instance) }.not_to raise_error
end
it 'runs branch path when in BRANCH_COVERAGE' do
branch = BRANCH_COVERAGE[branch_key]
next unless described_class.method_defined?(:post_execute) && branch
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(handler).to receive(:bind_raw)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
allow(BeEF::Core::Models::BrowserDetails).to receive(:set)
instance = build_command_instance(described_class, branch[:datastore])
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
@@ -0,0 +1,72 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/chrome_extensions/.
# Each directory is tested for .options (when present) and #post_execute.
#
require_relative '../../../spec_helper'
project_root = File.expand_path('../../../../', __dir__)
chrome_module_paths = Dir[File.join(project_root, 'modules/chrome_extensions/**/module.rb')].sort
chrome_module_paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
opts = described_class.options
expect(opts).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
instance = build_command_instance(described_class, 'return' => '', 'result' => '', 'cid' => '0')
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
instance = build_command_instance(described_class, 'return' => '', 'result' => '', 'cid' => '0')
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
+76
View File
@@ -0,0 +1,76 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/debug/.
# Each directory is tested for .options (when present) and #post_execute.
# See test_beef_debugs_spec.rb for integration/E2E tests (BrowserStack).
#
require_relative '../../../spec_helper'
project_root = File.expand_path('../../../../', __dir__)
debug_module_paths = Dir[File.join(project_root, 'modules/debug/**/module.rb')].sort
debug_module_paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_port).and_return('3000')
allow(config).to receive(:beef_proto).and_return('http')
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
opts = described_class.options
expect(opts).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).and_return(nil)
allow(handler).to receive(:bind_redirect).with(anything, anything).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
+112
View File
@@ -0,0 +1,112 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/exploits/.
# Branch coverage: extra post_execute for modules with conditional branches.
#
require_relative '../../../spec_helper'
project_root = File.expand_path('../../../../', __dir__)
exploit_module_paths = Dir[File.join(project_root, 'modules/exploits/**/module.rb')].sort
BRANCH_COVERAGE = {
'modules/exploits/vtiger_crm_upload_exploit' => { datastore: { 'result' => 'ok', 'cid' => '0' } },
'modules/exploits/router/asus_rt_n12e_get_info' => {
datastore: {
'result' => '', 'results' => 'ip=192.168.1.1&clients=192.168.1.2,00:11:22:33:44:55&wanip=1.2.3.4&netmask=255.255.255.0&gateway=192.168.1.1&dns=8.8.8.8 8.8.4.4',
'beefhook' => '1', 'cid' => '0'
},
config_get: { 'beef.extension.network.enable' => true }
}
}.freeze
exploit_module_paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
branch_key = File.dirname(path).sub("#{project_root}/", '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
opts = described_class.options
expect(opts).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
instance = build_command_instance(described_class, {})
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
instance = build_command_instance(described_class, {})
expect { run_post_execute(instance) }.not_to raise_error
end
it 'runs branch path when in BRANCH_COVERAGE' do
raw = BRANCH_COVERAGE[branch_key]
next unless described_class.method_defined?(:post_execute) && raw
branches = raw.is_a?(Array) ? raw : [raw]
branches.each do |branch|
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
allow(BeEF::Core::Models::NetworkService).to receive(:create)
allow(BeEF::Core::Models::NetworkHost).to receive(:create)
allow(BeEF::Filters).to receive(:is_valid_ip?).and_return(true)
if branch[:config_get]
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:get).with(anything) do |key|
branch[:config_get].key?(key) ? branch[:config_get][key] : '127.0.0.1'
end
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
end
instance = build_command_instance(described_class, branch[:datastore])
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
end
+135
View File
@@ -0,0 +1,135 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/host/.
# Each directory is tested for .options (when present), #pre_send, and #post_execute.
# Branch coverage: extra post_execute runs for modules listed in BRANCH_COVERAGE.
#
require_relative '../../../spec_helper'
project_root = File.expand_path('../../../../', __dir__)
host_module_paths = Dir[File.join(project_root, 'modules/host/**/module.rb')].sort
# Per-module datastore + config stubs to hit conditional branches in post_execute (e.g. NetworkService/NetworkHost path).
BRANCH_COVERAGE = {
'modules/host/detect_cups' => {
datastore: { 'results' => 'proto=http&ip=1.2.3.4&port=631&cups=Installed', 'beefhook' => '1', 'result' => '', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/host/detect_airdroid' => {
datastore: { 'results' => 'proto=http&ip=1.2.3.4&port=8888&airdroid=Installed', 'airdroid' => '', 'beefhook' => '1', 'result' => '', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/host/get_internal_ip_java' => {
datastore: { 'results' => '192.168.1.1', 'Result' => '', 'result' => '', 'beefhook' => '1', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/host/get_internal_ip_webrtc' => {
datastore: { 'results' => 'IP is 192.168.1.1', 'Result' => '', 'result' => '', 'beefhook' => '1', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
}
}.freeze
host_module_paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
branch_key = File.dirname(path).sub("#{project_root}/", '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_url_str).and_return('http://127.0.0.1:3000')
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
opts = described_class.options
expect(opts).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
file_double = double('File', write: nil, close: nil)
allow(File).to receive(:open).and_return(file_double)
allow(BeEF::Core::Models::Command).to receive(:save_result)
allow_any_instance_of(described_class).to receive(:ip).and_return('0.0.0.0')
allow_any_instance_of(described_class).to receive(:timestamp).and_return('0')
# Minimal datastore so modules that call .sub/.to_s on keys don't get nil
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_post_execute(instance) }.not_to raise_error
end
it 'runs branch path when in BRANCH_COVERAGE' do
branch = BRANCH_COVERAGE[branch_key]
next unless described_class.method_defined?(:post_execute) && branch
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
file_double = double('File', write: nil, close: nil)
allow(File).to receive(:open).and_return(file_double)
allow(BeEF::Core::Models::Command).to receive(:save_result)
allow_any_instance_of(described_class).to receive(:ip).and_return('0.0.0.0')
allow_any_instance_of(described_class).to receive(:timestamp).and_return('0')
allow(BeEF::Core::Models::NetworkService).to receive(:create)
allow(BeEF::Core::Models::NetworkHost).to receive(:create)
allow(BeEF::Core::Models::BrowserDetails).to receive(:get).and_return('Linux')
allow(BeEF::Filters).to receive(:is_valid_ip?).and_return(true)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_url_str).and_return('http://127.0.0.1:3000')
allow(config).to receive(:get).with(anything) do |key|
branch[:config_get].key?(key) ? branch[:config_get][key] : '127.0.0.1'
end
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
instance = build_command_instance(described_class, branch[:datastore])
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
+98
View File
@@ -0,0 +1,98 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/ipec/.
#
require_relative '../../../spec_helper'
# Stub extensions that some ipec modules reference (not loaded in unit tests)
module BeEF
module Extension
ETag = ::Module.new unless const_defined?(:ETag)
ServerClientDnsTunnel = ::Module.new unless const_defined?(:ServerClientDnsTunnel)
end
end
BeEF::Extension::ETag.const_set(:ETagMessages, ::Class.new do
def self.instance
@instance ||= Struct.new(:messages).new({})
end
end) unless BeEF::Extension::ETag.const_defined?(:ETagMessages)
BeEF::Extension::ServerClientDnsTunnel.const_set(:Server, ::Class.new do
def self.instance
@instance ||= Struct.new(:messages).new({})
end
end) unless BeEF::Extension::ServerClientDnsTunnel.const_defined?(:Server)
project_root = File.expand_path('../../../../', __dir__)
paths = Dir[File.join(project_root, 'modules/ipec/**/module.rb')].sort
paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_port).and_return('3000')
allow(config).to receive(:beef_proto).and_return('http')
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
expect(described_class.options).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything) do |key|
case key
when 'beef.extension.etag.enable' then true
when 'beef.extension.s2c_dns_tunnel.enable' then true
when 'beef.extension.s2c_dns_tunnel.zone' then 'example.com'
else '127.0.0.1'
end
end
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
instance = build_command_instance(described_class, [{'name' => 'data', 'value' => 'test'}])
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
file_double = double('File', write: nil, close: nil)
allow(File).to receive(:open).and_return(file_double)
allow(BeEF::Core::Models::Command).to receive(:save_result)
allow_any_instance_of(described_class).to receive(:ip).and_return('0.0.0.0')
allow_any_instance_of(described_class).to receive(:timestamp).and_return('0')
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
+100
View File
@@ -0,0 +1,100 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/misc/ (including subdirs).
# Branch coverage: extra post_execute runs for modules in BRANCH_COVERAGE.
#
require_relative '../../../spec_helper'
project_root = File.expand_path('../../../../', __dir__)
paths = Dir[File.join(project_root, 'modules/misc/**/module.rb')].sort
BRANCH_COVERAGE = {
'modules/misc/wordpress_post_auth_rce' => { datastore: { 'result' => 'ok', 'cid' => '0' } }
}.freeze
paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
branch_key = File.dirname(path).sub("#{project_root}/", '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_port).and_return('3000')
allow(config).to receive(:beef_proto).and_return('http')
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
expect(described_class.options).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
allow(IO).to receive(:popen).and_return(StringIO.new(''))
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(handler).to receive(:bind_raw)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
file_double = double('File', write: nil, close: nil)
allow(File).to receive(:open).and_return(file_double)
allow(BeEF::Core::Models::Command).to receive(:save_result)
allow_any_instance_of(described_class).to receive(:ip).and_return('0.0.0.0')
allow_any_instance_of(described_class).to receive(:timestamp).and_return('0')
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_post_execute(instance) }.not_to raise_error
end
it 'runs branch path when in BRANCH_COVERAGE' do
branch = BRANCH_COVERAGE[branch_key]
next unless described_class.method_defined?(:post_execute) && branch
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(handler).to receive(:bind_raw)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
file_double = double('File', write: nil, close: nil)
allow(File).to receive(:open).and_return(file_double)
allow(BeEF::Core::Models::Command).to receive(:save_result)
allow_any_instance_of(described_class).to receive(:ip).and_return('0.0.0.0')
allow_any_instance_of(described_class).to receive(:timestamp).and_return('0')
instance = build_command_instance(described_class, branch[:datastore])
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
+199
View File
@@ -0,0 +1,199 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/network/ (including ADC).
#
require_relative '../../../spec_helper'
# Stub Dns extension so network/dns_rebinding/module.rb can load (references BeEF::Extension::Dns::Server).
unless BeEF::Extension.const_defined?(:Dns)
BeEF::Extension.const_set(:Dns, Module.new)
end
unless BeEF::Extension::Dns.const_defined?(:Server)
dns_server_instance = Object.new
def dns_server_instance.add_rule(*) 1 end
def dns_server_instance.remove_rule!(*) nil end
dns_server = Class.new do
define_singleton_method(:instance) { dns_server_instance }
end
BeEF::Extension::Dns.const_set(:Server, dns_server)
end
# Per-module datastore + config to hit conditional branches in post_execute (network extension + regex paths).
BRANCH_COVERAGE = {
'modules/network/port_scanner' => {
datastore: { 'results' => 'ip=1.2.3.4&port=HTTP: Port 80 is OPEN Apache', 'beefhook' => '1', 'result' => '', 'port' => '', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/network/ping_sweep' => {
datastore: { 'results' => 'ip=192.168.1.1&ping=10ms', 'beefhook' => '1', 'result' => '', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/network/ping_sweep_ff' => {
datastore: { 'results' => 'host=192.168.1.1 is alive', 'beefhook' => '1', 'result' => '', 'host' => '', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/network/get_http_servers' => {
datastore: { 'results' => 'proto=http&ip=1.2.3.4&port=80&url=http://1.2.3.4/', 'beefhook' => '1', 'result' => '', 'url' => '', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/network/cross_origin_scanner_cors' => {
datastore: { 'results' => 'proto=http&ip=1.2.3.4&port=80&status=200', 'beefhook' => '1', 'result' => '', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/network/detect_burp' => {
datastore: { 'results' => 'has_burp=true&response=PROXY 127.0.0.1:8080', 'beefhook' => '1', 'result' => '', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/network/get_ntop_network_hosts' => {
datastore: { 'results' => 'proto=http&ip=1.2.3.4&port=3000&data={"hostNumIpAddress":"192.168.1.1"}', 'beefhook' => '1', 'result' => '', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/network/internal_network_fingerprinting' => {
datastore: { 'results' => 'proto=http&ip=1.2.3.4&port=80&discovered=Apache&url=http://test/', 'beefhook' => '1', 'result' => '', 'discovered' => '', 'url' => '', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/network/get_proxy_servers_wpad' => [
{ datastore: { 'results' => 'proxies=PROXY 192.168.1.1:3128', 'beefhook' => '1', 'result' => '', 'cid' => '0' }, config_get: { 'beef.extension.network.enable' => true } },
{ datastore: { 'results' => 'proxies=SOCKS 192.168.1.1:1080', 'beefhook' => '1', 'result' => '', 'cid' => '0' }, config_get: { 'beef.extension.network.enable' => true } }
],
'modules/network/jslanscanner' => [
{ datastore: { 'results' => 'proto=http&ip=1.2.3.4&port=80&service=HTTP', 'beefhook' => '1', 'result' => '', 'cid' => '0' }, config_get: { 'beef.extension.network.enable' => true } },
{ datastore: { 'results' => 'ip=1.2.3.4&device=Router', 'beefhook' => '1', 'result' => '', 'cid' => '0' }, config_get: { 'beef.extension.network.enable' => true } }
],
'modules/network/fetch_port_scanner' => {
datastore: { 'result' => 'ok', 'beefhook' => '1', 'cid' => '0' },
config_get: { 'beef.extension.network.enable' => true }
},
'modules/network/cross_origin_scanner_flash' => [
{ datastore: { 'results' => 'ip=1.2.3.4&status=alive', 'result' => '', 'beefhook' => '1', 'cid' => '0' }, config_get: { 'beef.extension.network.enable' => true } },
{ datastore: { 'results' => 'proto=http&ip=1.2.3.4&port=80&title=Apache', 'result' => '', 'beefhook' => '1', 'cid' => '0' }, config_get: { 'beef.extension.network.enable' => true } }
]
}.freeze
project_root = File.expand_path('../../../../', __dir__)
paths = Dir[File.join(project_root, 'modules/network/**/module.rb')].sort
paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
branch_key = File.dirname(path).sub("#{project_root}/", '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
# Irc_nat_pinning calls sleep 30 in post_execute; stub so the suite doesn't block.
before(:each) do
allow(Kernel).to receive(:sleep)
allow_any_instance_of(described_class).to receive(:sleep).and_return(nil)
end
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_port).and_return('3000')
allow(config).to receive(:beef_proto).and_return('http')
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
expect(described_class.options).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).and_return(nil)
allow(handler).to receive(:bind_socket).and_return(nil)
allow(handler).to receive(:unbind_socket).and_return(nil)
allow(handler).to receive(:bind_cached).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything) do |key|
case key
when 'beef.extension.dns_rebinding' then { 'address_http_external' => '127.0.0.1', 'port_proxy' => '1234' }
when 'beef.module.dns_rebinding.domain' then 'example.com'
else '127.0.0.1'
end
end
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
# Dns_rebinding expects @datastore as Array of option hashes (target, domain, url_callback)
datastore = described_class.name.include?('Dns_rebinding') ? [{ 'value' => '192.168.0.1' }, { 'value' => 'example.com' }, {}] : { 'result' => '', 'results' => '', 'cid' => '0' }
instance = build_command_instance(described_class, datastore)
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:bind_socket)
allow(handler).to receive(:unbind_socket)
allow(handler).to receive(:remap)
allow(handler).to receive(:bind_cached)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
file_double = double('File', write: nil, close: nil)
allow(File).to receive(:open).and_return(file_double)
allow(BeEF::Core::Models::Command).to receive(:save_result)
allow_any_instance_of(described_class).to receive(:ip).and_return('0.0.0.0')
allow_any_instance_of(described_class).to receive(:timestamp).and_return('0')
allow(Kernel).to receive(:sleep)
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_post_execute(instance) }.not_to raise_error
end
it 'runs branch path when in BRANCH_COVERAGE' do
raw = BRANCH_COVERAGE[branch_key]
next unless described_class.method_defined?(:post_execute) && raw
branches = raw.is_a?(Array) ? raw : [raw]
branches.each do |branch|
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:bind_socket)
allow(handler).to receive(:unbind_socket)
allow(handler).to receive(:remap)
allow(handler).to receive(:bind_cached)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
file_double = double('File', write: nil, close: nil)
allow(File).to receive(:open).and_return(file_double)
allow(BeEF::Core::Models::Command).to receive(:save_result)
allow_any_instance_of(described_class).to receive(:ip).and_return('0.0.0.0')
allow_any_instance_of(described_class).to receive(:timestamp).and_return('0')
allow(Kernel).to receive(:sleep)
allow(BeEF::Core::Models::NetworkService).to receive(:create)
allow(BeEF::Core::Models::NetworkHost).to receive(:create)
allow(BeEF::Filters).to receive(:is_valid_ip?).and_return(true)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_port).and_return('3000')
allow(config).to receive(:beef_proto).and_return('http')
allow(config).to receive(:get).with(anything) do |key|
branch[:config_get] && branch[:config_get].key?(key) ? branch[:config_get][key] : '127.0.0.1'
end
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
instance = build_command_instance(described_class, branch[:datastore])
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
end
@@ -0,0 +1,72 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/persistence/.
#
require_relative '../../../spec_helper'
project_root = File.expand_path('../../../../', __dir__)
paths = Dir[File.join(project_root, 'modules/persistence/**/module.rb')].sort
paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_port).and_return('3000')
allow(config).to receive(:beef_proto).and_return('http')
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
expect(described_class.options).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything).and_return('/hook.js')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(handler).to receive(:bind_raw)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
file_double = double('File', write: nil, close: nil)
allow(File).to receive(:open).and_return(file_double)
allow(BeEF::Core::Models::Command).to receive(:save_result)
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'cid' => '0')
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
@@ -0,0 +1,69 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/phonegap/.
# Some modules use #callback instead of #post_execute; only post_execute is tested here.
#
require_relative '../../../spec_helper'
project_root = File.expand_path('../../../../', __dir__)
paths = Dir[File.join(project_root, 'modules/phonegap/**/module.rb')].sort
paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_proto).and_return('http')
allow(config).to receive(:beef_port).and_return('3000')
allow(config).to receive(:hook_file_path).and_return('/hook.js')
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
expect(described_class.options).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
instance = build_command_instance(described_class, 'result' => '', 'Result' => '', 'cid' => '0')
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
instance = build_command_instance(described_class, 'result' => '', 'Result' => '', 'cid' => '0')
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
@@ -0,0 +1,108 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Unit tests for every module under modules/social_engineering/.
# Branch coverage: extra post_execute for KILLFRAME / conditional paths.
#
require_relative '../../../spec_helper'
project_root = File.expand_path('../../../../', __dir__)
paths = Dir[File.join(project_root, 'modules/social_engineering/**/module.rb')].sort
BRANCH_COVERAGE = {
'modules/social_engineering/fake_lastpass' => { datastore: { 'meta' => 'KILLFRAME', 'result' => '', 'results' => '', 'answer' => '', 'cid' => '0' } },
'modules/social_engineering/fake_evernote_clipper' => { datastore: { 'meta' => 'KILLFRAME', 'result' => '', 'results' => '', 'answer' => '', 'cid' => '0' } }
}.freeze
# Modules whose pre_send needs Zip, real filesystem, or logger; skip generic pre_send example
PRE_SEND_SKIP = %w[
Firefox_extension_bindshell Firefox_extension_dropper Firefox_extension_reverse_shell
Text_to_voice Ui_abuse_ie
].freeze
paths.each do |path|
rel = path.sub("#{project_root}/", '').sub(/\.rb$/, '')
branch_key = File.dirname(path).sub("#{project_root}/", '')
require_path = File.join('../../../../', rel)
class_line = File.read(path).lines.find { |l| l =~ /\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/ }
next unless class_line
klass_name = class_line.match(/\bclass\s+(\w+)\s+<\s+BeEF::Core::Command/)[1]
require_relative require_path
mod = Object.const_get(klass_name)
RSpec.describe mod do
describe '.options' do
it 'returns an Array when defined' do
next unless described_class.respond_to?(:options)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:beef_host).and_return('127.0.0.1')
allow(config).to receive(:beef_proto).and_return('http')
allow(config).to receive(:beef_port).and_return('3000')
allow(config).to receive(:beef_url_str).and_return('http://127.0.0.1:3000')
allow(config).to receive(:get).with(anything) do |key|
key == 'beef.module.simple_hijacker.templates' ? [] : '127.0.0.1'
end
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
expect(described_class.options).to be_an(Array)
end
end
describe '#pre_send' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:pre_send)
next if PRE_SEND_SKIP.include?(described_class.name)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind).and_return(nil)
allow(handler).to receive(:bind).and_return(nil)
allow(handler).to receive(:bind_raw).with(anything, anything, anything, anything, anything).and_return(nil)
allow(handler).to receive(:remap).and_return(nil)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
config = instance_double(BeEF::Core::Configuration)
allow(config).to receive(:get).with(anything).and_return('127.0.0.1')
allow(BeEF::Core::Configuration).to receive(:instance).and_return(config)
allow(IO).to receive(:popen).and_return(StringIO.new(''))
# Many pre_send implementations expect @datastore to be an Array of option hashes (name/value)
pre_send_datastore = [
{ 'name' => 'payload', 'value' => 'cmd' },
{ 'name' => 'payload_handler', 'value' => 'http://127.0.0.1:8080' },
{ 'name' => 'extension_name', 'value' => 'TestExt' },
{ 'name' => 'xpi_name', 'value' => 'test.xpi' },
{ 'name' => 'lport', 'value' => '4444' }
]
instance = build_command_instance(described_class, pre_send_datastore)
expect { run_pre_send(instance) }.not_to raise_error
end
end
describe '#post_execute' do
it 'runs without error when defined' do
next unless described_class.method_defined?(:post_execute)
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
instance = build_command_instance(described_class, 'result' => '', 'results' => '', 'answer' => '', 'cid' => '0')
expect { run_post_execute(instance) }.not_to raise_error
end
it 'runs branch path when in BRANCH_COVERAGE' do
branch = BRANCH_COVERAGE[branch_key]
next unless described_class.method_defined?(:post_execute) && branch
handler = instance_double('AssetHandler')
allow(handler).to receive(:unbind)
allow(handler).to receive(:bind)
allow(handler).to receive(:remap)
allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(handler)
instance = build_command_instance(described_class, branch[:datastore])
expect { run_post_execute(instance) }.not_to raise_error
end
end
end
end
+58
View File
@@ -0,0 +1,58 @@
#
# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - https://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# Helpers for unit specs of command modules (modules/*/module.rb).
# Use with stubbed config; no REST/API or real server.
#
module ModuleSpecHelper
#
# Build a command instance for testing post_execute (or other instance methods).
# Uses allocate so we avoid Command#initialize reading from config.
# Set @datastore before calling post_execute; results are stored in @results via save().
#
# @param klass [Class] The command module class (e.g. Test_beef_debug)
# @param datastore [Hash] Data to set on @datastore (simulates callback data)
# @return [Object] Instance with @datastore set; call post_execute then read instance_variable_get(:@results)
#
def build_command_instance(klass, datastore = {})
instance = klass.allocate
instance.instance_variable_set(:@datastore, datastore)
instance
end
#
# Call post_execute on a command instance and return the saved results.
# Use after build_command_instance(klass, datastore).
#
# @param instance [Object] Command instance from build_command_instance
# @return [Hash, nil] The value passed to save() (stored in @results)
#
def run_post_execute(instance)
instance.post_execute
instance.instance_variable_get(:@results)
end
#
# Call pre_send on a command instance (e.g. before sending the command to the hooked browser).
# Use after build_command_instance(klass, datastore). Stub AssetHandler, Configuration, etc. before calling.
#
# @param instance [Object] Command instance from build_command_instance
#
def run_pre_send(instance)
instance.pre_send
end
end
RSpec.configure do |config|
config.include ModuleSpecHelper
# Stub Kernel.sleep for all module specs so modules that call sleep (e.g. Irc_nat_pinning's post_execute sleep 30) don't slow the suite.
config.before(:each) do |example|
if example.metadata[:file_path]&.include?('spec/beef/modules')
allow(Kernel).to receive(:sleep)
end
end
end