snackhack2 0.6.5 → 0.6.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cda044a6c9ae56812b5742965caa204d3e32d8fe9dee0857806cefd45d058e4e
4
- data.tar.gz: 6f6b5a0c249afdd9691070f481fcaa756721d599b5bf7f1f68909a54c30211f1
3
+ metadata.gz: f24d3c225a7262763bb360b50b139af3d73222abfa7288d1149f5f47a7c837e4
4
+ data.tar.gz: 90f9e49687132acd4930f01ce2d03bd98b1911301d81f26130e253461f94d5a5
5
5
  SHA512:
6
- metadata.gz: 62c3e1c33052a126536a6c3b2708f2f15acd1a4adbb2d26df1f3ad9ba639c1e55308034872391fc179736e0ad9899c3f633a3273e7217ac5a547ced717f389b9
7
- data.tar.gz: 43943cb44a33159f5fdd31650e8322355882ceb46ce4049ad6e17d900e6bd74e35d83989a205f0a3379c303233ed3359c5abf774fd9fc164fceb4ca763af5e40
6
+ metadata.gz: 5c535c224366a2ad8a2ebcb047d47c4157d1fad3a3aa30b782decd5b2291823cd1b0b91043bfd60ab21f3d9c40b66c47e4e85957fb784cd6a0209b3117c6cfa5
7
+ data.tar.gz: 97232dc976b82e3a677d87fda6ea3319fc6ddc09526657d731bf89701b8ccaf70f84b4215977b17cdb7fb2ac05e6143aebf7791ce0488b88e5a0ca5cd7f14e22
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  require 'socket'
4
3
  module Snackhack2
5
4
  class BannerGrabber
@@ -8,24 +7,19 @@ module Snackhack2
8
7
  def initialize(port: 443, save_file: true)
9
8
  @site = site
10
9
  @port = port
11
- @headers = Snackhack2.get(@site).headers
12
10
  @save_file = save_file
13
11
  end
14
12
 
15
- def site
16
- # @site.gsub('https://', '')
17
- end
18
-
19
13
  def run
20
14
  nginx
21
15
  apache2
22
16
  wordpress
23
- headers
17
+ get_ssh_info
18
+ end
19
+ def headers
20
+ @headers = Snackhack2.get(@site).headers
24
21
  end
25
-
26
22
  def nginx
27
- return unless @headers['server'].match(/nginx/)
28
-
29
23
  puts "[+] Server is running NGINX... Now checking if #{File.join(@site, 'nginx_status')} is valid..."
30
24
  nginx = Snackhack2.get(File.join(@site, 'nginx_status'))
31
25
  if nginx.code == 200
@@ -37,20 +31,25 @@ module Snackhack2
37
31
 
38
32
  def curl
39
33
  servers = ''
34
+ # rus the curl command to get the headers of the given site.
40
35
  cmd = `curl -s -I #{@site.gsub('https://', '')}`
36
+ # extracts the server header from the curl results
41
37
  version = cmd.split('Server: ')[1].split("\n")[0].strip
42
38
  if @save_file
43
39
  servers += version.to_s
44
40
  else
45
41
  puts "Banner: #{cmd.split('Server: ')[1].split("\n")[0]}"
46
42
  end
43
+
44
+ # saves the results if '@save_file' is set to true.
47
45
  Snackhack2.file_save(@site, 'serverversion', servers) if @save_file
48
46
  end
49
47
 
50
48
  def apache2
51
- if @headers['server'].match(/Apache/)
49
+ if headers['server'].match(/Apache/)
52
50
  puts "[+] Server is running Apache2... Now checking #{File.join(@site, 'server-status')}..."
53
51
  apache = Snackhack2.get(File.join(@site, 'server-status'))
52
+ # status code 200 means the request was successful.
54
53
  if apache.code == 200
55
54
  puts "Check #{@site}/server-status"
56
55
  else
@@ -67,16 +66,98 @@ module Snackhack2
67
66
 
68
67
  puts "[+] Wordpress found [+]\n\n\n"
69
68
  end
69
+ def types
70
+ {
71
+ "cloudflare": [ "cf-cache-status", "cf-ray", "cloudflare"],
72
+ "aws CloudFront": [ "X-Amz-Cf-Pop", "X-Amz-Cf-Id", "CloudFront", "x-amz-cf-pop", "x-amz-cf-id", "cloudfront.net"]
73
+ }
74
+ end
75
+ def find_headers
76
+ # make a request to the site and grab the headers.
77
+ Snackhack2.get(@site).headers
78
+ end
70
79
 
71
- def headers
72
- h = Snackhack2.get(@site).headers
73
- puts "[+] Server Version: #{h['server']}..."
80
+ def get_tcp_info(ports: "")
81
+ ports = 22 if ports.empty?
82
+ begin
83
+ TCPSocket.new(@site, ports).recv(1024)
84
+ rescue => e
85
+ puts "ERROR OCCURRED"
86
+ end
74
87
  end
88
+ def cloudflare(print_status: true)
89
+ # the purpose of this method is to
90
+ # check to see if a site has
91
+ # cloudflare in the headers
92
+
93
+ cf_status = false
94
+ cf_count = 0
75
95
 
96
+ # access the 'types' hash to get the cloudflare strings.
97
+ cf = types[:"cloudflare"]
98
+
99
+ # make a single get request to the site defined at '@site'
100
+ find_headers.each do |k,v|
101
+ # if the key is in the array cf
102
+ if cf.include?(k)
103
+ cf_status = true
104
+ cf_count += 1
105
+ end
106
+ end
107
+ if print_status
108
+ # cf_status[0] : the status if cloudflare was found
109
+ # cf_count[1] : the number of found elements in the 'cloudflare' hash.
110
+ return [cf_status, cf_count]
111
+ else
112
+ if cf_status
113
+ puts "Cloudflare was found. The count is: #{cf_count}"
114
+ else
115
+ puts "Cloudflare was NOT found. The count is #{cf_count}"
116
+ end
117
+ end
118
+ end
119
+ def detect_header(return_status: true)
120
+ # stores the data found in
121
+ # the headers.
122
+ data = {}
123
+ # loops through the hash stored in the 'types' method.
124
+ # the t_k is the KEY of the hash
125
+ # the t_v is the VALUE of the hash.
126
+ types.each do |t_k, t_v|
127
+ # make a single get request to the site
128
+ # to get the headers.
129
+ find_headers.each do |fh_k, fh_v|
130
+ # Get the keys from the 'types' method
131
+ # which is basicly a hash
132
+ type_key = t_k
133
+ # uses the key of the 'types' hash
134
+ # to see if includes the string found in 'fh_k'
135
+ if types[type_key].include?(fh_k)
136
+ if data.has_key?(type_key)
137
+ data[type_key] << fh_k
138
+ else
139
+ data[type_key] = [fh_k]
140
+ end
141
+ end
142
+ end
143
+ end
144
+ if return_status
145
+ return data
146
+ else
147
+ data.each do |k,v|
148
+ puts "K:#{k}"
149
+ puts "V: #{v}"
150
+ end
151
+ end
152
+ end
76
153
  def server
77
154
  @headers['server']
78
155
  end
79
156
 
80
157
  attr_reader :site
81
- end
158
+ private :find_headers
159
+ end
82
160
  end
161
+ # to do: instead of doing mutiple methods for each type of
162
+ # header make one method that is dynamic...
163
+ # and can do different ones
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Snackhack2
4
- class PhishingData
4
+ class PhishingData
5
5
  def domains
6
6
  [
7
7
  ".com",
@@ -44,154 +44,297 @@ module Snackhack2
44
44
  ".work"
45
45
  ]
46
46
  end
47
+ def domain_keywords
48
+ [
49
+ "connect",
50
+ "corp",
51
+ "duo",
52
+ "help",
53
+ "he1p",
54
+ "helpdesk",
55
+ "helpnow",
56
+ "info",
57
+ "internal",
58
+ "mfa",
59
+ "my",
60
+ "okta",
61
+ "onelogin",
62
+ "schedule",
63
+ "service",
64
+ "servicedesk",
65
+ "servicenow",
66
+ "rci",
67
+ "rsa",
68
+ "sso",
69
+ "ssp",
70
+ "support",
71
+ "usa",
72
+ "vpn",
73
+ "work",
74
+ "dev",
75
+ "workspace",
76
+ "it",
77
+ "ops",
78
+ "hr",
79
+ "login",
80
+ "secure"
81
+ ]
82
+ end
47
83
  private :domains
48
84
  end
49
- class PhishingTlds < PhishingData
50
- attr_reader :site
51
- def initialize
52
- @site = site
85
+ class PhishingTlds < PhishingData
86
+ attr_reader :site
87
+ def initialize
88
+ @site = site
89
+ end
90
+ def domain_split
91
+ # This method splits up the value block_given
92
+ # given in @site by the period. Which is used
93
+ # by 'remove_tlds' method to remove the TLDs
94
+ @site.split(".")
95
+ end
96
+ def site=(s)
97
+ @site = s
98
+ end
99
+ def remove_tlds
100
+ # this method function is to remove
101
+ # the TLDs from the @site. For Example
102
+ # it will remove .org, .com
103
+
104
+ ds = domain_split
105
+
106
+ # remove ".com" (last element in array)
107
+ ds.pop
108
+
109
+ # returns the domain w/o the tlds
110
+ ds
111
+ end
112
+ def check_domains(array: true)
113
+ # The function of this method is to
114
+ # check if the given domains are valid or not.
115
+ # By valid I mean resolvable and active.
116
+
117
+
118
+ # if domains is set to true, this array will hold the domains
119
+ domains_out = []
120
+
121
+ # build the list of domains
122
+ generated_tlds = change_tld
123
+
124
+ valid_domains = []
125
+ not_valid_domains = []
126
+
127
+ generated_tlds.each do |domain|
128
+ # if array is true; add the domains to array
129
+ if array
130
+ domains_out << domain
131
+ else
132
+ # if array is false print out the domains
133
+ puts domain
53
134
  end
54
- def domain_split
55
- # This method splits up the value block_given
56
- # given in @site by the period. Which is used
57
- # by 'remove_tlds' method to remove the TLDs
58
- @site.split(".")
135
+ domains_out if array
136
+ end
137
+ end
138
+ def remove_letters(array_out: true)
139
+ # This method will remove letters that
140
+ # occur more than once. For example:
141
+ # google.com would become goggle.com
142
+
143
+ # store the letter count in a hash.
144
+ letter_count = {}
145
+
146
+ ds = remove_tlds
147
+
148
+ # Creates an array with each character being
149
+ # stored in a element. It will loop through the array
150
+ # and figure out the number of occurrences for each character
151
+ ds.shift.split(//).each do |letter|
152
+ if letter_count.has_key?(letter)
153
+ letter_count[letter] += 1
154
+ else
155
+ letter_count[letter] = 1
59
156
  end
60
- def site=(s)
61
- @site = s
157
+ end
158
+
159
+ # After it creates the hash with the character and
160
+ # the number of time it cocures. This method
161
+ # will loop through the hash and check to see
162
+ # if the value is greater than 1. If it is then the key ( the letter)
163
+ # is added to the array named 'letters_with_more_than_one'
164
+ letters_with_more_than_one = []
165
+ letter_count.each do |key, value|
166
+ if value > 1
167
+ letters_with_more_than_one << key
62
168
  end
63
- def remove_tlds
64
- # this method function is to remove
65
- # the TLDs from the @site. For Example
66
- # it will remove .org, .com
67
-
68
- ds = domain_split
69
-
70
- # remove ".com" (last element in array)
71
- ds.pop
72
-
73
- # returns the domain w/o the tlds
74
- ds
169
+ end
170
+
171
+
172
+ ds = remove_tlds
173
+ new_ds = ds.shift
174
+
175
+ # the final array with the duplicates letters removed
176
+ remove_letters_out = []
177
+
178
+ # Loops through the 'letters_with_more_than_one'
179
+ # array and uses 'sub' to remove the occurence
180
+ # of one of the letters
181
+ letters_with_more_than_one.each do |l|
182
+ # removes only first character ( l )
183
+ remove_letters_out << new_ds.sub(l, "")
184
+ # removes ALL chracters ( l )
185
+ remove_letters_out << new_ds.gsub(l, "")
186
+ end
187
+ # add tldds to the created list
188
+ domains_with_tlds = add_tlds(remove_letters_out)
189
+ if array_out
190
+ domains_with_tlds
191
+ else
192
+ # will print the contents of the array
193
+ # instead of returning the array
194
+ domains_with_tlds.each { |a| puts a }
195
+ end
196
+ end
197
+ def add_tlds(list)
198
+ # takes the newly created domains (list)
199
+ # and adds the tlds (domains) to the newly created
200
+ # ones.
201
+ o = []
202
+ list.each do |rr|
203
+ domains.each do |dd|
204
+ o << "#{rr}#{dd}"
75
205
  end
76
- def check_domains(array: true)
77
- # The function of this method is to
78
- # check if the given domains are valid or not.
79
- # By valid I mean resolvable and active.
80
-
81
-
82
- # if domains is set to true, this array will hold the domains
83
- domains_out = []
84
-
85
- # build the list of domains
86
- generated_tlds = change_tld
87
-
88
- valid_domains = []
89
- not_valid_domains = []
90
-
91
- generated_tlds.each do |domain|
92
- # if array is true; add the domains to array
93
- if array
94
- domains_out << domain
95
- else
96
- # if array is false print out the domains
97
- puts domain
98
- end
99
- domains_out if array
206
+ end
207
+ o
208
+ end
209
+ def combosquatting
210
+ # where the generated domains will be located.
211
+ results = []
212
+
213
+ # get the domain_keywords array from the PhishingData class.
214
+ keywords = domain_keywords
215
+
216
+ prefixes = ["-", ".", "--"]
217
+ ds = remove_tlds
218
+ # this will generate the 'new_domain' with the keywords
219
+ # as a prefix
220
+ prefixes.each do |pre|
221
+ ds.each do |domain|
222
+ keywords.each do |key|
223
+ new_domain = "#{key}#{pre}#{domain}"
224
+ results << new_domain
100
225
  end
101
226
  end
102
- def remove_letters(array_out: true)
103
- # This method will remove letters that
104
- # occur more than once. For example:
105
- # google.com would become goggle.com
106
-
107
- # store the letter count in a hash.
108
- letter_count = {}
109
-
110
- ds = remove_tlds
111
-
112
- # Creates an array with each character being
113
- # stored in a element. It will loop through the array
114
- # and figure out the number of occurrences for each character
115
- ds.shift.split(//).each do |letter|
116
- if letter_count.has_key?(letter)
117
- letter_count[letter] += 1
118
- else
119
- letter_count[letter] = 1
120
- end
121
- end
122
-
123
- # After it creates the hash with the character and
124
- # the number of time it cocures. This method
125
- # will loop through the hash and check to see
126
- # if the value is greater than 1. If it is then the key ( the letter)
127
- # is added to the array named 'letters_with_more_than_one'
128
- letters_with_more_than_one = []
129
- letter_count.each do |key, value|
130
- if value > 1
131
- letters_with_more_than_one << key
132
- end
133
- end
134
-
135
-
136
- ds = remove_tlds
137
- new_ds = ds.shift
138
-
139
- # the final array with the duplicates letters removed
140
- remove_lettters_out = []
141
-
142
- # Loops through the 'letters_with_more_than_one'
143
- # array and uses 'sub' to remove the occurence
144
- # of one of the letters
145
- letters_with_more_than_one.each do |l|
146
- remove_lettters_out << new_ds.sub(l, "")
147
- end
148
-
149
- if array_out
150
- remove_lettters_out
151
- else
152
- # will print the contents of the array
153
- # instead of returning the array
154
- remove_lettters_out.each { |a| puts a }
227
+ end
228
+ suffixes = ["-", ".", "--"]
229
+ # this will generate the 'new_domain' with the keywords
230
+ # as a suffixes
231
+ suffixes.each do |suf|
232
+ ds.each do |domain|
233
+ keywords.each do |key|
234
+ new_domain = "#{domain}#{suf}#{key}"
235
+ results << new_domain
155
236
  end
156
237
  end
157
- def change_tld(no_tld: true)
158
- # This method will take the inputted site in @site and
159
- # remove the TLDs and add a new TLDs to the domain.
160
- # its uses the 'domain' method in the PhishingData class
161
- # which has an array of a bunch of different tlds.
162
-
238
+ end
239
+ # adds the tlds to the newly created domains
240
+
241
+ add_tlds(results)
242
+ end
243
+ def change_tld(no_tld: true)
244
+ # This method will take the inputted site in @site and
245
+ # remove the TLDs and add a new TLDs to the domain.
246
+ # its uses the 'domain' method in the PhishingData class
247
+ # which has an array of a bunch of different tlds.
248
+
249
+
250
+ # if the @site does not have a tlds
251
+ if no_tld
252
+ new_domains = []
253
+ # loop through the tlds
254
+ domains.each do |d|
255
+ # combine the inputed @site
256
+ # and the tlds
257
+ new_domains << "#{@site}#{d}"
258
+ end
259
+ new_domains
260
+ else
261
+ # If the @site does have a TLDs.
163
262
 
164
- # if the @site does not have a tlds
165
- if no_tld
166
- new_domains = []
167
- # loop through the tlds
168
- domains.each do |d|
169
- # combine the inputed @site
170
- # and the tlds
171
- new_domains << "#{@site}#{d}"
172
- end
173
- new_domains
174
- else
175
- # If the @site does have a TLDs.
176
-
177
- # this is where the final results
178
- # are stored.
179
- list_of_domains = []
180
-
181
- # removes .com, .org, etc
182
- ds = remove_tlds
183
-
184
- # join the elements together
185
- ds = ds.join(".")
186
-
187
- # loops through the tlds
188
- domains.each do |tlds|
189
- # adds the new domains to the array
190
- list_of_domains << ds + tlds
263
+ # this is where the final results
264
+ # are stored.
265
+ list_of_domains = []
266
+
267
+ # removes .com, .org, etc
268
+ ds = remove_tlds
269
+
270
+ # join the elements together with .
271
+ ds = ds.join(".")
272
+
273
+ # loops through the tlds
274
+ domains.each do |tlds|
275
+ # adds the new domains to the array
276
+ list_of_domains << "#{ds}#{tlds}"
277
+ #ds + tlds
278
+ end
279
+ list_of_domains
280
+ end
281
+ end
282
+ def idn_homograph
283
+ letters = {
284
+ "o" => ["0", "О", "ó", "о","ο","օ","ȯ","ọ","ỏ","ơ","ó","ö"],
285
+ "i" => ["1","ı", "ỉ", "і", "í", "ï"],
286
+ "a" => ["а","α", "ạ"],
287
+ "h" => ["н", "һ", "ĥ"],
288
+ "c" => ["с"],
289
+ "I" => "l",
290
+ "e" => ["е", "℮", "ё", "ė", "ẹ"],
291
+ "b" => [ "þ", "в", "B" ],
292
+ "g" => [ "ɢ"],
293
+ "l" => ["Ɩ", "Ι"],
294
+ "m" => ["m", "ʍ", "м"],
295
+ "t" => ["т", "ţ"],
296
+ "p" => ["р"],
297
+ "y" => ["у", "ý"],
298
+ "k" => ["ķ"],
299
+ "d" => ["ɗ"],
300
+ "z" => ["ź","ʐ", "ż"],
301
+ "s" => ["ś", "ṣ"],
302
+ "u" => ["ų", "υ", "ս","ü","ú","ù"],
303
+ "n" => ["ń", "ñ"],
304
+ "r" => ["ɾ", "R", "r", "ʀ", "Ի", "Ꮢ", "ᚱ", "R", "r"],
305
+ "ll" => ["ǁ"],
306
+ "q" => ["զ"],
307
+ "j" => ["ј", "ʝ"],
308
+ "v" => ["ν", "ѵ"],
309
+ "x" => ["х" "ҳ"]
310
+ }
311
+ tlds = @site.split(".")
312
+ # removes the tlds
313
+ tlds.pop
314
+ # joins back the rest of the site
315
+ tlds = tlds.join(".")
316
+
317
+ new_domains = []
318
+ letters.each do |k, v|
319
+ tlds.split(//).each do |letter|
320
+ # if the letter elements
321
+ # are qual to the key vlaue
322
+ # located in the letters hash
323
+ if letter.eql?(k)
324
+ # find the key and replace it
325
+ # the v ( idn )
326
+ if v.kind_of?(Array)
327
+ # detct if the v ( value )
328
+ # is an array. If it is
329
+ # then it will "randomly" pick an element
330
+ v = v.sample
191
331
  end
192
- list_of_domains
332
+ new_domains << tlds.gsub(k, v)
193
333
  end
194
334
  end
195
- private :remove_tlds, :domain_split
196
335
  end
336
+ add_tlds(new_domains)
337
+ end
338
+ private :remove_tlds, :domain_split
339
+ end
197
340
  end
@@ -0,0 +1,15 @@
1
+ require 'socket'
2
+
3
+ # Grab the banner of a given +ip+ address and +port+
4
+ # to attempt to connect to.
5
+ #
6
+ # @param ip [String] Target IP address.
7
+ # @param port [Integer] Target port.
8
+ #
9
+ # @return [String]
10
+ def grab_banner(ip, port)
11
+ TCPSocket.new(ip, port).recv(1024)
12
+ end
13
+
14
+ # Print the result of the method to STDOUT.
15
+ puts grab_banner('100.106.14.40', 22)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Snackhack2
4
- VERSION = '0.6.5'
4
+ VERSION = '0.6.7'
5
5
  end
data/lib/snackhack2.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'uri'
4
4
  require 'httparty'
5
-
5
+ =begin
6
6
  require_relative 'snackhack2/version'
7
7
  require_relative 'snackhack2/bannergrabber'
8
8
  require_relative 'snackhack2/wordpress'
@@ -36,6 +36,12 @@ require_relative 'snackhack2/ssrf'
36
36
  require_relative 'snackhack2/dns'
37
37
  require_relative 'snackhack2/CVE-2017-9841'
38
38
  require_relative 'snackhack2/phishing_tlds'
39
+ =end
40
+ Dir.glob(File.join(File.dirname(__FILE__), "snackhack2", "*")).each do |file|
41
+ unless File.directory?(file)
42
+ require_relative file
43
+ end
44
+ end
39
45
  module Snackhack2
40
46
  UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
41
47
  def self.read_serverversion
@@ -57,10 +63,17 @@ module Snackhack2
57
63
  end
58
64
  end
59
65
 
60
- def self.file_save(site, type, content, ip: false)
61
- hostname = URI.parse(site).host
62
- File.open("#{hostname}_#{type}.txt", 'w+') { |file| file.write(content) }
63
- puts "[+] Saving file to #{hostname}_#{type}.txt..."
66
+ def self.file_save(site, type, content, ip: false, host: true)
67
+ if host
68
+ hostname = URI.parse(site).host
69
+ File.open("#{hostname}_#{type}.txt", 'w+') { |file| file.write(content) }
70
+ puts "[+] Saving file to #{hostname}_#{type}.txt..."
71
+ else
72
+ File.open("#{site}_#{type}.txt", 'w+') { |file| file.write(content) }
73
+ puts "[+] Saving file to #{site}_#{type}.txt..."
74
+ end
75
+
76
+
64
77
  end
65
78
 
66
79
  def self.get(site)
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.5
4
+ version: 0.6.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - mike
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-08 00:00:00.000000000 Z
11
+ date: 2025-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -99,6 +99,7 @@ files:
99
99
  - lib/snackhack2/robots.rb
100
100
  - lib/snackhack2/screenshots.rb
101
101
  - lib/snackhack2/sitemap.rb
102
+ - lib/snackhack2/ssh.rb
102
103
  - lib/snackhack2/sshbrute.rb
103
104
  - lib/snackhack2/ssrf.rb
104
105
  - lib/snackhack2/subdomains.rb