cms_scanner 0.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +14 -0
- data/Gemfile +6 -0
- data/README.md +20 -0
- data/Rakefile +9 -0
- data/app/app.rb +4 -0
- data/app/controllers.rb +2 -0
- data/app/controllers/core.rb +46 -0
- data/app/controllers/core/cli_options.rb +68 -0
- data/app/controllers/interesting_files.rb +12 -0
- data/app/finders.rb +1 -0
- data/app/finders/interesting_files.rb +21 -0
- data/app/finders/interesting_files/fantastico_fileslist.rb +23 -0
- data/app/finders/interesting_files/headers.rb +15 -0
- data/app/finders/interesting_files/robots_txt.rb +22 -0
- data/app/finders/interesting_files/search_replace_db_2.rb +28 -0
- data/app/finders/interesting_files/xml_rpc.rb +62 -0
- data/app/formatters.rb +3 -0
- data/app/formatters/cli.rb +18 -0
- data/app/formatters/cli_no_colour.rb +15 -0
- data/app/formatters/json.rb +12 -0
- data/app/models.rb +5 -0
- data/app/models/fantastico_fileslist.rb +20 -0
- data/app/models/headers.rb +37 -0
- data/app/models/interesting_file.rb +30 -0
- data/app/models/robots_txt.rb +20 -0
- data/app/models/xml_rpc.rb +35 -0
- data/app/views/cli/core/finished.erb +4 -0
- data/app/views/cli/core/started.erb +3 -0
- data/app/views/cli/interesting_files/findings.erb +19 -0
- data/app/views/cli/scan_aborted.erb +4 -0
- data/app/views/json/core/finished.erb +3 -0
- data/app/views/json/core/started.erb +3 -0
- data/app/views/json/interesting_files/findings.erb +1 -0
- data/app/views/json/scan_aborted.erb +4 -0
- data/cms_scanner.gemspec +37 -0
- data/examples/views/cli/wp_custom/test.erb +1 -0
- data/examples/views/json/wp_custom/test.erb +1 -0
- data/examples/wpscan.rb +29 -0
- data/lib/cms_scanner.rb +71 -0
- data/lib/cms_scanner/browser.rb +68 -0
- data/lib/cms_scanner/browser/actions.rb +48 -0
- data/lib/cms_scanner/browser/options.rb +53 -0
- data/lib/cms_scanner/cache/file_store.rb +75 -0
- data/lib/cms_scanner/cache/typhoeus.rb +21 -0
- data/lib/cms_scanner/controller.rb +90 -0
- data/lib/cms_scanner/controllers.rb +34 -0
- data/lib/cms_scanner/errors/auth_errors.rb +15 -0
- data/lib/cms_scanner/finders.rb +5 -0
- data/lib/cms_scanner/finders/finder.rb +27 -0
- data/lib/cms_scanner/finders/finding.rb +32 -0
- data/lib/cms_scanner/finders/findings.rb +25 -0
- data/lib/cms_scanner/finders/independent_finder.rb +30 -0
- data/lib/cms_scanner/finders/independent_finders.rb +41 -0
- data/lib/cms_scanner/formatter.rb +118 -0
- data/lib/cms_scanner/formatter/buffer.rb +15 -0
- data/lib/cms_scanner/target.rb +33 -0
- data/lib/cms_scanner/target/platform.rb +2 -0
- data/lib/cms_scanner/target/platform/php.rb +39 -0
- data/lib/cms_scanner/target/platform/wordpress.rb +35 -0
- data/lib/cms_scanner/target/platform/wordpress/custom_directories.rb +62 -0
- data/lib/cms_scanner/target/server.rb +3 -0
- data/lib/cms_scanner/target/server/apache.rb +43 -0
- data/lib/cms_scanner/target/server/generic.rb +34 -0
- data/lib/cms_scanner/target/server/iis.rb +48 -0
- data/lib/cms_scanner/version.rb +4 -0
- data/lib/cms_scanner/web_site.rb +68 -0
- data/lib/helper.rb +24 -0
- data/spec/app/controllers/core_spec.rb +152 -0
- data/spec/app/controllers/interesting_files_spec.rb +50 -0
- data/spec/app/finders/interesting_files/fantastico_fileslist_spec.rb +68 -0
- data/spec/app/finders/interesting_files/headers_spec.rb +38 -0
- data/spec/app/finders/interesting_files/robots_txt_spec.rb +56 -0
- data/spec/app/finders/interesting_files/search_replace_db_2_spec.rb +55 -0
- data/spec/app/finders/interesting_files/xml_rpc_spec.rb +138 -0
- data/spec/app/finders/interesting_files_spec.rb +13 -0
- data/spec/app/formatters/cli_no_colour_spec.rb +17 -0
- data/spec/app/formatters/cli_spec.rb +21 -0
- data/spec/app/formatters/json_spec.rb +33 -0
- data/spec/app/models/fantastico_fileslist_spec.rb +32 -0
- data/spec/app/models/headers_spec.rb +52 -0
- data/spec/app/models/interesting_file_spec.rb +51 -0
- data/spec/app/models/robots_txt_spec.rb +28 -0
- data/spec/app/models/xml_rpc_spec.rb +47 -0
- data/spec/cache/.gitignore +4 -0
- data/spec/dummy_finders.rb +41 -0
- data/spec/fixtures/interesting_files/fantastico_fileslist/fantastico_fileslist.txt +12 -0
- data/spec/fixtures/interesting_files/file.txt +4 -0
- data/spec/fixtures/interesting_files/headers/interesting.txt +14 -0
- data/spec/fixtures/interesting_files/headers/no_interesting.txt +12 -0
- data/spec/fixtures/interesting_files/robots_txt/robots.txt +10 -0
- data/spec/fixtures/interesting_files/search_replace_db_2/searchreplacedb2.php +188 -0
- data/spec/fixtures/interesting_files/xml_rpc/homepage_in_scope_pingback.html +7 -0
- data/spec/fixtures/interesting_files/xml_rpc/homepage_out_of_scope_pingback.html +7 -0
- data/spec/fixtures/interesting_files/xml_rpc/xmlrpc.php +1 -0
- data/spec/fixtures/output.txt +0 -0
- data/spec/fixtures/target/platform/php/debug_log/debug.log +2 -0
- data/spec/fixtures/target/platform/php/fpd/wp_rss_functions.php +2 -0
- data/spec/fixtures/target/platform/wordpress/custom_directories/custom_w_spaces.html +10 -0
- data/spec/fixtures/target/platform/wordpress/custom_directories/default.html +14 -0
- data/spec/fixtures/target/platform/wordpress/custom_directories/https.html +12 -0
- data/spec/fixtures/target/platform/wordpress/detection/default.html +4 -0
- data/spec/fixtures/target/platform/wordpress/detection/not_wp.html +8 -0
- data/spec/fixtures/target/platform/wordpress/detection/wp_includes.html +3 -0
- data/spec/fixtures/target/server/apache/directory_listing/2.2.16.html +15 -0
- data/spec/fixtures/target/server/generic/server/apache/basic.txt +5 -0
- data/spec/fixtures/target/server/generic/server/iis/basic.txt +6 -0
- data/spec/fixtures/target/server/generic/server/not_detected.txt +3 -0
- data/spec/fixtures/target/server/iis/directory_listing/no_parent.html +3 -0
- data/spec/fixtures/target/server/iis/directory_listing/with_parent.html +3 -0
- data/spec/fixtures/views/base/ctrl/local.erb +1 -0
- data/spec/fixtures/views/base/ctrl/test.erb +3 -0
- data/spec/fixtures/views/base/global.erb +1 -0
- data/spec/fixtures/views/base/test.erb +2 -0
- data/spec/fixtures/views/based_format/test.erb +1 -0
- data/spec/fixtures/views/json/render_me.erb +4 -0
- data/spec/lib/browser_spec.rb +141 -0
- data/spec/lib/cache/file_store_spec.rb +101 -0
- data/spec/lib/cache/typhoeus_spec.rb +30 -0
- data/spec/lib/cms_scanner_spec.rb +45 -0
- data/spec/lib/controller_spec.rb +23 -0
- data/spec/lib/controllers_spec.rb +52 -0
- data/spec/lib/finders/findings_spec.rb +49 -0
- data/spec/lib/finders/independent_finders_spec.rb +98 -0
- data/spec/lib/formatter_spec.rb +136 -0
- data/spec/lib/sub_scanner_spec.rb +27 -0
- data/spec/lib/target/platforms_spec.rb +13 -0
- data/spec/lib/target/servers_spec.rb +13 -0
- data/spec/lib/target_spec.rb +50 -0
- data/spec/lib/web_site_spec.rb +124 -0
- data/spec/shared_examples.rb +11 -0
- data/spec/shared_examples/browser_actions.rb +32 -0
- data/spec/shared_examples/finding.rb +20 -0
- data/spec/shared_examples/formatter_buffer.rb +8 -0
- data/spec/shared_examples/formatter_class_methods.rb +26 -0
- data/spec/shared_examples/independent_finder.rb +33 -0
- data/spec/shared_examples/target/platform/php.rb +58 -0
- data/spec/shared_examples/target/platform/wordpress.rb +41 -0
- data/spec/shared_examples/target/platform/wordpress/custom_directories.rb +50 -0
- data/spec/shared_examples/target/server/apache.rb +33 -0
- data/spec/shared_examples/target/server/generic.rb +34 -0
- data/spec/shared_examples/target/server/iis.rb +38 -0
- data/spec/spec_helper.rb +41 -0
- metadata +432 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: f568051a37f6bcd75abe28d026dea5e2ff8a1372
|
|
4
|
+
data.tar.gz: d9399f063d4bc5b3929f566e2a018788dc708615
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 60523f8ef6495c41045f34e16bf18287f677b0c8749678d8cc9e4bfd4620b21ec357e06a9e230b6b83f3604d0cdfb24f159796a902939d1b9c239c7a5051fe7a
|
|
7
|
+
data.tar.gz: 38d4c48bf4e4b682732ce4f37b7eba45cca00c19b5edffbf89abd3a362bc8e782c10d842948a3fd657fa16737c09ceb7eb3461ed1551ebc795e2be5d0d3e8861
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# CMSScanner
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/wpscanteam/CMSScanner)
|
|
4
|
+
[](https://coveralls.io/r/wpscanteam/CMSScanner)
|
|
5
|
+
[](https://codeclimate.com/github/wpscanteam/CMSScanner)
|
|
6
|
+
[](https://gemnasium.com/wpscanteam/CMSScanner)
|
|
7
|
+
|
|
8
|
+
The goal of this gem is to provide a quick and easy way to create a CMS/WebSite Scanner by acting like a Framework and providing classes, formatters etc.
|
|
9
|
+
|
|
10
|
+
## /!\ This gem is currently Experimental /!\
|
|
11
|
+
|
|
12
|
+
Install Dependencies: ```bundle install```
|
|
13
|
+
|
|
14
|
+
## Contributing
|
|
15
|
+
|
|
16
|
+
1. Fork it ( https://github.com/wpscanteam/CMSScanner/fork )
|
|
17
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
18
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
19
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
20
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/app/app.rb
ADDED
data/app/controllers.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require_relative 'core/cli_options'
|
|
2
|
+
|
|
3
|
+
module CMSScanner
|
|
4
|
+
module Controller
|
|
5
|
+
# Core Controller
|
|
6
|
+
class Core < Base
|
|
7
|
+
def setup_cache
|
|
8
|
+
return unless parsed_options[:cache_dir]
|
|
9
|
+
|
|
10
|
+
storage_path = File.join(parsed_options[:cache_dir], Digest::MD5.hexdigest(target.url))
|
|
11
|
+
|
|
12
|
+
Typhoeus::Config.cache = Cache::Typhoeus.new(storage_path)
|
|
13
|
+
Typhoeus::Config.cache.clean if parsed_options[:clear_cache]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def before_scan
|
|
17
|
+
setup_cache
|
|
18
|
+
|
|
19
|
+
fail "The url supplied '#{target.url}' seems to be down" unless target.online?
|
|
20
|
+
|
|
21
|
+
fail HTTPAuthRequiredError if target.http_auth?
|
|
22
|
+
fail ProxyAuthRequiredError if target.proxy_auth?
|
|
23
|
+
|
|
24
|
+
# TODO: ask if the redirection should be followed
|
|
25
|
+
# if user_interaction? is allowed (if followed, the Cache#storage_path should be updated)
|
|
26
|
+
redirection = target.redirection
|
|
27
|
+
fail "The url supplied redirects to #{redirection}" if redirection
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def run
|
|
31
|
+
@start_time = Time.now
|
|
32
|
+
@start_memory = memory_usage
|
|
33
|
+
|
|
34
|
+
output('started', url: target.url)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def after_scan
|
|
38
|
+
@stop_time = Time.now
|
|
39
|
+
@elapsed = @stop_time - @start_time
|
|
40
|
+
@used_memory = memory_usage - @start_memory
|
|
41
|
+
|
|
42
|
+
output('finished')
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module CMSScanner
|
|
2
|
+
module Controller
|
|
3
|
+
# CLI Options for the Core Controller
|
|
4
|
+
class Core < Base
|
|
5
|
+
def cli_options
|
|
6
|
+
formats = NS::Formatter.availables
|
|
7
|
+
|
|
8
|
+
[
|
|
9
|
+
OptURL.new(['-u', '--url URL'], required: true),
|
|
10
|
+
OptBoolean.new(%w(-v --verbose)),
|
|
11
|
+
OptFilePath.new(['-o', '--output FILE', 'Output to FILE'], writable: true, exists: false),
|
|
12
|
+
OptChoice.new(['-f', '--format FORMAT',
|
|
13
|
+
"Available formats: #{formats.join(', ')}"], choices: formats),
|
|
14
|
+
OptChoice.new(['--detection-mode MODE', 'Modes: mixed (default), passive, aggressive'],
|
|
15
|
+
choices: %w(mixed passive aggressive),
|
|
16
|
+
normalize: :to_sym,
|
|
17
|
+
default: :mixed)
|
|
18
|
+
] + cli_browser_options
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [ Array<OptParseValidator::OptBase> ]
|
|
22
|
+
def cli_browser_options
|
|
23
|
+
[
|
|
24
|
+
OptString.new(['--user-agent VALUE', '--ua']),
|
|
25
|
+
OptCredentials.new(['--http-auth login:password']),
|
|
26
|
+
OptPositiveInteger.new(['--max-threads VALUE', '-t', 'The max threads to use']),
|
|
27
|
+
OptPositiveInteger.new(['--request-timeout SECONDS', 'The request timeout in seconds']),
|
|
28
|
+
OptPositiveInteger.new(['--connect-timeout SECONDS',
|
|
29
|
+
'The connection timeout in seconds'])
|
|
30
|
+
] + cli_browser_proxy_options + cli_browser_cookies_options + cli_browser_cache_options
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [ Array<OptParseValidator::OptBase> ]
|
|
34
|
+
def cli_browser_proxy_options
|
|
35
|
+
[
|
|
36
|
+
OptProxy.new(['--proxy protocol://IP:port',
|
|
37
|
+
'Supported protocols depend on the cURL installed']),
|
|
38
|
+
OptCredentials.new(['--proxy-auth login:password'])
|
|
39
|
+
]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [ Array<OptParseValidator::OptBase> ]
|
|
43
|
+
def cli_browser_cookies_options
|
|
44
|
+
[
|
|
45
|
+
OptString.new(['--cookie-string COOKIE',
|
|
46
|
+
'Cookie string to use in requests, ' \
|
|
47
|
+
'format: cookie1=value1[; cookie2=value2]']),
|
|
48
|
+
OptFilePath.new(['--cookie-jar FILE-PATH', 'File to read and write cookies'],
|
|
49
|
+
writable: true,
|
|
50
|
+
exists: false,
|
|
51
|
+
default: '/tmp/cms_scanner/cookie_jar.txt')
|
|
52
|
+
]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @return [ Array<OptParseValidator::OptBase> ]
|
|
56
|
+
def cli_browser_cache_options
|
|
57
|
+
[
|
|
58
|
+
OptInteger.new(['--cache-ttl TIME_TO_LIVE'], default: 600),
|
|
59
|
+
OptBoolean.new(['--clear-cache', 'Clear the cache before the scan']),
|
|
60
|
+
OptDirectoryPath.new(['--cache-dir PATH'],
|
|
61
|
+
readable: true,
|
|
62
|
+
writable: true,
|
|
63
|
+
default: '/tmp/cms_scanner/cache/')
|
|
64
|
+
]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module CMSScanner
|
|
2
|
+
module Controller
|
|
3
|
+
# InterestingFiles Controller
|
|
4
|
+
class InterestingFiles < Base
|
|
5
|
+
def run
|
|
6
|
+
findings = target.interesting_files(mode: parsed_options[:detection_mode])
|
|
7
|
+
|
|
8
|
+
output('findings', findings: findings) unless findings.empty?
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
data/app/finders.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_relative 'finders/interesting_files'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require_relative 'interesting_files/headers'
|
|
2
|
+
require_relative 'interesting_files/robots_txt'
|
|
3
|
+
require_relative 'interesting_files/fantastico_fileslist'
|
|
4
|
+
require_relative 'interesting_files/search_replace_db_2'
|
|
5
|
+
require_relative 'interesting_files/xml_rpc'
|
|
6
|
+
|
|
7
|
+
module CMSScanner
|
|
8
|
+
module Finders
|
|
9
|
+
# Interesting Files Finder
|
|
10
|
+
class InterestingFiles
|
|
11
|
+
include IndependentFinder
|
|
12
|
+
|
|
13
|
+
# @param [ CMSScanner::Target ] target
|
|
14
|
+
def initialize(target)
|
|
15
|
+
%w(Headers RobotsTxt FantasticoFileslist SearchReplaceDB2 XMLRPC).each do |f|
|
|
16
|
+
finders << NS.const_get("Finders::InterestingFile::#{f}").new(target)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module CMSScanner
|
|
2
|
+
module Finders
|
|
3
|
+
module InterestingFile
|
|
4
|
+
# FantasticoFileslist finder
|
|
5
|
+
class FantasticoFileslist < Finder
|
|
6
|
+
# @return [ String ] The url of the fantastico_fileslist.txt file
|
|
7
|
+
def url
|
|
8
|
+
target.url('fantastico_fileslist.txt')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @return [ InterestingFile ]
|
|
12
|
+
def aggressive(_opts = {})
|
|
13
|
+
res = NS::Browser.get(url)
|
|
14
|
+
|
|
15
|
+
return unless res && res.code == 200 && res.body.length > 0
|
|
16
|
+
return unless res.headers && res.headers['Content-Type'] =~ /\Atext\/plain/
|
|
17
|
+
|
|
18
|
+
NS::FantasticoFileslist.new(url, confidence: 100, found_by: found_by)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module CMSScanner
|
|
2
|
+
module Finders
|
|
3
|
+
module InterestingFile
|
|
4
|
+
# Interesting Headers finder
|
|
5
|
+
class Headers < Finder
|
|
6
|
+
# @return [ InterestingFile ]
|
|
7
|
+
def passive(_opts = {})
|
|
8
|
+
r = NS::Headers.new(target.url, confidence: 100, found_by: found_by)
|
|
9
|
+
|
|
10
|
+
r.interesting_entries.empty? ? nil : r
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module CMSScanner
|
|
2
|
+
module Finders
|
|
3
|
+
module InterestingFile
|
|
4
|
+
# Robots.txt finder
|
|
5
|
+
class RobotsTxt < Finder
|
|
6
|
+
# @return [ String ] The url of the robots.txt file
|
|
7
|
+
def url
|
|
8
|
+
target.url('robots.txt')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @return [ InterestingFile ]
|
|
12
|
+
def aggressive(_opts = {})
|
|
13
|
+
res = NS::Browser.get(url)
|
|
14
|
+
|
|
15
|
+
return unless res && res.code == 200 && res.body =~ /(?:user-agent|(?:dis)?allow):/i
|
|
16
|
+
|
|
17
|
+
NS::RobotsTxt.new(url, confidence: 100, found_by: found_by)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module CMSScanner
|
|
2
|
+
module Finders
|
|
3
|
+
module InterestingFile
|
|
4
|
+
# SearchReplaceDB2 finder
|
|
5
|
+
class SearchReplaceDB2 < Finder
|
|
6
|
+
# @return [ String ] The url to the searchreplacedb2 PHP file
|
|
7
|
+
def url
|
|
8
|
+
target.url('searchreplacedb2.php')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @return [ InterestingFile ]
|
|
12
|
+
def aggressive(_opts = {})
|
|
13
|
+
res = NS::Browser.get(url)
|
|
14
|
+
|
|
15
|
+
return unless res && res.code == 200 && res.body =~ /by interconnect/i
|
|
16
|
+
|
|
17
|
+
NS::InterestingFile.new(url, confidence: 100,
|
|
18
|
+
found_by: found_by,
|
|
19
|
+
references: references)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def references
|
|
23
|
+
%w(https://interconnectit.com/products/search-and-replace-for-wordpress-databases/)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module CMSScanner
|
|
2
|
+
module Finders
|
|
3
|
+
module InterestingFile
|
|
4
|
+
# XML RPC finder
|
|
5
|
+
class XMLRPC < Finder
|
|
6
|
+
# @return [ Array<String> ] The potential urls to the XMl RPC file
|
|
7
|
+
def potential_urls
|
|
8
|
+
@potential_urls ||= []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @return [ Array<XMLRPC> ]
|
|
12
|
+
def passive(opts = {})
|
|
13
|
+
[passive_headers(opts), passive_body(opts)].compact
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [ XMLRPC ]
|
|
17
|
+
def passive_headers(_opts = {})
|
|
18
|
+
url = NS::Browser.get(target.url).headers['X-Pingback']
|
|
19
|
+
|
|
20
|
+
return unless target.in_scope?(url)
|
|
21
|
+
potential_urls << url
|
|
22
|
+
|
|
23
|
+
NS::XMLRPC.new(url, confidence: 30, found_by: 'Headers (passive detection)')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [ XMLRPC ]
|
|
27
|
+
def passive_body(_opts = {})
|
|
28
|
+
page = Nokogiri::HTML(NS::Browser.get(target.url).body)
|
|
29
|
+
|
|
30
|
+
page.css('link[rel="pingback"]').each do |tag|
|
|
31
|
+
url = tag.attribute('href').to_s
|
|
32
|
+
|
|
33
|
+
next unless target.in_scope?(url)
|
|
34
|
+
potential_urls << url
|
|
35
|
+
|
|
36
|
+
return NS::XMLRPC.new(url, confidence: 30,
|
|
37
|
+
found_by: 'Link Tag (passive detection)')
|
|
38
|
+
end
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [ XMLRPC ]
|
|
43
|
+
def aggressive(_opts = {})
|
|
44
|
+
potential_urls << target.url('xmlrpc.php')
|
|
45
|
+
|
|
46
|
+
potential_urls.uniq.each do |potential_url|
|
|
47
|
+
next unless target.in_scope?(potential_url)
|
|
48
|
+
|
|
49
|
+
res = NS::Browser.get(potential_url)
|
|
50
|
+
|
|
51
|
+
next unless res && res.body =~ /XML-RPC server accepts POST requests only/i
|
|
52
|
+
|
|
53
|
+
return NS::XMLRPC.new(potential_url,
|
|
54
|
+
confidence: 100,
|
|
55
|
+
found_by: DIRECT_FILE_ACCESS)
|
|
56
|
+
end
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
data/app/formatters.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module CMSScanner
|
|
2
|
+
module Formatter
|
|
3
|
+
# CLI Formatter
|
|
4
|
+
class Cli < Base
|
|
5
|
+
def red(text)
|
|
6
|
+
colorize(text, 31)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def green(text)
|
|
10
|
+
colorize(text, 32)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def colorize(text, color_code)
|
|
14
|
+
"\e[#{color_code}m#{text}\e[0m"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|