Merge branch 'rspec-conversion'

* Converted tests to rspec for future releases + travis integration.
* Files remaining in test/ are integrations that require verification if they are still relevant/working.
This commit is contained in:
Ben Passmore
2019-09-26 13:40:29 +10:00
59 changed files with 1287 additions and 1970 deletions

View File

@@ -0,0 +1,62 @@
#
# Copyright (c) 2006-2017 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - http://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
RSpec.describe 'BeEF API Rate Limit' do
before(:all) do
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
@config = BeEF::Core::Configuration.instance
http_hook_server = BeEF::Core::Server.instance
http_hook_server.prepare
BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server)
@pid = fork do
http_hook_server.start
end
# wait for server to start
sleep 1
end
after(:all) do
Process.kill("INT",@pid)
end
it 'adheres to auth rate limits' do
passwds = (1..9).map { |i| "broken_pass"}
passwds.push BEEF_PASSWD
apis = passwds.map { |pswd| BeefRestClient.new('http', ATTACK_DOMAIN, '3000', BEEF_USER, pswd) }
l = apis.length
(0..2).each do |again| # multiple sets of auth attempts
# first pass -- apis in order, valid passwd on 9th attempt
# subsequent passes apis shuffled
puts "speed requesets" # all should return 401
(0..50).each do |i|
# t = Time.now()
#puts "#{i} : #{t - t0} : #{apis[i%l].auth()[:payload]}"
test_api = apis[i%l]
expect(test_api.auth()[:payload]).to eql("401 Unauthorized") # all (unless the valid is first 1 in 10 chance)
# t0 = t
end
# again with more time between calls -- there should be success (1st iteration)
puts "delayed requests"
(0..(l*2)).each do |i|
# t = Time.now()
#puts "#{i} : #{t - t0} : #{apis[i%l].auth()[:payload]}"
test_api = apis[i%l]
if (test_api.is_pass?(BEEF_PASSWD))
expect(test_api.auth()[:payload]["success"]).to be(true) # valid pass should succeed
else
expect(test_api.auth()[:payload]).to eql("401 Unauthorized")
end
sleep(0.5)
# t0 = t
end
apis.shuffle! # new order for next iteration
apis.reverse if (apis[0].is_pass?(BEEF_PASSWD)) # prevent the first from having valid passwd
end # multiple sets of auth attempts
end
end

View File

@@ -0,0 +1,22 @@
RSpec.describe 'BeEF Extensions' do
it 'loaded successfully' do
expect {
BeEF::Extensions.load
}.to_not raise_error
exts = BeEF::Core::Configuration.instance.get('beef.extension').select{|k,v|
v['enable']
}
expect(exts.length).to be > 0
exts.each do |k,v|
expect(v).to have_key('name')
expect(v).to have_key('enable')
expect(v).to have_key('loaded')
expect(v['loaded']).to be(true)
end
end
end

View File

@@ -0,0 +1,354 @@
RSpec.describe 'BeEF Filters' do
context 'is_non_empty_string?' do
it 'nil' do
expect(BeEF::Filters::is_non_empty_string?(nil)).to be(false)
end
it 'Integer' do
expect(BeEF::Filters::is_non_empty_string?(1)).to be(false)
end
it 'Empty String' do
expect(BeEF::Filters::is_non_empty_string?("")).to be(false)
end
it 'null' do
expect(BeEF::Filters::is_non_empty_string?("\x00")).to be(true)
end
it 'First char is num' do
expect(BeEF::Filters::is_non_empty_string?("0")).to be(true)
end
it 'First char is alpha' do
expect(BeEF::Filters::is_non_empty_string?("A")).to be(true)
end
it 'Four num chars' do
expect(BeEF::Filters::is_non_empty_string?("3333")).to be(true)
end
it 'Four num chars begining with alpha' do
expect(BeEF::Filters::is_non_empty_string?("A3333")).to be(true)
end
it 'Four num chars begining with null' do
expect(BeEF::Filters::is_non_empty_string?("\x003333")).to be(true)
end
end
context 'only?' do
it 'success' do
expect(BeEF::Filters::only?('A', 'A')).to be(true)
end
it 'fail' do
expect(BeEF::Filters::only?('A', 'B')).to be(false)
end
end
context 'exists?' do
it 'success' do
expect(BeEF::Filters::exists?('A', 'A')).to be(true)
end
it 'fail' do
expect(BeEF::Filters::exists?('A', 'B')).to be(false)
end
end
context 'has_null?' do
context 'false with' do
it 'general' do
chars = [nil, "", "\x01", "\xFF", "A", "A3333", "0", "}", ".", "+", "-", "-1", "0.A", "3333", "33 33", " AAAAA", "AAAAAA "]
chars.each do |c|
expect(BeEF::Filters::has_null?(c)).to be(false)
end
end
it 'alphabet' do
(1..255).each do |c|
str = ''
str.concat(c)
expect(BeEF::Filters::has_null?(str)).to be(false)
end
end
end
context 'true with' do
it 'general' do
chars = ["\x00", "A\x00", "AAAAAA\x00", "\x00A", "\x00AAAAAAAA", "A\x00A", "AAAAA\x00AAAA", "A\n\r\x00", "\x00\n\rA", "A\n\r\x00\n\rA", "\tA\x00A"]
chars.each do |c|
expect(BeEF::Filters::has_null?(c)).to be(true)
end
end
it 'alphabet null after' do
(1..255).each do |c|
str = ''
str.concat(c)
str += "\x00"
expect(BeEF::Filters::has_null?(str)).to be(true)
end
end
it 'alphabet null before' do
(1..255).each do |c|
str = "\x00"
str.concat(c)
expect(BeEF::Filters::has_null?(str)).to be(true)
end
end
end
end
context 'has_non_printable_char?' do
context 'false with' do
it 'general' do
chars = [nil, "", "A", "A3333", "0", "}", ".", "+", "-", "-1", "0.A", "3333", " 0AAAAA", " 0AAA "]
chars.each do |c|
expect(BeEF::Filters::has_non_printable_char?(c)).to be(false)
end
end
it 'lowercase' do
('a'..'z').each do |c|
expect(BeEF::Filters::has_non_printable_char?(c)).to be(false)
end
end
it 'uppercase' do
('A'..'Z').each do |c|
expect(BeEF::Filters::has_non_printable_char?(c)).to be(false)
end
end
it 'numbers' do
('0'..'9').each do |c|
expect(BeEF::Filters::has_non_printable_char?(c)).to be(false)
end
end
end
context 'true with' do
it 'general' do
chars = ["\x00", "\x01", "\x02", "A\x03", "\x04A", "\x0033333", "\x00AAAAAA", " AAAAA\x00", "\t\x00AAAAA", "\n\x00AAAAA", "\n\r\x00AAAAAAAAA", "AAAAAAA\x00AAAAAAA", "\n\x00"]
chars.each do |c|
expect(BeEF::Filters::has_non_printable_char?(c)).to be(true)
end
end
it 'alphabet null before' do
(1..255).each do |c|
str = ''
str.concat(c)
str += "\x00"
expect(BeEF::Filters::has_non_printable_char?(str)).to be(true)
end
end
end
end
context 'nums_only?' do
it 'false with general' do
chars = [nil, 1, "", "A", "A3333", "\x003333", "}", ".", "+", "-", "-1"]
chars.each do |c|
expect(BeEF::Filters::nums_only?(c)).to be(false)
end
end
it 'true with general' do
chars = ["0", "333"]
chars.each do |c|
expect(BeEF::Filters::nums_only?(c)).to be(true)
end
end
end
context 'is_valid_float?' do
it 'false with general' do
chars = [nil, 1, "", "A", "A3333", "\x003333", "}", ".", "+", "-", "-1", "0", "333", "0.A"]
chars.each do |c|
expect(BeEF::Filters::is_valid_float?(c)).to be(false)
end
end
it 'true with general' do
chars = ["33.33", "0.0", "1.0", "0.1"]
chars.each do |c|
expect(BeEF::Filters::is_valid_float?(c)).to be(true)
end
end
end
context 'hexs_only?' do
it 'false with general' do
chars = [nil, 1, "", "\x003333", "}", ".", "+", "-", "-1", "0.A", "33.33", "0.0", "1.0", "0.1"]
chars.each do |c|
expect(BeEF::Filters::hexs_only?(c)).to be(false)
end
end
it 'true with general' do
chars = ["0123456789ABCDEFabcdef", "0", "333", "A33333", "A"]
chars.each do |c|
expect(BeEF::Filters::hexs_only?(c)).to be(true)
end
end
end
context 'first_char_is_num?' do
it 'false with general' do
chars = ["", "A", "A33333", "\x0033333"]
chars.each do |c|
expect(BeEF::Filters::first_char_is_num?(c)).to be(false)
end
end
it 'true with general' do
chars = ["333", "0AAAAAA", "0"]
chars.each do |c|
expect(BeEF::Filters::first_char_is_num?(c)).to be(true)
end
end
end
context 'has_whitespace_char?' do
it 'false with general' do
chars = ["", "A", "A33333", "\x0033333", "0", "}", ".", "+", "-", "-1", "0.A"]
chars.each do |c|
expect(BeEF::Filters::has_whitespace_char?(c)).to be(false)
end
end
it 'true with general' do
chars = ["33 33", " ", " ", " 0AAAAAAA", " 0AAAAAAA ", "\t0AAAAAAA", "\n0AAAAAAAA"]
chars.each do |c|
expect(BeEF::Filters::has_whitespace_char?(c)).to be(true)
end
end
end
context 'alphanums_only?' do
context 'false with' do
it 'general' do
chars = [nil, "", "\n", "\r", "\x01", "}", ".", "+", "-", "-1", "ee-!@$%^&*}=0.A", "33 33", " AAAA", "AAA "]
chars.each do |c|
expect(BeEF::Filters::alphanums_only?(c)).to be(false)
end
end
it 'additional nulls' do
chars = ["\x00", "A\x00", "AAAAAAAAA\x00", "\x00A", "\x00AAAAAAAAA", "A\x00A", "AAAAAAAA\x00AAAAAAAA", "A\n\r\x00", "\x00\n\rA", "A\n\r\x00\n\rA", "\tA\x00A"]
chars.each do |c|
expect(BeEF::Filters::alphanums_only?(c)).to be(false)
end
end
it 'alphabet null after' do
(1..255).each do |c|
str = ''
str.concat(c)
str += "\x00"
expect(BeEF::Filters::alphanums_only?(str)).to be(false)
end
end
it 'alphabet null before' do
(1..255).each do |c|
str = "\x00"
str.concat(c)
expect(BeEF::Filters::alphanums_only?(str)).to be(false)
end
end
it 'alphabet around null' do
(1..255).each do |c|
str = ''
str.concat(c)
str += "\x00"
str.concat(c)
expect(BeEF::Filters::alphanums_only?(str)).to be(false)
end
end
end
context 'true with' do
it 'general' do
chars = ["A", "A3333", "0", "3333"]
chars.each do |c|
expect(BeEF::Filters::alphanums_only?(c)).to be(true)
end
end
it 'uppercase' do
('A'..'Z').each do |c|
expect(BeEF::Filters::alphanums_only?(c)).to be(true)
end
end
it 'lowercase' do
('a'..'z').each do |c|
expect(BeEF::Filters::alphanums_only?(c)).to be(true)
end
end
it 'numbers' do
('0'..'9').each do |c|
expect(BeEF::Filters::alphanums_only?(c)).to be(true)
end
end
end
end
context 'has_valid_param_chars?' do
it 'false' do
chars = [nil, "", "+"]
chars.each do |c|
expect(BeEF::Filters::has_valid_param_chars?(c)).to be(false)
end
end
it 'true' do
expect(BeEF::Filters::has_valid_param_chars?("A")).to be(true)
end
end
end

View File

@@ -0,0 +1,34 @@
RSpec.describe 'BeEF BrowserDetails' do
before(:all) do
@session = (0...10).map { ('a'..'z').to_a[rand(26)] }.join
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
end
it 'set nil value' do
BeEF::Core::Models::BrowserDetails.set(@session, 'key_with_nil_value', nil)
expect(BeEF::Core::Models::BrowserDetails.get(@session, 'key_with_nil_value')).to be_empty
end
it 'set value' do
key_name = (0...10).map { ('a'..'z').to_a[rand(26)] }.join
key_value = (0...10).map { ('a'..'z').to_a[rand(26)] }.join
BeEF::Core::Models::BrowserDetails.set(@session, key_name, key_value)
expect(BeEF::Core::Models::BrowserDetails.get(@session, key_name)).to eql(key_value)
end
it 'update value' do
key_name = (0...10).map { ('a'..'z').to_a[rand(26)] }.join
original_key_value = (0...10).map { ('a'..'z').to_a[rand(26)] }.join
BeEF::Core::Models::BrowserDetails.set(@session, key_name, original_key_value).to_s
expect(BeEF::Core::Models::BrowserDetails.get(@session, key_name)).to eql(original_key_value)
new_key_value = (0...10).map { ('a'..'z').to_a[rand(26)] }.join
BeEF::Core::Models::BrowserDetails.set(@session, key_name, new_key_value).to_s
expect(BeEF::Core::Models::BrowserDetails.get(@session, key_name)).to_not eql(original_key_value)
expect(BeEF::Core::Models::BrowserDetails.get(@session, key_name)).to eql(new_key_value)
end
end

View File

@@ -0,0 +1,82 @@
RSpec.describe 'BeEF Dynamic Reconsturction' do
before(:all) do
@port = 2001
config = {}
config[:BindAddress] = '127.0.0.1'
config[:Port] = @port.to_s
@mounts = {}
@mounts['/test'] = BeEF::Core::NetworkStack::Handlers::DynamicReconstruction.new
@rackApp = Rack::URLMap.new(@mounts)
Thin::Logging.silent = true
@server = Thin::Server.new('127.0.0.1', @port.to_s, @rackApp)
trap("INT") { @server.stop }
trap("TERM") { @server.stop }
@pid = fork do
@server.start!
end
# wait for server to start
sleep 1
end
after(:all) do
Process.kill("INT",@pid)
end
it 'delete' do
response = Curl::Easy.http_delete("http://127.0.0.1:#{@port}/test")
expect(response.response_code).to eql(404)
end
it 'put' do
response = Curl::Easy.http_put("http://127.0.0.1:#{@port}/test", nil)
expect(response.response_code).to eql(404)
end
it 'head' do
response = Curl::Easy.http_head("http://127.0.0.1:#{@port}/test")
expect(response.response_code).to eql(404)
end
context 'get' do
it 'no params' do
response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test")
expect(response.response_code).to eql(404)
end
it 'zero values' do
response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test?bh=0&sid=0&pid=0&pc=0&d=0")
expect(response.response_code).to eql(200)
expect(response.body_str).to be_empty
end
it 'one values' do
response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test?bh=1&sid=1&pid=1&pc=1&d=1")
expect(response.response_code).to eql(200)
expect(response.body_str).to be_empty
end
it 'negative one values' do
response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test?bh=-1&sid=-1&pid=-1&pc=-1&d=-1")
expect(response.response_code).to eql(200)
expect(response.body_str).to be_empty
end
# Fails gracefully
it 'ascii values' do
response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test?bh=z&sid=z&pid=z&pc=z&d=z")
expect(response.response_code).to eql(200)
expect(response.body_str).to be_empty
end
# Fails gracefully
it 'array values' do
response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test?bh[]=1&sid[]=1&pid[]=1&pc[]=1&d[]=1")
expect(response.response_code).to eql(200)
expect(response.body_str).to be_empty
end
end
end

View File

@@ -0,0 +1,33 @@
RSpec.describe 'BeEF Redirector' do
before(:all) do
@port = 2002
config = {}
config[:BindAddress] = '127.0.0.1'
config[:Port] = @port.to_s
@mounts = {}
@mounts['/test'] = BeEF::Core::NetworkStack::Handlers::Redirector.new('http://www.beefproject.com')
@rackApp = Rack::URLMap.new(@mounts)
Thin::Logging.silent = true
@server = Thin::Server.new('127.0.0.1', @port.to_s, @rackApp)
trap("INT") { @server.stop }
trap("TERM") { @server.stop }
@pid = fork do
@server.start!
end
# wait for server to start
sleep 0.8
end
after(:all) do
Process.kill("INT",@pid)
end
it 'redirects' do
response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test/")
expect(response.response_code).to eql(302)
expect(response.body_str).to eql("302 found")
expect(response.header_str).to match(/Location: http:\/\/www.beefproject\.com/)
end
end

View File

@@ -0,0 +1,48 @@
RSpec.describe 'BeEF Modules' do
it 'loaded successfully' do
expect {
BeEF::Modules.load
}.to_not raise_error
modules = BeEF::Core::Configuration.instance.get('beef.module').select do |k,v|
v['enable'] == true and v['category'] != nil
end
expect(modules.length).to be > 0
modules.each do |k,v|
expect(BeEF::Module.is_present(k)).to be(true)
expect(BeEF::Module.is_enabled(k)).to be(true)
expect {
BeEF::Module.hard_load(k)
}.to_not raise_error
expect(BeEF::Module.is_loaded(k)).to be(true)
BeEF::Core::Configuration.instance.get("beef.module.#{k}.target").each do |k,v|
expect(v).to_not be_empty
end
end
end
it 'safe client debug log' do
Dir['../../modules/**/*.js'].each do |path|
next unless File.file?(path)
File.open(path) do |f|
f.grep(/\bconsole\.log\W*\(/m) do |line|
fail "Function 'console.log' instead of 'beef.debug' inside\n Path: #{path}\nLine: #{line}"
end
end
end
end
it 'safe variable decleration' do
Dir['../../modules/**/*.js'].each do |path|
next unless File.file?(path)
File.open(path) do |f|
f.grep(/\blet\W+[a-zA-Z0-9_\.]+\W*=/) do |line|
fail "Variable declared with 'let' instead of 'var' inside\n Path: #{path}\nLine: #{line}"
end
end
end
end
end

View File

@@ -0,0 +1,15 @@
RSpec.describe 'BeEF Extension Console' do
before(:all) do
@config = BeEF::Core::Configuration.instance
@config.load_extensions_config
end
it 'loads configuration' do
expect(@config.get('beef.extension.console')).to have_key('enable')
console_shell = @config.get('beef.extension.console.shell')
expect(console_shell).to have_key('historyfolder')
expect(console_shell).to have_key('historyfile')
end
end

View File

@@ -0,0 +1,340 @@
require 'resolv'
require 'extensions/dns/extension.rb'
RSpec.describe 'BeEF Extension DNS' do
IN = Resolv::DNS::Resource::IN
before(:all) do
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
@config = BeEF::Core::Configuration.instance
@config.load_extensions_config
@dns = BeEF::Extension::Dns::Server.instance
end
it 'loaded configuration' do
config = @config.get('beef.extension.dns')
expect(config).to have_key('protocol')
expect(config).to have_key('address')
expect(config).to have_key('port')
expect(config).to have_key('upstream')
end
it 'responds to interfaces' do
expect(@dns).to respond_to(:add_rule)
expect(@dns).to respond_to(:get_rule)
expect(@dns).to respond_to(:remove_rule!)
expect(@dns).to respond_to(:get_ruleset)
expect(@dns).to respond_to(:remove_ruleset!)
end
context 'add good rule' do
it '1.2.3.4' do
id = nil
response = '1.2.3.4'
expect {
id = @dns.add_rule(
:pattern => 'foo.bar',
:resource => IN::A,
:response => [response] ) do |transaction|
transaction.respond!(response)
end
}.to_not raise_error
expect(id).to_not be_nil
end
it '9.9.9.9' do
id = nil
response = '9.9.9.9'
expect {
id = @dns.add_rule(
:pattern => %r{i\.(love|hate)\.beef\.com?},
:resource => IN::A,
:response => [response] ) do |transaction|
transaction.respond!(response)
end
}.to_not raise_error
expect(id).to_not be_nil
end
it 'domains' do
response = '9.9.9.9'
domains = %w(
i.hate.beef.com
i.love.beef.com
i.love.beef.co
i.love.beef.co )
domains.each do |d|
id = nil
expect {
id = @dns.add_rule(
:pattern => %r{i\.(love|hate)\.beef\.com?},
:resource => IN::A,
:response => [response] ) do |transaction|
transaction.respond!(response)
end
}.to_not raise_error
expect(id).to_not be_nil
end
end
context 'add bad rule' do
it '4.2.4.2' do
id = nil
same_id = nil
pattern = 'j.random.hacker'
response = '4.2.4.2'
expect {
id = @dns.add_rule(
:pattern => pattern,
:resource => IN::A,
:response => [response] ) do |transaction|
transaction.respond!(response)
end
}.to_not raise_error
expect {
same_id = @dns.add_rule(
:pattern => pattern,
:resource => IN::A,
:response => [response] ) do |transaction|
transaction.respond!(response)
end
}.to_not raise_error
expect {
same_id = @dns.add_rule(
:pattern => pattern,
:resource => IN::A,
:response => [response] ) do |transaction|
transaction.respond!(response)
end
}.to_not raise_error
expect(id).to eql(same_id)
end
end
end
it 'id format' do
pattern = 'dead.beef'
response = '2.2.2.2'
id = nil
expect {
id = @dns.add_rule(
:pattern => pattern,
:resource => IN::A,
:response => [response] ) do |transaction|
transaction.respond!(response)
end
}.to_not raise_error
expect(id.length).to eql(8)
expect(id).to match(/^\h{8}$/)
end
it 'get good rule' do
pattern = 'be.ef'
response = '1.1.1.1'
id = nil
expect {
id = @dns.add_rule(
:pattern => pattern,
:resource => IN::A,
:response => [response] ) do |transaction|
transaction.respond!(response)
end
}.to_not raise_error
expect(id).to_not be_nil
rule = @dns.get_rule(id)
expect(rule).to be_a(Hash)
expect(rule.length).to be > 0
expect(rule).to have_key(:id)
expect(rule).to have_key(:pattern)
expect(rule).to have_key(:resource)
expect(rule).to have_key(:response)
expect(rule[:id]).to eql(id)
expect(rule[:pattern]).to eql(pattern)
expect(rule[:resource]).to eql('A')
expect(rule[:response]).to be_a(Array)
expect(rule[:response].length).to be > 0
expect(rule[:response].first).to eql(response)
end
it 'get bad rule' do
expect(@dns.get_rule(42)).to be_nil
end
it 'remove good rule' do
pattern = 'hack.the.gibson'
response = '1.9.9.5'
id = nil
expect {
id = @dns.add_rule(
:pattern => pattern,
:resource => IN::A,
:response => [response] ) do |transaction|
transaction.respond!(response)
end
}.to_not raise_error
expect(@dns.remove_rule!(id)).to be(true)
end
it 'remove bad rule' do
expect(@dns.remove_rule!(42)).to be_nil
end
it 'get ruleset' do
rules = [
{ pattern: 'be.ef', resource: 'A', response: '1.1.1.1' },
{ pattern: 'dead.beef', resource: 'A', response: '2.2.2.2' },
{ pattern: 'foo.bar', resource: 'A', response: '1.2.3.4' },
{ pattern: 'i\.(love|hate)\.beef.com?', resource: 'A', response: '9.9.9.9' },
{ pattern: 'j.random.hacker', resource: 'A', response: '4.2.4.2' }
]
@dns.remove_ruleset!
expect(@dns.get_ruleset.length).to eql(0)
rules.each do |r|
@dns.add_rule(
:pattern => r[:pattern],
:resource => IN::A,
:response => r[:response]
)
end
ruleset = @dns.get_ruleset
ruleset.sort! { |a, b| a[:pattern] <=> b[:pattern] }
expect(ruleset).to be_a(Array)
expect(ruleset.length).to eql(5)
rules.each_with_index do |v,i|
expect(ruleset[i][:pattern]).to eql(v[:pattern])
expect(ruleset[i][:resource]).to eql(v[:resource])
expect(ruleset[i][:response]).to eql(v[:response])
end
end
it 'remove ruleset' do
expect(@dns.remove_ruleset!).to be(true)
expect(@dns.get_ruleset.length).to eql(0)
end
it 'failure types' do
end
end
# Tests each supported type of query failure
# def test_13_failure_types
# begin
# id = @@dns.add_rule(
# :pattern => 'noerror.beef.com',
# :resource => IN::A,
# :response => ['1.2.3.4'] ) do |transaction|
# transaction.failure!(:NoError)
# end
# #check_failure_status(id, :NoError)
# end
#
# begin
# id = @@dns.add_rule(
# :pattern => 'formerr.beef.com',
# :resource => IN::A,
# :response => ['1.2.3.4'] ) do |transaction|
# transaction.failure!(:FormErr)
# end
## #check_failure_status(id, :FormErr)
# end
#
# begin
# id = @@dns.add_rule(
# :pattern => 'servfail.beef.com',
# :resource => IN::A,
# :response => ['1.2.3.4'] ) do |transaction|
# transaction.failure!(:ServFail)
# end
# #check_failure_status(id, :ServFail)
# end
#
# begin
# id = @@dns.add_rule(
# :pattern => 'nxdomain.beef.com',
# :resource => IN::A,
# :response => ['1.2.3.4'] ) do |transaction|
# transaction.failure!(:NXDomain)
# end
# #check_failure_status(id, :NXDomain)
# end
#
# begin
# id = @@dns.add_rule(
# :pattern => 'notimp.beef.com',
# :resource => IN::A,
## :response => ['1.2.3.4'] ) do |transaction|
# transaction.failure!(:NotImp)
# end
# #check_failure_status(id, :NotImp)
# end
#
# begin
# id = @@dns.add_rule(
# :pattern => 'refused.beef.com',
# :resource => IN::A,
# :response => ['1.2.3.4'] ) do |transaction|
### transaction.failure!(:Refused)
# end
# #check_failure_status(id, :Refused)
# end
#
# begin
# id = @@dns.add_rule(
# :pattern => 'notauth.beef.com',
# :resource => IN::A,
# :response => ['1.2.3.4'] ) do |transaction|
# transaction.failure!(:NotAuth)
# end
## #check_failure_status(id, :NotAuth)
# end
# end
#
## private
##
# # Confirms that a query for the rule given in 'id' returns a 'resource' failure status
## def check_failure_status(id, resource)
## rule = @@dns.get_rule(id)
# status = resource.to_s.force_encoding('UTF-8').upcase
# assert_equal(status, rule[:response][0])
#
# check_dns_response(/status: #{status}/, rule[:resource], rule[:pattern])
# end
#
# # Compares output of dig command against regex
# def check_dns_response(regex, type, pattern)
# address = @@config.get('beef.extension.dns.address')
# port = @@config.get('beef.extension.dns.port')
### dig_output = IO.popen(["dig", "@#{address}", "-p", "#{port}", "-t", "#{type}", "#{pattern}"], 'r+').read
# assert_match(regex, dig_output)
# end
##
##end
###

View File

@@ -0,0 +1,20 @@
require 'extensions/ipec/extension'
RSpec.describe 'BeEF Extension IPEC' do
before(:all) do
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
@config = BeEF::Core::Configuration.instance
@config.load_extensions_config
end
it 'loads configuration' do
expect(@config.get('beef.extension.ipec')).to have_key('enable')
end
it 'interface' do
expect(BeEF::Extension::Ipec::JunkCalculator.instance).to respond_to(:bind_junk_calculator)
end
end

View File

@@ -0,0 +1,26 @@
require 'extensions/network/models/network_service'
require 'extensions/network/models/network_host'
RSpec.describe 'BeEF Extension Network' do
before(:all) do
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
end
it 'add good host' do
expect {
BeEF::Core::Models::NetworkHost.add(:hooked_browser_id => '1234', :ip => '127.0.0.1')
}.to_not raise_error
expect(BeEF::Core::Models::NetworkHost.all(hooked_browser_id: '1234', ip: '127.0.0.1')).to_not be_empty
end
it 'add good service' do
expect {
BeEF::Core::Models::NetworkService.add(:hooked_browser_id => '1234', :proto => 'http', :ip => '127.0.0.1', :port => 80, :type => 'Apache')
}.to_not raise_error
expect(BeEF::Core::Models::NetworkService.all(hooked_browser_id: '1234', ip: '127.0.0.1')).to_not be_empty
end
end

View File

@@ -0,0 +1,21 @@
require 'extensions/proxy/extension'
RSpec.describe 'BeEF Extension Proxy' do
before(:all) do
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
@config = BeEF::Core::Configuration.instance
@config.load_extensions_config
end
it 'loads configuration' do
config = @config.get('beef.extension.proxy')
expect(config).to have_key('enable')
expect(config).to have_key('address')
expect(config).to have_key('port')
expect(config).to have_key('key')
expect(config).to have_key('cert')
end
end

View File

@@ -0,0 +1,20 @@
require 'extensions/qrcode/extension'
RSpec.describe 'BeEF Extension QRCode' do
before(:all) do
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
@config = BeEF::Core::Configuration.instance
@config.load_extensions_config
end
it 'loads configuration' do
config = @config.get('beef.extension.qrcode')
expect(config).to have_key('enable')
expect(config).to have_key('targets')
expect(config).to have_key('qrsize')
expect(config).to have_key('qrborder')
end
end

View File

@@ -0,0 +1,23 @@
require 'extensions/requester/extension'
RSpec.describe 'BeEF Extension Requester' do
before(:all) do
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
@config = BeEF::Core::Configuration.instance
@config.load_extensions_config
end
it 'loads configuration' do
expect(@config.get('beef.extension.requester')).to have_key('enable')
end
it 'has interface' do
requester = BeEF::Extension::Requester::API::Hook.new
expect(requester).to respond_to(:requester_run)
expect(requester).to respond_to(:add_to_body)
expect(requester).to respond_to(:requester_parse_db_request)
end
end

View File

@@ -0,0 +1,67 @@
require 'rest-client'
RSpec.describe 'BeEF Extension WebRTC' do
before(:all) do
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
@config = BeEF::Core::Configuration.instance
@config.load_extensions_config
# json = {:username => BEEF_USER, :password => BEEF_PASSWD}.to_json
# @headers = {:content_type => :json, :accept => :json}
# response = RestClient.post("#{RESTAPI_ADMIN}/login", json, @headers)
# result = JSON.parse(response.body)
# @token = result['token']
# @activated = @config.get('beef.extension.webrtc.enable') || false
# @victim1 = BeefTest.new_victim
# @victim2 = BeefTest.new_victim
# sleep 8
# # Fetch last online browsers' ids
# rest_response = RestClient.get "#{RESTAPI_HOOKS}", {:params => { :token => @token}}
# result = JSON.parse(rest_response.body)
# browsers = result["hooked-browsers"]["online"]
# browsers.each_with_index do |elem, index|
# if index == browsers.length - 1
# @victim2id = browsers["#{index}"]["id"].to_s
# end
# if index == browsers.length - 2
# @victim1id = browsers["#{index}"]["id"].to_s
# end
# end
end
after(:all) do
# @victim1.driver.browser.close unless @victim1.nil?
# @victim2.driver.browser.close unless @victim2.nil?
end
it 'loads configuration' do
config = @config.get('beef.extension.webrtc')
expect(config).to have_key('enable')
expect(config).to have_key('stunservers')
expect(config).to have_key('turnservers')
end
# it 'check two hooked browsers' do
# expect(@activated).to be(true)
# response = nil
# expect {
# response = RestClient.get "#{RESTAPI_HOOKS}", {:params => {:token => @token}}
# }.to_not raise_error
# expect(response).to_not be_nil
# expect(response.body).to_not be_nil
# expect(response.code).to eql(200)
# result = JSON.parse(rest_response.body)
# browsers = result["hooked-browsers"]["online"]
# expect(browsers).to_not be_nil
# expect(browsers.length).to be >= 2
# end
end

View File

@@ -0,0 +1,24 @@
require 'extensions/xssrays/extension'
RSpec.describe 'BeEF Extension XSSRays' do
before(:all) do
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
@config = BeEF::Core::Configuration.instance
@config.load_extensions_config
end
it 'loads configuration' do
config = @config.get('beef.extension.xssrays')
expect(config).to have_key('enable')
expect(config).to have_key('clean_timeout')
expect(config).to have_key('cross_domain')
end
it 'interface' do
xssrays = BeEF::Extension::Xssrays::API::Scan.new
expect(xssrays).to respond_to(:start_scan)
expect(xssrays).to respond_to(:add_to_body)
end
end

View File

@@ -0,0 +1,30 @@
RSpec.describe 'BeEF Filesystem' do
def file_test(file)
expect(File.file?(file)).to be(true)
expect(File.zero?(file)).to be(false)
end
it 'required files' do
files = [
'beef',
'config.yaml',
'install'
]
files.each do |f|
file_test(f)
end
end
it 'executable directories' do
dirs = [
'core',
'modules',
'extensions'
]
dirs.each do |d|
expect(File.executable?(d)).to be(true)
end
end
end

View File

@@ -0,0 +1,17 @@
RSpec.describe 'BeEF Security Checks' do
it 'dangerous eval usage' do
Dir['**/*.rb'].each do |path|
File.open(path) do |f|
next if /#{File.basename(__FILE__)}/.match(path) # skip this file
next if /\/msf-test\//.match(path) # skip this file
next if /extensions\/dns/.match(path) # skip this file
f.grep(/\Weval\W/im) do |line|
fail "Illegal use of 'eval' found in\n Path: #{path}\nLine: #{line}"
end
end
end
end
end

30
spec/spec_helper.rb Normal file
View File

@@ -0,0 +1,30 @@
require 'core/loader.rb'
# Notes
# We need to load vairables that 'beef' usually does for us
## config
config = BeEF::Core::Configuration.new('config.yaml')
## home_dir
$home_dir = Dir.pwd
## root_dir
$root_dir = Dir.pwd
require 'core/bootstrap.rb'
require 'rack/test'
require 'curb'
require 'rest-client'
# Require supports
Dir['spec/support/*.rb'].each do |f|
require f
end
ENV['RACK_ENV'] ||= 'test'
RSpec.configure do |config|
config.disable_monkey_patching!
config.include Rack::Test::Methods
config.expect_with :rspec do |c|
c.syntax = :expect
end
end

50
spec/support/beef_test.rb Normal file
View File

@@ -0,0 +1,50 @@
#
# Copyright (c) 2006-2019 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - http://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
require 'test/unit'
require 'capybara'
require 'capybara/rspec'
Capybara.run_server = false # we need to run our own BeEF server
require 'selenium-webdriver'
class BeefTest
def self.save_screenshot(session)
Dir.mkdir(BEEF_TEST_DIR) unless File.directory?(BEEF_TEST_DIR)
session.driver.browser.save_screenshot(BEEF_TEST_DIR + Time.now.strftime("%Y-%m-%d--%H-%M-%S-%N") + ".png")
end
def self.login(session = nil)
session = Capybara::Session.new(:selenium_headless) if session.nil?
session.visit(ATTACK_URL)
sleep 2.0
session.has_content?('BeEF Authentication')
session.fill_in 'user', :with => BEEF_USER
session.fill_in 'pass', :with => BEEF_PASSWD
session.click_button('Login')
sleep 10.0
session
end
def self.logout(session)
session.click_link('Logout')
session
end
def self.new_attacker
self.login
end
def self.new_victim
victim = Capybara::Session.new(:selenium_headless)
victim.visit(VICTIM_URL)
victim
end
end

27
spec/support/constants.rb Normal file
View File

@@ -0,0 +1,27 @@
#
# Copyright (c) 2006-2019 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - http://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
BEEF_TEST_DIR = "/tmp/beef-test/"
# General constants
ATTACK_DOMAIN = "127.0.0.1"
VICTIM_DOMAIN = "localhost"
ATTACK_URL = "http://" + ATTACK_DOMAIN + ":3000/ui/panel"
VICTIM_URL = "http://" + VICTIM_DOMAIN + ":3000/demos/basic.html"
# Credentials
BEEF_USER = ENV["TEST_BEEF_USER"] || 'beef'
BEEF_PASSWD = ENV["TEST_BEEF_PASS"] || "beef"
# RESTful API root endpoints
RESTAPI_HOOKS = "http://" + ATTACK_DOMAIN + ":3000/api/hooks"
RESTAPI_LOGS = "http://" + ATTACK_DOMAIN + ":3000/api/logs"
RESTAPI_MODULES = "http://" + ATTACK_DOMAIN + ":3000/api/modules"
RESTAPI_NETWORK = "http://" + ATTACK_DOMAIN + ":3000/api/network"
RESTAPI_PROXY = "http://" + ATTACK_DOMAIN + ":3000/api/proxy"
RESTAPI_DNS = "http://" + ATTACK_DOMAIN + ":3000/api/dns"
RESTAPI_SENG = "http://" + ATTACK_DOMAIN + ":3000/api/seng"
RESTAPI_ADMIN = "http://" + ATTACK_DOMAIN + ":3000/api/admin"
RESTAPI_WEBRTC = "http://" + ATTACK_DOMAIN + ":3000/api/webrtc"

View File

@@ -0,0 +1,49 @@
#
# Copyright (c) 2006-2017 Wade Alcorn - wade@bindshell.net
# Browser Exploitation Framework (BeEF) - http://beefproject.com
# See the file 'doc/COPYING' for copying permission
#
# less noisy verson of BeeRestAPI found in tools.
class BeefRestClient
def initialize proto, host, port, user, pass
@user = user
@pass = pass
@url = "#{proto}://#{host}:#{port}/api/"
@token = nil
end
def is_pass?(passwd)
@pass == passwd
end
def auth
begin
response = RestClient.post "#{@url}admin/login",
{ 'username' => "#{@user}",
'password' => "#{@pass}" }.to_json,
:content_type => :json,
:accept => :json
result = JSON.parse(response.body)
@token = result['token']
{:success => result['success'], :payload => result}
rescue => e
{:success => false, :payload => e.message }
end
end
def version
return {:success => false, :payload => 'no token'} if @token.nil?
begin
response = RestClient.get "#{@url}server/version", {:params => {:token => @token}}
result = JSON.parse(response.body)
{:success => result['success'], :payload => result}
rescue => e
print_error "Could not retrieve BeEF version: #{e.message}"
{:success => false, :payload => e.message}
end
end
end