gauntlt 0.0.0 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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)