gauntlt 0.0.0 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. data/.gitignore +3 -0
  2. data/.gitmodules +6 -0
  3. data/.travis.yml +9 -0
  4. data/Gemfile +3 -2
  5. data/LICENSE +10 -0
  6. data/README.md +95 -0
  7. data/Rakefile +4 -0
  8. data/bin/gauntlt +51 -2
  9. data/features/attack.feature +62 -0
  10. data/features/attacks/cookies.feature +25 -0
  11. data/features/attacks/curl.feature +23 -0
  12. data/features/attacks/http_methods.feature +33 -0
  13. data/features/attacks/nmap.feature +40 -0
  14. data/features/attacks/sqlmap.feature +17 -0
  15. data/features/attacks/sslyze.feature +36 -0
  16. data/features/help.feature +37 -0
  17. data/features/report.feature +5 -0
  18. data/features/step_definitions/aruba_extension_steps.rb +3 -0
  19. data/features/step_definitions/config_steps.rb +3 -0
  20. data/features/step_definitions/help_steps.rb +8 -0
  21. data/features/step_definitions/support_steps.rb +5 -0
  22. data/features/support/aruba.rb +5 -0
  23. data/features/support/attack_steps.rb +1 -0
  24. data/features/support/env.rb +1 -0
  25. data/features/support/hooks.rb +3 -0
  26. data/features/support/profile/profile.xml +5 -0
  27. data/gauntlt.gemspec +13 -8
  28. data/gem_tasks/cucumber.rake +5 -0
  29. data/gem_tasks/rspec.rake +6 -0
  30. data/lib/gauntlt.rb +35 -1
  31. data/lib/gauntlt/attack.rb +32 -0
  32. data/lib/gauntlt/attack_adapters/cookies.rb +11 -0
  33. data/lib/gauntlt/attack_adapters/curl.rb +3 -0
  34. data/lib/gauntlt/attack_adapters/http_methods.rb +12 -0
  35. data/lib/gauntlt/attack_adapters/nmap.rb +14 -0
  36. data/lib/gauntlt/attack_adapters/sqlmap.rb +3 -0
  37. data/lib/gauntlt/attack_adapters/sslyze.rb +15 -0
  38. data/lib/gauntlt/attack_adapters/support/cli_helper.rb +18 -0
  39. data/lib/gauntlt/attack_adapters/support/cookie_helper.rb +27 -0
  40. data/lib/gauntlt/attack_adapters/support/env.rb +1 -0
  41. data/lib/gauntlt/attack_adapters/support/hooks.rb +3 -0
  42. data/lib/gauntlt/attack_adapters/support/nmap_helper.rb +13 -0
  43. data/lib/gauntlt/attack_adapters/support/profile_helper.rb +12 -0
  44. data/lib/gauntlt/attack_adapters/support/python_script_helper.rb +70 -0
  45. data/lib/gauntlt/attack_adapters/support/sslyze_output.README +91 -0
  46. data/lib/gauntlt/version.rb +1 -1
  47. data/spec/gauntlt/attack_spec.rb +58 -0
  48. data/spec/gauntlt_spec.rb +43 -0
  49. data/spec/spec_helper.rb +18 -0
  50. data/spec/support/mock_constants.rb +46 -0
  51. metadata +199 -12
  52. data/Gemfile.lock +0 -44
@@ -0,0 +1,37 @@
1
+ Feature: Display help info
2
+
3
+ As a user of gauntlt,
4
+ I want contextual help info,
5
+ In order to learn the options required by an attack
6
+
7
+ Scenario: A user runs the help command in the core part of gauntlt
8
+ When I run `gauntlt --help`
9
+ Then I should see a help menu that explains how to invoke gauntlt
10
+
11
+ Scenario: A user runs the help command for a certain test
12
+ When I run `gauntlt attack -h -n nmap`
13
+ Then the output should contain:
14
+ """
15
+ Command 'attack':
16
+ """
17
+
18
+ Scenario: A user runs gauntlt without any arguments
19
+ When I run `gauntlt`
20
+ Then I should see a help menu that explains how to invoke gauntlt
21
+
22
+ Scenario: A user runs the attack command without specifying attack name
23
+ When I run `gauntlt attack`
24
+ Then the output should contain:
25
+ """
26
+ Available attacks:
27
+
28
+ cookies
29
+ curl
30
+ http_methods
31
+ nmap
32
+ sqlmap
33
+ sslyze
34
+
35
+ try: gauntlt attack -n nmap
36
+ """
37
+
@@ -0,0 +1,5 @@
1
+ # Feature: Report details of security behaviour
2
+ #
3
+ # In order to document and analyze security behaviour,
4
+ # As a software developer or security expert,
5
+ # I want to generate a report.
@@ -0,0 +1,3 @@
1
+ Then /^it should pass$/ do
2
+ assert_success(true)
3
+ end
@@ -0,0 +1,3 @@
1
+ Given /^an attack "(.*?)" exists$/ do |attack_name|
2
+ Gauntlt.should have_attack(attack_name)
3
+ end
@@ -0,0 +1,8 @@
1
+ Then /^I should see a help menu that explains how to invoke gauntlt$/ do
2
+ steps %q{
3
+ Then the output should contain:
4
+ """
5
+ -h, --help
6
+ """
7
+ }
8
+ end
@@ -0,0 +1,5 @@
1
+ Then /^debug$/ do
2
+ require 'debugger'
3
+ debugger
4
+ nil
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'aruba/cucumber'
2
+
3
+ Before do
4
+ @aruba_timeout_seconds = 5 # Add more time for sloooooowww networks
5
+ end
@@ -0,0 +1 @@
1
+ require 'gauntlt'
@@ -0,0 +1 @@
1
+ require 'gauntlt'
@@ -0,0 +1,3 @@
1
+ Before('@slow') do
2
+ @aruba_timeout_seconds = 10
3
+ end
@@ -0,0 +1,5 @@
1
+ <app>
2
+ <name>google</name>
3
+ <hostname>www.google.com</hostname>
4
+ <login>https://www.example.com/login.php</login>
5
+ </app>
data/gauntlt.gemspec CHANGED
@@ -5,21 +5,26 @@ require "gauntlt/version"
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "gauntlt"
7
7
  s.version = Gauntlt::VERSION
8
- s.authors = ["James Wickett"]
8
+ s.authors = ["James Wickett", "Mani Tadayon"]
9
9
  s.email = ["james@ruggeddevops.org"]
10
10
  s.homepage = ""
11
- s.summary = %q{the security testing tool using cucumber}
12
- s.description = %q{Using standard Gherkin language to define security tests, gauntlet happily wraps cucumber functionality and provides a security testing framework that security engineers, developers and operations teams can collaborate on together.}
11
+ s.summary = %q{behaviour-driven security using cucumber}
12
+ s.description = %q{Using standard Gherkin language to define security tests, gauntlt happily wraps cucumber functionality and provides a security testing framework that security engineers, developers and operations teams can collaborate on together.}
13
13
 
14
- s.rubyforge_project = "gauntlt"
15
-
16
- s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec}/*`.split("\n")
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
17
  s.require_paths = ["lib"]
20
18
 
21
19
  # specify any dependencies here; for example:
22
- # s.add_development_dependency "rspec"
20
+ s.add_development_dependency "cucumber"
21
+ s.add_development_dependency "rspec"
22
+ s.add_development_dependency "aruba"
23
+ s.add_development_dependency "rake"
24
+
23
25
  s.add_runtime_dependency "cucumber"
24
26
  s.add_runtime_dependency "aruba"
27
+ s.add_runtime_dependency "curb"
28
+ s.add_runtime_dependency "acclaim"
29
+ s.add_runtime_dependency "ribbon", "0.7.0"
25
30
  end
@@ -0,0 +1,5 @@
1
+ require 'cucumber/rake/task'
2
+
3
+ Cucumber::Rake::Task.new(:features) do |t|
4
+ t.fork = false
5
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ desc "Run RSpec"
4
+ RSpec::Core::RakeTask.new do |t|
5
+ t.verbose = true
6
+ end
data/lib/gauntlt.rb CHANGED
@@ -1,5 +1,39 @@
1
1
  require "gauntlt/version"
2
2
 
3
+ require 'rubygems'
4
+ require 'cucumber'
5
+ require 'gauntlt/attack'
6
+
3
7
  module Gauntlt
4
- puts "this is gauntlt" # Your code goes here...
8
+ CURRENT_DIR = if defined?(Pathname) # ruby 1.9
9
+ Pathname.new(__FILE__).dirname.to_s
10
+ else
11
+ File.dirname(File.expand_path(__FILE__))
12
+ end
13
+
14
+ GAUNTLT_DIR = File.join(CURRENT_DIR, 'gauntlt')
15
+
16
+ ATTACKS_DIR = File.join(GAUNTLT_DIR, 'attack_adapters')
17
+
18
+ ATTACK_GLOB_PATTERN = ATTACKS_DIR + '/*.rb'
19
+
20
+ class << self
21
+ def attack_files
22
+ Dir.glob(ATTACK_GLOB_PATTERN)
23
+ end
24
+
25
+ def attacks
26
+ attack_files.map do |full_path|
27
+ File.basename(full_path, '.rb')
28
+ end.sort
29
+ end
30
+
31
+ def has_attack?(name)
32
+ attacks.include?(name)
33
+ end
34
+
35
+ def attack(name, options={})
36
+ Attack.new(name, options).run
37
+ end
38
+ end
5
39
  end
@@ -0,0 +1,32 @@
1
+ require 'cucumber'
2
+ require 'cucumber/cli/main'
3
+
4
+ module Gauntlt
5
+ class Attack
6
+ class NotFound < Exception; end
7
+
8
+ attr_accessor :name, :opts, :attack_file
9
+
10
+ def initialize(name, opts={})
11
+ if opts[:attack_file] && File.exists?( opts[:attack_file] )
12
+ self.name = name
13
+ self.opts = opts
14
+ self.attack_file = opts[:attack_file]
15
+ else
16
+ raise NotFound.new("No '#{opts[:attack_file]}' attack found")
17
+ end
18
+ end
19
+
20
+ def base_dir
21
+ File.expand_path( File.dirname(__FILE__) )
22
+ end
23
+
24
+ def attacks_dir
25
+ File.join(base_dir, "attack_adapters")
26
+ end
27
+
28
+ def run
29
+ Cucumber::Cli::Main.execute([self.attack_file, '--strict', '--require', self.attacks_dir])
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,11 @@
1
+ When /^I launch a "cookies" attack$/ do
2
+ set_cookies( cookies_for(hostname) )
3
+ end
4
+
5
+ Then /^the following cookies should be received:$/ do |table|
6
+ names = table.hashes.map{|h| h['name'] }
7
+ names.each do |name|
8
+ cookies.any?{|s| s =~ /^#{name}/}.should be_true
9
+ # TODO: check other values in table
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ Then /^the response code should be "(.*?)"$/ do |http_code|
2
+ @response.response_code.should == http_code.to_i
3
+ end
@@ -0,0 +1,12 @@
1
+ When /^"curl" is installed$/ do
2
+ ensure_cli_installed("curl")
3
+ end
4
+
5
+ When /^I launch a "curl" attack$/ do
6
+ @response = Curl::Easy.http_get(hostname)
7
+ end
8
+
9
+ When /^I launch a "curl" attack with:$/ do |command|
10
+ command.gsub!('<hostname>', hostname)
11
+ run command
12
+ end
@@ -0,0 +1,14 @@
1
+ # TODO: figure out if there's a way to namespace these step definitions
2
+
3
+ When /^"nmap" is installed$/ do
4
+ ensure_cli_installed("nmap")
5
+ end
6
+
7
+ When /^the target hostname is "(.*?)"$/ do |host|
8
+ set_hostname host
9
+ end
10
+
11
+ When /^I launch an "nmap" attack with:$/ do |command|
12
+ command.gsub!('<hostname>', hostname)
13
+ run command
14
+ end
@@ -0,0 +1,3 @@
1
+ Given /^"sqlmap" is installed$/ do
2
+ ensure_python_script_installed('sqlmap')
3
+ end
@@ -0,0 +1,15 @@
1
+ Given /^"sslyze" is installed$/ do
2
+ ensure_python_script_installed('sslyze')
3
+ end
4
+
5
+ When /^I launch an "sslyze" attack with:$/ do |command|
6
+ sslyze_path = path_to_python_script("sslyze")
7
+
8
+ command.gsub!('<hostname>', hostname)
9
+ command.gsub!('<sslyze_path>', sslyze_path)
10
+ run command
11
+ end
12
+
13
+ Then /^the key size should be at least (\d+)$/ do |arg1|
14
+ pending # express the regexp above with the code you wish you had
15
+ end
@@ -0,0 +1,18 @@
1
+ require 'English'
2
+ # English.rb adds human-readable names for things like $?, $!, etc.:
3
+ # http://www.ruby-doc.org/stdlib-1.9.3/libdoc/English/rdoc/English_rb.html
4
+
5
+ module Gauntlt
6
+ module Support
7
+ module CliHelper
8
+ def cli_installed?(bin_name)
9
+ `which #{bin_name}` && $CHILD_STATUS.success?
10
+ end
11
+
12
+ def ensure_cli_installed(bin)
13
+ raise "#{bin} is not installed or is not in your path" unless cli_installed?(bin)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ World(Gauntlt::Support::CliHelper)
@@ -0,0 +1,27 @@
1
+ require 'curb'
2
+
3
+ module CookieHelper
4
+ def cookies_for(url)
5
+ [].tap do |returner|
6
+ c = Curl::Easy.perform(url) do |curl|
7
+ curl.follow_location = true
8
+ curl.enable_cookies = true
9
+
10
+ curl.on_header do |header|
11
+ returner << "#{$1}=#{$2}" if header =~ /^Set-Cookie: ([^=]+)=([^;]+;)/
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ def cookies
18
+ raise "No cookies set" if @cookies.nil?
19
+
20
+ @cookies
21
+ end
22
+
23
+ def set_cookies(a)
24
+ @cookies = a
25
+ end
26
+ end
27
+ World(CookieHelper)
@@ -0,0 +1 @@
1
+ require 'aruba/cucumber'
@@ -0,0 +1,3 @@
1
+ Before('@slow') do
2
+ @aruba_timeout_seconds = 10
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'aruba'
2
+
3
+ module NmapHelper
4
+ def run_nmap_attack(host, opts)
5
+ args = opts.map{|k,v| "#{k} #{v}"}
6
+
7
+ command = "nmap #{args.join(' ')} #{host}"
8
+
9
+ # run is from aruba
10
+ run command
11
+ end
12
+ end
13
+ World(NmapHelper)
@@ -0,0 +1,12 @@
1
+ module ProfileHelper
2
+ def hostname
3
+ raise "No host defined" if @hostname.nil?
4
+
5
+ @hostname
6
+ end
7
+
8
+ def set_hostname(s)
9
+ @hostname = s
10
+ end
11
+ end
12
+ World(ProfileHelper)
@@ -0,0 +1,70 @@
1
+ # TODO: get this explicit require to work
2
+ # require 'gauntlt/support/cli_helper'
3
+
4
+ module Gauntlt
5
+ module Support
6
+ module PythonScriptHelper
7
+ DOWNLOAD_URLS = {
8
+ 'sslyze' => 'https://github.com/iSECPartners/sslyze',
9
+ 'sqlmap' => 'https://github.com/sqlmapproject/sqlmap'
10
+ }
11
+
12
+ def python_installed?
13
+ cli_installed?('python')
14
+ end
15
+
16
+ def shell_variable_name_for(script_name)
17
+ script_name.upcase + '_PATH'
18
+ end
19
+
20
+ def path_to_python_script(script_name)
21
+ shell_variable_name = shell_variable_name_for(script_name)
22
+ ENV[shell_variable_name]
23
+ end
24
+
25
+ def script_exists?(script_name)
26
+ path = path_to_python_script(script_name)
27
+ File.exists?(path) if path
28
+ end
29
+
30
+ def python_script_installed?(script_name)
31
+ python_installed? && script_exists?(script_name)
32
+ end
33
+
34
+ def ensure_python_script_installed(script_name, debug=false)
35
+ python_script_installed?(script_name) || begin
36
+ shell_variable_name = '$' + shell_variable_name_for(script_name)
37
+
38
+ msg = <<-EOS
39
+ #{script_name}.py not installed or #{shell_variable_name} not set!
40
+
41
+ 1. Download #{script_name} from: #{DOWNLOAD_URLS[script_name]}
42
+ 2. In your .zshrc or .bash_profile (or whatever), set #{shell_variable_name}
43
+
44
+ export #{shell_variable_name.gsub('$', '')}=/path/to/#{script_name}.py
45
+
46
+ 3. Make sure you have python installed:
47
+
48
+ $ which python
49
+
50
+
51
+ EOS
52
+
53
+ if debug
54
+ msg += <<-EOS
55
+ python installed : #{python_installed?}
56
+ script_exists? : #{script_exists?(script_name)}
57
+ shell_variable_name: #{shell_variable_name_for(script_name)}
58
+ path: #{path_to_python_script(script_name)}
59
+ path_via_echo: #{`echo #{'$'+shell_variable_name_for(script_name)}`}
60
+ EOS
61
+ end
62
+
63
+ raise msg
64
+
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ World(Gauntlt::Support::PythonScriptHelper)