concuss 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -2
- data/Gemfile.lock +1 -1
- data/README.md +30 -3
- data/bin/concuss +8 -0
- data/lib/concuss/formatters/table.rb +31 -0
- data/lib/concuss/formatters.rb +6 -0
- data/lib/concuss/headers.rb +0 -1
- data/lib/concuss/report.rb +20 -0
- data/lib/concuss/runner.rb +23 -9
- data/lib/concuss/version.rb +1 -1
- data/lib/concuss.rb +12 -4
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebbc8f1ad06752a93ba6b66ef4fa666a693532a792b71d14ff830ae1a7537494
|
4
|
+
data.tar.gz: 8a1b02193ffb5bac321fbad3a4905c7b00f9ddfec1df543ab755aba9c564b4e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9407c5f49b7dc5b2f03ad0b69e00e21b6f1940ea6167c630ffe59fd4366bd1e099c68e061fe2943c9c3c41ff4103ce781b50e9ed85a268627ab7e2fe41b0050
|
7
|
+
data.tar.gz: e891c23429f6931b81bf9b00a9b38bb4ecb361ebc3c40d35dead0b7f5510e8a7ed33cd88c27dbb532d438baed12126cabf588cf04dc82448e64b45584402a0a3
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
# Concuss
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/concuss.svg)](https://badge.fury.io/rb/concuss)
|
4
|
+
[![Build Status](https://github.com/patricktulskie/concuss/actions/workflows/main.yml/badge.svg)](https://github.com/patricktulskie/concuss/actions/workflows/main.yml)
|
5
|
+
|
3
6
|
## What is it?
|
4
7
|
|
5
8
|
Concuss is a tool for banging against a url with a bunch of different headers to look for potential vulnerabilities.
|
6
9
|
|
7
10
|
It works by sending a custom or a random string to a webserver for a specific url in a variety of headers to see if it's able to get that string to appear on the page. If so, you'll get a HIT and you can evaluate that header to see if it's useful for some kind of XSS, cache poisoning, or some other form of injection from malformed headers.
|
8
11
|
|
12
|
+
Often times web app and framework developers assume that headers from the client are not malicious or manipulated and will just write them out to the page in one form or another. This project is a specialized tool to find instances of this so that they can be fixed before they are abused.
|
13
|
+
|
9
14
|
## What it is NOT.
|
10
15
|
|
11
16
|
Concuss is not a tool for automating vulnerabilities, nor should it be used to certify that a page is safe from vulnerabilities. It should not be used on applications or website that you do not personally have permission to scan.
|
@@ -39,17 +44,39 @@ While concuss is designed to be used as a command line tool, you can also includ
|
|
39
44
|
require 'concuss'
|
40
45
|
|
41
46
|
concuss = Concuss.new(url: 'http://localhost:4567', file: 'header_file.txt', header_set: :standard, test_string: "OOGABOOGA")
|
42
|
-
concuss.attack!
|
47
|
+
report = concuss.attack!
|
43
48
|
```
|
44
49
|
|
45
|
-
|
50
|
+
From there, you'll get a `Concuss::Report` object that contains the raw data as well as filters for `hits`, `misses`, `headers`, and the `url` in the event you've done a bunch of these.
|
51
|
+
|
52
|
+
## Demo
|
53
|
+
|
54
|
+
There is a sample app with a vulnerability to test with in the `vuln_app` directory. It takes the contents of `X-CSRF-Token` and spits them out blindly.
|
55
|
+
|
56
|
+
Here's some steps to get going with that:
|
57
|
+
|
58
|
+
```
|
59
|
+
docker-compose build
|
60
|
+
docker-compose run console bash
|
61
|
+
|
62
|
+
# You should see the vuln_app container boot up and
|
63
|
+
# then you'll land in bash on the console container
|
64
|
+
|
65
|
+
bin/concuss http://vuln_app:4567 -h non_standard
|
66
|
+
```
|
46
67
|
|
47
68
|
## Development
|
48
69
|
|
49
|
-
|
70
|
+
Primarily, you'll want to use Docker to do debugging and development. To get into the console, just run `docker-compose run console bash` and from there you can run `bin/concuss` against the sample vulnerable app, or you can run `rspec` to run the specs.
|
71
|
+
|
72
|
+
If you prefer to develop without docker, after checking out the repo, run `bundle install` to install dependencies. Then, run `rspec` to run the tests.
|
73
|
+
|
74
|
+
When developing using docker or on your bare machine you can also run `script/console` for an interactive prompt that will allow you to experiment. This will give you access to the underlying classes and let you experiment outside the confines of the CLI.
|
50
75
|
|
51
76
|
If you add features or fix bugs, please write specs and open up a PR.
|
52
77
|
|
78
|
+
Note: Concuss was designed to easily install on most systems with ruby 3+. As such, its only dependencies are in the ruby standard library.
|
79
|
+
|
53
80
|
## Contributing
|
54
81
|
|
55
82
|
Bug reports and pull requests are welcome on GitHub at https://github.com/patricktulskie/concuss
|
data/bin/concuss
CHANGED
@@ -19,6 +19,10 @@ OptionParser.new do |opts|
|
|
19
19
|
opts.on("-t", "--test-string STRING", "Set a custom test string. If none specified, it sets a random string to match on.") do |v|
|
20
20
|
options[:test_string] = v
|
21
21
|
end
|
22
|
+
|
23
|
+
opts.on("-a", "--user-agent STRING", "Set a custom user agent. If none specified, it defaults to Concuss/#{Concuss::VERSION}") do |v|
|
24
|
+
options[:user_agent] = v
|
25
|
+
end
|
22
26
|
end.parse!
|
23
27
|
|
24
28
|
if ARGV[0].nil?
|
@@ -27,5 +31,9 @@ if ARGV[0].nil?
|
|
27
31
|
end
|
28
32
|
|
29
33
|
options[:url] = ARGV[0]
|
34
|
+
options[:formatter] = Concuss::Formatters::Table
|
35
|
+
options[:progress_type] = :dots
|
36
|
+
|
37
|
+
puts "Scanning #{options[:url]}"
|
30
38
|
|
31
39
|
Concuss.new(**options).attack!
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Concuss::Formatters::Table
|
2
|
+
|
3
|
+
HEADINGS = ['HEADER', 'RESPONSE_CODE', 'HIT/MISS'].freeze
|
4
|
+
|
5
|
+
def initialize(report)
|
6
|
+
@report = report
|
7
|
+
end
|
8
|
+
|
9
|
+
def print
|
10
|
+
header_max_length = @report.headers.map(&:length).max
|
11
|
+
response_code_length = HEADINGS[1].length
|
12
|
+
hit_header_length = HEADINGS[2].length
|
13
|
+
|
14
|
+
header_format = "%-#{header_max_length}s | %-#{response_code_length}s | %-0s\n"
|
15
|
+
separator = '-' * (header_max_length + response_code_length + hit_header_length + 6)
|
16
|
+
|
17
|
+
puts header_format % HEADINGS
|
18
|
+
puts separator
|
19
|
+
print_data(@report.hits, header_format)
|
20
|
+
print_data(@report.misses, header_format)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def print_data(data, header_format)
|
26
|
+
data.sort.each do |header, values|
|
27
|
+
puts header_format % [header, values[:response_code], values[:hit] ? 'HIT' : 'MISS']
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
data/lib/concuss/headers.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
class Concuss::Report
|
2
|
+
attr_reader :data, :url
|
3
|
+
|
4
|
+
def initialize(data:, url:)
|
5
|
+
@url = url
|
6
|
+
@data = data
|
7
|
+
end
|
8
|
+
|
9
|
+
def hits
|
10
|
+
data.select { |_, value| value[:hit] }
|
11
|
+
end
|
12
|
+
|
13
|
+
def misses
|
14
|
+
data.reject { |_, value| value[:hit] }
|
15
|
+
end
|
16
|
+
|
17
|
+
def headers
|
18
|
+
data.keys
|
19
|
+
end
|
20
|
+
end
|
data/lib/concuss/runner.rb
CHANGED
@@ -2,30 +2,44 @@ require 'securerandom'
|
|
2
2
|
require 'net/http'
|
3
3
|
|
4
4
|
class Concuss::Runner
|
5
|
-
|
5
|
+
DEFAULT_USER_AGENT = "Concuss/#{Concuss::VERSION}"
|
6
6
|
|
7
|
-
|
7
|
+
attr_reader :headers, :url, :test_string, :user_agent, :progress_type
|
8
|
+
|
9
|
+
def initialize(headers:, url:, test_string: nil, user_agent: nil, progress_type: nil)
|
8
10
|
@headers = headers
|
9
11
|
@url = url
|
10
12
|
@test_string = test_string || SecureRandom.hex(25)
|
13
|
+
@user_agent = user_agent || DEFAULT_USER_AGENT
|
14
|
+
@progress_type = progress_type
|
11
15
|
end
|
12
16
|
|
13
17
|
def run
|
14
18
|
uri = URI(@url)
|
19
|
+
report_data = { }
|
15
20
|
|
16
21
|
@headers.each do |header|
|
17
22
|
response = Net::HTTP.get_response(uri,
|
18
|
-
{
|
23
|
+
{
|
24
|
+
header => test_string,
|
25
|
+
'User-Agent' => user_agent
|
26
|
+
}
|
19
27
|
)
|
20
28
|
|
21
|
-
|
22
|
-
|
23
|
-
else
|
24
|
-
result = "MISS"
|
25
|
-
end
|
29
|
+
hit = response.code == "200" && response.body.include?(@test_string)
|
30
|
+
report_data[header] = { response_code: response.code, hit: hit }
|
26
31
|
|
27
|
-
|
32
|
+
case progress_type
|
33
|
+
when :full
|
34
|
+
puts "#{header} - #{response.code} - #{hit ? "HIT" : "MISS"}"
|
35
|
+
when :dots
|
36
|
+
print "."
|
37
|
+
end
|
28
38
|
end
|
39
|
+
|
40
|
+
puts "" if progress_type == :dots
|
41
|
+
|
42
|
+
return Concuss::Report.new(data: report_data, url: @url)
|
29
43
|
end
|
30
44
|
end
|
31
45
|
|
data/lib/concuss/version.rb
CHANGED
data/lib/concuss.rb
CHANGED
@@ -3,24 +3,32 @@
|
|
3
3
|
class Concuss
|
4
4
|
class Error < StandardError; end
|
5
5
|
|
6
|
-
attr_reader :url, :file, :header_set, :headers, :test_string
|
6
|
+
attr_reader :url, :file, :header_set, :headers, :test_string, :user_agent, :formatter, :progress_type
|
7
7
|
|
8
|
-
def initialize(url:, file: nil, header_set: :all, test_string: nil)
|
8
|
+
def initialize(url:, file: nil, header_set: :all, test_string: nil, user_agent: nil, formatter: nil, progress_type: nil)
|
9
9
|
@url = url
|
10
10
|
@file = file
|
11
11
|
@header_set = file.nil? ? header_set : :file
|
12
12
|
@test_string = test_string
|
13
|
+
@user_agent = user_agent
|
14
|
+
@formatter = formatter
|
15
|
+
@progress_type = progress_type
|
13
16
|
|
14
17
|
@headers = Concuss::Headers.new(header_set: @header_set, file: @file).group
|
15
18
|
end
|
16
19
|
|
17
20
|
def attack!
|
18
|
-
runner = Concuss::Runner.new(headers: headers, url: url, test_string: test_string)
|
21
|
+
runner = Concuss::Runner.new(headers: headers, url: url, test_string: test_string, user_agent: user_agent, progress_type: progress_type)
|
22
|
+
results = runner.run
|
19
23
|
|
20
|
-
|
24
|
+
formatter.new(results).print if formatter
|
25
|
+
|
26
|
+
return results
|
21
27
|
end
|
22
28
|
end
|
23
29
|
|
24
30
|
require_relative "concuss/version"
|
31
|
+
require_relative "concuss/report"
|
25
32
|
require_relative "concuss/headers"
|
26
33
|
require_relative "concuss/runner"
|
34
|
+
require_relative "concuss/formatters"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concuss
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrick Tulskie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Test websites for header injection issues
|
14
14
|
email:
|
@@ -27,7 +27,10 @@ files:
|
|
27
27
|
- Rakefile
|
28
28
|
- bin/concuss
|
29
29
|
- lib/concuss.rb
|
30
|
+
- lib/concuss/formatters.rb
|
31
|
+
- lib/concuss/formatters/table.rb
|
30
32
|
- lib/concuss/headers.rb
|
33
|
+
- lib/concuss/report.rb
|
31
34
|
- lib/concuss/runner.rb
|
32
35
|
- lib/concuss/version.rb
|
33
36
|
homepage: https://github.com/patricktulskie/concuss
|
@@ -45,7 +48,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
45
48
|
requirements:
|
46
49
|
- - ">="
|
47
50
|
- !ruby/object:Gem::Version
|
48
|
-
version:
|
51
|
+
version: 3.0.0
|
49
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
53
|
requirements:
|
51
54
|
- - ">="
|