easywins 0.1.0

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.
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in easywins.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Michael Henriksen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,51 @@
1
+ # Easywins
2
+
3
+ ![Easywins probing somewebsite.com](https://i.imgur.com/Qso3M12.png)
4
+
5
+ Easywins is a simple security tool that can probe a web server for common
6
+ paths that can be used for gathering information or for gaining a foothold
7
+ on the system.
8
+
9
+ The list of paths is taken from [@mubix's](https://twitter.com/mubix) crowd-sourced
10
+ list of common *easy win* paths: https://github.com/pwnwiki/webappurls
11
+
12
+ ## Installation
13
+
14
+ $ gem install easywins
15
+
16
+ ## Usage
17
+
18
+ Usage: easywins [options] base_url
19
+
20
+ Probe a web server for common files and endpoints that are useful for gathering information or gaining a foothold.
21
+
22
+ v0.1.0
23
+
24
+ Options:
25
+ -h, --help Show command line help
26
+ -g, --get Use GET requests instead of HEAD (slower but stealthier)
27
+ -s, --sleep Sleep between 0 and 10 seconds before each request
28
+ -x, --spoof Spoof X-Forwarded-For header with random IP addresses
29
+ --timeout SECONDS Request timeout in seconds
30
+ (default: 2.5)
31
+ -r, --retries RETRIES Number of retries on failed requests
32
+ (default: 3)
33
+ -t, --threads THREADS Number of threads to use
34
+ (default: 3)
35
+ --no-verify Don't do SSL verification
36
+ --no-redirect-check Don't check if server redirects
37
+ --no-404-check Don't check if server responds with 404
38
+ --no-color Don't colorize output
39
+ --version Show help/version info
40
+
41
+ ### Example:
42
+
43
+ $ easywins --sleep --spoof --threads 5 http://somewebsite.com
44
+
45
+ ## Contributing
46
+
47
+ 1. Fork it ( https://github.com/michenriksen/easywins/fork )
48
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require 'easywins'
5
+
6
+ class App
7
+ include Methadone::Main
8
+ include Methadone::CLILogging
9
+
10
+ main do |base_url|
11
+ begin
12
+ Paint.mode = 0 if options.include?('no-color')
13
+
14
+ target = Easywins::Target.new(base_url, {
15
+ :spoof => options.include?('spoof'),
16
+ :timeout => options[:timeout].to_f,
17
+ :retries => options[:retries],
18
+ :verify => options['no-verify'].nil?
19
+ })
20
+
21
+ not_found_codes = [404]
22
+
23
+ print "\n [*] Checking to see if the server is alive... "
24
+ if target.alive?
25
+ print Paint["yes, good.\n", :green]
26
+ else
27
+ print Paint["nope, exiting.\n", :red]
28
+ exit!
29
+ end
30
+
31
+ if !options.include?('no-redirect-check')
32
+ print " [*] Checking to see if the server redirects... "
33
+ if target.redirects?
34
+ print Paint["it does.\n", :yellow]
35
+ puts Paint[" [*] Changing base URL to #{target.base_url}", :yellow]
36
+ else
37
+ print Paint["nope.\n", :green]
38
+ end
39
+ end
40
+
41
+ if !options.include?('no-404-check')
42
+ print " [*] Checking to see if the server responds with 404... "
43
+ not_found_probe = target.request("/#{SecureRandom.urlsafe_base64}")
44
+ if not_found_probe.code == 404
45
+ print Paint["yes, good.\n", :green]
46
+ else
47
+ if not_found_probe.code == 200
48
+ print Paint["#{not_found_probe.code} #{not_found_probe.message}\n", :red]
49
+ puts Paint[" [*] The server responds with 200 OK. Be prepared for tons of false-positives!", :red]
50
+ else
51
+ print Paint["#{not_found_probe.code} #{not_found_probe.message}.\n", :yellow]
52
+ puts Paint[" [*] Treating #{not_found_probe.code} responses as Not Found.", :yellow]
53
+ not_found_codes << not_found_probe.code
54
+ end
55
+ end
56
+ end
57
+
58
+ puts " [*] Checking the server for #{Easywins::PATHS.count} interesting paths...\n\n"
59
+
60
+ thread_pool = Thread.pool(options[:threads].to_i)
61
+ column_width = Easywins::PATHS.max { |a, b| a.length <=> b.length }.length + target.base_url.length
62
+
63
+ Easywins::PATHS.shuffle.each do |path|
64
+ thread_pool.process do
65
+ sleep Random.rand(10) if options.include?('sleep')
66
+ begin
67
+ url = "#{target.base_url}#{path}"
68
+ result = target.request(path, options.include?('get'))
69
+
70
+ if result.code == 200
71
+ puts Paint[" #{url.ljust(column_width)} #{result.code} #{result.message}", :green]
72
+ else
73
+ if !not_found_codes.include?(result.code)
74
+ puts Paint[" #{url.ljust(column_width)} #{result.code} #{result.message}", :yellow]
75
+ end
76
+ end
77
+ rescue => e
78
+ puts Paint[" #{url.ljust(column_width)} FAILED: #{e.class}", :red]
79
+ end
80
+ end
81
+ end
82
+
83
+ thread_pool.shutdown
84
+
85
+ puts Paint["\n [*] Done!\n", :green]
86
+
87
+ rescue Exception => e
88
+ if e.is_a?(OptionParser::ParseError) || e.is_a?(ArgumentError)
89
+ help_now!
90
+ elsif e.is_a?(Interrupt)
91
+ puts Paint["\n\n [*] Interrupted.\n", :yellow]
92
+ elsif e.is_a?(OpenSSL::SSL::SSLError)
93
+ puts Paint["\n\n [*] There's a problem with the server's SSL certificate. Use the --no-verify option if you know what you're doing.\n", :red]
94
+ else
95
+ puts Paint["\n\n [*] WARP CORE BREACH!", :red]
96
+ puts Paint[" #{e.class}: #{e.message}\n", :red]
97
+ end
98
+ end
99
+ end
100
+
101
+ options['threads'] = 3
102
+ options['timeout'] = Easywins::HttpClient::DEFAULT_TIMEOUT
103
+ options['retries'] = Easywins::HttpClient::DEFAULT_RETRIES
104
+
105
+ on('-g', '--get', "Use GET requests instead of HEAD (slower but stealthier)")
106
+ on('-s', '--sleep', "Sleep between 0 and 10 seconds before each request")
107
+ on('-x', '--spoof', "Spoof X-Forwarded-For header with random IP addresses")
108
+ on('-t', '--timeout SECONDS', "Request timeout in seconds")
109
+ on('-r', '--retries RETRIES', "Number of retries on failed requests")
110
+ on('-t THREADS', '--threads', "Number of threads to use")
111
+ on('--no-verify', "Don't do SSL verification")
112
+ on('--no-redirect-check', "Don't check if server redirects")
113
+ on('--no-404-check', "Don't check if server responds with 404")
114
+ on('--no-color', "Don't colorize output")
115
+
116
+ arg :base_url
117
+
118
+ description "Probe a web server for common files and endpoints that are useful for gathering information or gaining a foothold."
119
+ version Easywins::VERSION
120
+
121
+ go!
122
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'easywins/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "easywins"
8
+ spec.version = Easywins::VERSION
9
+ spec.authors = ["Michael Henriksen"]
10
+ spec.email = ["michenriksen@neomailbox.ch"]
11
+ spec.summary = %q{Probe a web server for common files and endpoints that are useful for gathering information or gaining a foothold.}
12
+ spec.description = %q{Probe a web server for common files and endpoints that are useful for gathering information or gaining a foothold.}
13
+ spec.homepage = "https://github.com/michenriksen/easywins"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'httparty'
22
+ spec.add_dependency 'methadone'
23
+ spec.add_dependency 'paint'
24
+ spec.add_dependency 'thread'
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.6"
27
+ spec.add_development_dependency "rake"
28
+ end
@@ -0,0 +1,99 @@
1
+ require 'optparse'
2
+ require 'net/http'
3
+ require 'httparty'
4
+ require 'methadone'
5
+ require 'paint'
6
+ require 'thread/pool'
7
+
8
+ require 'easywins/version'
9
+ require 'easywins/http_client'
10
+ require 'easywins/target'
11
+
12
+ module Easywins
13
+ PATHS = [
14
+ '/.bzr/README',
15
+ '/.git/config',
16
+ '/.hg/requires',
17
+ '/.htaccess',
18
+ '/.htpasswd',
19
+ '/.svn/wc.db',
20
+ '/_layouts/groups.aspx',
21
+ '/_layouts/people.aspx',
22
+ '/access.log',
23
+ '/admin',
24
+ '/admin.nsf',
25
+ '/administration/index.php',
26
+ '/administrator/',
27
+ '/apc.php',
28
+ '/awstats/',
29
+ '/axis2/axis2-web/HappyAxis.jsp',
30
+ '/backup.tar.gz',
31
+ '/backup/',
32
+ '/backups/',
33
+ '/bb-admin',
34
+ '/c99.php',
35
+ '/cacti',
36
+ '/CFIDE/adminapi/administrator.cfc',
37
+ '/CFIDE/administrator/enter.cfm',
38
+ '/CFIDE/administrator/index.cfm',
39
+ '/CFIDE/scripts/ajax/FCKeditor/editor/filemanager/connectors/cfm/upload.cfm',
40
+ '/cgi-bin/cvsweb',
41
+ '/cgi-bin/php',
42
+ '/cgi-bin/php5',
43
+ '/CHANGELOG.txt',
44
+ '/console/',
45
+ '/crossdomain.xml',
46
+ '/data',
47
+ '/dev/',
48
+ '/elmah.axd',
49
+ '/error.log',
50
+ '/exchange/',
51
+ '/files',
52
+ '/ghost',
53
+ '/include/',
54
+ '/includes/',
55
+ '/index.php?-s',
56
+ '/index.php?url=admin',
57
+ '/info.php',
58
+ '/install',
59
+ '/INSTALL.txt',
60
+ '/install/upgrade.php',
61
+ '/jmx-console/',
62
+ '/login',
63
+ '/logon',
64
+ '/logs/',
65
+ '/manager',
66
+ '/manager/html',
67
+ '/manual/',
68
+ '/na_admin/ataglance.html',
69
+ '/owa',
70
+ '/pgmyadmin/',
71
+ '/phpinfo.php',
72
+ '/phpmyadmin/',
73
+ '/plesk',
74
+ '/pls/admin',
75
+ '/private',
76
+ '/Providers/HtmlEditorProviders/Fck/fcklinkgallery.aspx',
77
+ '/README.txt',
78
+ '/robots.txt',
79
+ '/rockmongo/index.php',
80
+ '/server-status',
81
+ '/sitemap.xml',
82
+ '/sites/default/files/backup_migrate/',
83
+ '/temp',
84
+ '/test.php',
85
+ '/test/',
86
+ '/tmp',
87
+ '/trace.axd',
88
+ '/upload/',
89
+ '/uploads/',
90
+ '/user.php',
91
+ '/webalizer/',
92
+ '/webdav/',
93
+ '/webmin',
94
+ '/WorkArea/version.xml',
95
+ '/wp-admin/',
96
+ '/wsman',
97
+ '/xampp/'
98
+ ]
99
+ end
@@ -0,0 +1,169 @@
1
+ require 'ipaddr'
2
+
3
+ module Easywins
4
+ class HttpClient
5
+ include HTTParty
6
+
7
+ follow_redirects false
8
+
9
+ class UnhandledError < StandardError; end
10
+
11
+ DEFAULT_TIMEOUT = 2.5 #seconds
12
+ DEFAULT_RETRIES = 3
13
+
14
+ HANDLED_EXCEPTIONS = [
15
+ SocketError,
16
+ Timeout::Error,
17
+ Errno::ETIMEDOUT,
18
+ Errno::ECONNRESET,
19
+ Errno::ECONNREFUSED,
20
+ Errno::ENETUNREACH,
21
+ Errno::EHOSTUNREACH,
22
+ EOFError
23
+ ]
24
+
25
+ USER_AGENTS = [
26
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36',
27
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/537.75.14',
28
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0',
29
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36',
30
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36',
31
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:28.0) Gecko/20100101 Firefox/28.0',
32
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36',
33
+ 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36',
34
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36',
35
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36',
36
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko',
37
+ 'Mozilla/5.0 (Windows NT 6.1; rv:28.0) Gecko/20100101 Firefox/28.0',
38
+ 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36',
39
+ 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0',
40
+ 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0',
41
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.74.9 (KHTML, like Gecko) Version/7.0.2 Safari/537.74.9',
42
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D167 Safari/9537.53',
43
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36',
44
+ 'Mozilla/5.0 (Windows NT 5.1; rv:28.0) Gecko/20100101 Firefox/28.0',
45
+ 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36',
46
+ 'Mozilla/5.0 (iPad; CPU OS 7_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D167 Safari/9537.53',
47
+ 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36',
48
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36',
49
+ 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0',
50
+ 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36',
51
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36',
52
+ 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36',
53
+ 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)',
54
+ 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36',
55
+ 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)',
56
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0',
57
+ 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0',
58
+ 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko',
59
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0',
60
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:28.0) Gecko/20100101 Firefox/28.0',
61
+ 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36',
62
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D201 Safari/9537.53',
63
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:28.0) Gecko/20100101 Firefox/28.0',
64
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/33.0.1750.152 Chrome/33.0.1750.152 Safari/537.36',
65
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36',
66
+ 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko',
67
+ 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36',
68
+ 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36',
69
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:28.0) Gecko/20100101 Firefox/28.0',
70
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36',
71
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/6.1.3 Safari/537.75.14',
72
+ 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36',
73
+ 'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:28.0) Gecko/20100101 Firefox/28.0',
74
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:29.0) Gecko/20100101 Firefox/29.0',
75
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.59.10 (KHTML, like Gecko) Version/5.1.9 Safari/534.59.10',
76
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36',
77
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0',
78
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B554a Safari/9537.53',
79
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.132 Safari/537.36',
80
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0',
81
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36',
82
+ 'Mozilla/5.0 (iPad; CPU OS 7_1_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D201 Safari/9537.53',
83
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.74.9 (KHTML, like Gecko) Version/6.1.2 Safari/537.74.9',
84
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/6.1.3 Safari/537.75.14',
85
+ 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko',
86
+ 'Mozilla/5.0 (iPad; CPU OS 7_0_6 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B651 Safari/9537.53',
87
+ 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36',
88
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0',
89
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20140319 Firefox/24.0 Iceweasel/24.4.0',
90
+ 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)',
91
+ 'Mozilla/5.0 (iPad; CPU OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B554a Safari/9537.53',
92
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1',
93
+ 'Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36',
94
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36',
95
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0',
96
+ 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:29.0) Gecko/20100101 Firefox/29.0',
97
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36',
98
+ 'Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36',
99
+ 'Mozilla/5.0 (Windows NT 6.0; rv:28.0) Gecko/20100101 Firefox/28.0',
100
+ 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
101
+ 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)',
102
+ 'Mozilla/5.0 (iPad; CPU OS 7_1 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) CriOS/33.0.1750.21 Mobile/11D167 Safari/9537.53',
103
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_6 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B651 Safari/9537.53',
104
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.74.9 (KHTML, like Gecko) Version/6.1.2 Safari/537.74.9',
105
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.73.11 (KHTML, like Gecko) Version/7.0.1 Safari/537.73.11'
106
+ ]
107
+
108
+ def initialize(config = {})
109
+ @config = {
110
+ :timeout => DEFAULT_TIMEOUT,
111
+ :retries => DEFAULT_RETRIES
112
+ }.merge(config)
113
+ default_timeout = @config[:timeout]
114
+ end
115
+
116
+ def do_head(path, params=nil, opt={})
117
+ do_request(:head, path, {:query => params}.merge(opt))
118
+ end
119
+
120
+ def do_get(path, params=nil, opt={})
121
+ do_request(:get, path, {:query => params}.merge(opt))
122
+ end
123
+
124
+ def do_post(path, params=nil, opt={})
125
+ do_request(:post, path, {:body => params}.merge(opt))
126
+ end
127
+
128
+ def do_put(path, params=nil, opt={})
129
+ do_request(:put, path, {:body => params}.merge(opt))
130
+ end
131
+
132
+ def do_delete(path, params=nil, opt={})
133
+ do_request(:delete, path, {:query => params}.merge(opt))
134
+ end
135
+
136
+ private
137
+
138
+ def do_request(method, path, options)
139
+ o = {
140
+ :headers => {
141
+ 'User-Agent' => random_user_agent
142
+ }
143
+ }.merge(options)
144
+ o[:headers]['X-Forwarded-for'] = random_ip_address if @config[:spoof]
145
+ with_retries do
146
+ self.class.send(method, path, o)
147
+ end
148
+ end
149
+
150
+ def with_retries(&block)
151
+ tries ||= @config[:retries]
152
+ yield
153
+ rescue *HANDLED_EXCEPTIONS => ex
154
+ if (tries -= 1) > 0
155
+ sleep 0.2
156
+ retry
157
+ end
158
+ raise ex
159
+ end
160
+
161
+ def random_user_agent
162
+ USER_AGENTS.sample
163
+ end
164
+
165
+ def random_ip_address
166
+ ipv4 = IPAddr.new(rand(2**32), Socket::AF_INET).to_s
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,77 @@
1
+ require 'securerandom'
2
+
3
+ module Easywins
4
+ class Target
5
+
6
+ attr_reader :base_url
7
+
8
+ URL_REGEX = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?\??$/
9
+ REDIRECT_CODES = [300, 301, 302, 303, 305]
10
+
11
+ class InvalidBaseUrlError < StandardError; end
12
+ class TooManyRedirectsError < StandardError; end
13
+
14
+ def initialize(base_url, options = {})
15
+ @base_url = validate_and_normalize_url!(base_url)
16
+ @options = options
17
+ end
18
+
19
+ def request(path, use_get = false)
20
+ url = "#{@base_url}#{path}"
21
+ if use_get
22
+ http_client.do_get(url, {}, :verify => @options[:verify])
23
+ else
24
+ http_client.do_head(url, {}, :verify => @options[:verify])
25
+ end
26
+ end
27
+
28
+ def alive?
29
+ response = request('/', true)
30
+ rescue *HttpClient::HANDLED_EXCEPTIONS
31
+ false
32
+ end
33
+
34
+ def redirects?
35
+ final_url = validate_and_normalize_url!(follow_redirects!("#{@base_url}/"))
36
+ if @base_url != final_url
37
+ @base_url = final_url
38
+ true
39
+ else
40
+ false
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def validate_and_normalize_url!(url)
47
+ url = "http://#{url}" unless url =~ /^https?:\/\//i
48
+ raise InvalidBaseUrlError.new("#{url} is an invalid URL") unless valid_url?(url)
49
+ normalized_url = url.dup
50
+ use_ssl = (normalized_url =~ /^https/) || (normalized_url =~ /:443\b/)
51
+ ends_with_slash = normalized_url =~ /\/$/
52
+
53
+ normalized_url.chop! if ends_with_slash
54
+ normalized_url.gsub!(/^https?:\/\//i, '')
55
+
56
+ "http#{'s' if use_ssl}://#{normalized_url}".downcase
57
+ end
58
+
59
+ def follow_redirects!(url, redirects = 5)
60
+ raise TooManyRedirectsError.new() if redirects.zero?
61
+ response = http_client.do_get(url, {}, :verify => @options[:verify])
62
+ if REDIRECT_CODES.include?(response.code)
63
+ follow_redirects!(response.headers['location'], redirects-1)
64
+ else
65
+ url
66
+ end
67
+ end
68
+
69
+ def valid_url?(url)
70
+ url =~ URL_REGEX
71
+ end
72
+
73
+ def http_client
74
+ @http_client ||= HttpClient.new(@options)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ module Easywins
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: easywins
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michael Henriksen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-05-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: httparty
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: methadone
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: paint
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: thread
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: bundler
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '1.6'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '1.6'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rake
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Probe a web server for common files and endpoints that are useful for
111
+ gathering information or gaining a foothold.
112
+ email:
113
+ - michenriksen@neomailbox.ch
114
+ executables:
115
+ - easywins
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - .gitignore
120
+ - Gemfile
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - bin/easywins
125
+ - easywins.gemspec
126
+ - lib/easywins.rb
127
+ - lib/easywins/http_client.rb
128
+ - lib/easywins/target.rb
129
+ - lib/easywins/version.rb
130
+ homepage: https://github.com/michenriksen/easywins
131
+ licenses:
132
+ - MIT
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ none: false
145
+ requirements:
146
+ - - ! '>='
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ requirements: []
150
+ rubyforge_project:
151
+ rubygems_version: 1.8.23
152
+ signing_key:
153
+ specification_version: 3
154
+ summary: Probe a web server for common files and endpoints that are useful for gathering
155
+ information or gaining a foothold.
156
+ test_files: []