ronin-vulns 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.github/workflows/ruby.yml +31 -0
  4. data/.gitignore +13 -0
  5. data/.rspec +1 -0
  6. data/.ruby-version +1 -0
  7. data/.yardopts +1 -0
  8. data/COPYING.txt +165 -0
  9. data/ChangeLog.md +22 -0
  10. data/Gemfile +34 -0
  11. data/README.md +328 -0
  12. data/Rakefile +34 -0
  13. data/bin/ronin-vulns +19 -0
  14. data/data/rfi_test.asp +21 -0
  15. data/data/rfi_test.aspx +25 -0
  16. data/data/rfi_test.cfm +27 -0
  17. data/data/rfi_test.jsp +19 -0
  18. data/data/rfi_test.php +24 -0
  19. data/data/rfi_test.pl +25 -0
  20. data/gemspec.yml +41 -0
  21. data/lib/ronin/vulns/cli/command.rb +39 -0
  22. data/lib/ronin/vulns/cli/commands/lfi.rb +145 -0
  23. data/lib/ronin/vulns/cli/commands/open_redirect.rb +119 -0
  24. data/lib/ronin/vulns/cli/commands/reflected_xss.rb +99 -0
  25. data/lib/ronin/vulns/cli/commands/rfi.rb +156 -0
  26. data/lib/ronin/vulns/cli/commands/scan.rb +316 -0
  27. data/lib/ronin/vulns/cli/commands/sqli.rb +133 -0
  28. data/lib/ronin/vulns/cli/commands/ssti.rb +126 -0
  29. data/lib/ronin/vulns/cli/logging.rb +78 -0
  30. data/lib/ronin/vulns/cli/web_vuln_command.rb +347 -0
  31. data/lib/ronin/vulns/cli.rb +45 -0
  32. data/lib/ronin/vulns/lfi/test_file.rb +91 -0
  33. data/lib/ronin/vulns/lfi.rb +266 -0
  34. data/lib/ronin/vulns/open_redirect.rb +118 -0
  35. data/lib/ronin/vulns/reflected_xss/context.rb +224 -0
  36. data/lib/ronin/vulns/reflected_xss/test_string.rb +149 -0
  37. data/lib/ronin/vulns/reflected_xss.rb +184 -0
  38. data/lib/ronin/vulns/rfi.rb +224 -0
  39. data/lib/ronin/vulns/root.rb +28 -0
  40. data/lib/ronin/vulns/sqli/error_pattern.rb +89 -0
  41. data/lib/ronin/vulns/sqli.rb +397 -0
  42. data/lib/ronin/vulns/ssti/test_expression.rb +104 -0
  43. data/lib/ronin/vulns/ssti.rb +203 -0
  44. data/lib/ronin/vulns/url_scanner.rb +218 -0
  45. data/lib/ronin/vulns/version.rb +26 -0
  46. data/lib/ronin/vulns/vuln.rb +49 -0
  47. data/lib/ronin/vulns/web_vuln/http_request.rb +223 -0
  48. data/lib/ronin/vulns/web_vuln.rb +774 -0
  49. data/man/ronin-vulns-lfi.1 +107 -0
  50. data/man/ronin-vulns-lfi.1.md +80 -0
  51. data/man/ronin-vulns-open-redirect.1 +98 -0
  52. data/man/ronin-vulns-open-redirect.1.md +73 -0
  53. data/man/ronin-vulns-reflected-xss.1 +95 -0
  54. data/man/ronin-vulns-reflected-xss.1.md +71 -0
  55. data/man/ronin-vulns-rfi.1 +107 -0
  56. data/man/ronin-vulns-rfi.1.md +80 -0
  57. data/man/ronin-vulns-scan.1 +138 -0
  58. data/man/ronin-vulns-scan.1.md +103 -0
  59. data/man/ronin-vulns-sqli.1 +107 -0
  60. data/man/ronin-vulns-sqli.1.md +80 -0
  61. data/man/ronin-vulns-ssti.1 +99 -0
  62. data/man/ronin-vulns-ssti.1.md +74 -0
  63. data/ronin-vulns.gemspec +60 -0
  64. metadata +161 -0
@@ -0,0 +1,397 @@
1
+ # frozen_string_literal: true
2
+ # frozen_string_literal: true
3
+ #
4
+ # ronin-vulns - A Ruby library for blind vulnerability testing.
5
+ #
6
+ # Copyright (c) 2022 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # ronin-vulns is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU Lesser General Public License as published
10
+ # by the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # ronin-vulns is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU Lesser General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU Lesser General Public License
19
+ # along with ronin-vulns. If not, see <https://www.gnu.org/licenses/>.
20
+ #
21
+
22
+ require 'ronin/vulns/web_vuln'
23
+ require 'ronin/vulns/sqli/error_pattern'
24
+
25
+ require 'time'
26
+
27
+ module Ronin
28
+ module Vulns
29
+ #
30
+ # Represents a SQL injection vulnerability.
31
+ #
32
+ # ## Features
33
+ #
34
+ # * Supports testing ` OR 1=1` and ` AND 1=0`.
35
+ # * Supports testing SQL sleep functions.
36
+ #
37
+ class SQLI < WebVuln
38
+
39
+ # Specifies whether to escape a quoted string value.
40
+ #
41
+ # @return [Boolean]
42
+ attr_reader :escape_quote
43
+
44
+ # Specifies whether to escape parenthesis.
45
+ #
46
+ # @return [Boolean]
47
+ attr_reader :escape_parens
48
+
49
+ # Specifies whether to terminate the SQL statement with `--`.
50
+ #
51
+ # @return [Boolean]
52
+ attr_reader :terminate
53
+
54
+ #
55
+ # Initializes the SQL injection vulnerability.
56
+ #
57
+ # @param [URI::HTTP, String] url
58
+ # The URL to test or exploit.
59
+ #
60
+ # @param [Boolean] escape_quote
61
+ # Specifies whether to escape a quoted string value.
62
+ #
63
+ # @param [Boolean] escape_parens
64
+ # Specifies whether to escape parenthesis.
65
+ #
66
+ # @param [Boolean] terminate
67
+ # Specifies whether to terminate the SQL statement with `--`.
68
+ #
69
+ def initialize(url, escape_quote: false,
70
+ escape_parens: false,
71
+ terminate: false,
72
+ **kwargs)
73
+ super(url,**kwargs)
74
+
75
+ @escape_quote = escape_quote
76
+ @escape_parens = escape_parens
77
+ @terminate = terminate
78
+
79
+ @escape_string = build_escape_string
80
+ end
81
+
82
+ private
83
+
84
+ #
85
+ # Builds the SQL escape String.
86
+ #
87
+ # @return [String]
88
+ #
89
+ def build_escape_string
90
+ if @escape_quote && @escape_parens
91
+ "#{original_value}')"
92
+ elsif @escape_quote
93
+ "#{original_value}'"
94
+ elsif @escape_parens
95
+ "#{original_value})"
96
+ else
97
+ original_value
98
+ end
99
+ end
100
+
101
+ public
102
+
103
+ #
104
+ # Scans the URL for SQL injections.
105
+ #
106
+ # @param [URI::HTTP, String] url
107
+ # The URL to test or exploit.
108
+ #
109
+ # @param [Ronin::Support::Network::HTTP, nil] http
110
+ # An HTTP session to use for testing the URL.
111
+ #
112
+ # @param [Hash{Symbol => Object}] kwargs
113
+ # Additional keyword arguments for {WebVuln.scan}.
114
+ #
115
+ # @yield [sqli]
116
+ # If a block is given it will be yielded each discovered SQL injection
117
+ # vulnerability.
118
+ #
119
+ # @yieldparam [SQLi] sqli
120
+ # A discovered SQL injection vulnerability in the URL.
121
+ #
122
+ # @return [Array<SQLi>]
123
+ # All discovered SQL injection vulnerabilities.
124
+ #
125
+ def self.scan(url, http: nil, **kwargs, &block)
126
+ url = URI(url)
127
+ http ||= Support::Network::HTTP.connect_uri(url)
128
+
129
+ escape_quotes = [false, true]
130
+ escape_parens = [false, true]
131
+ terminations = [false, true]
132
+
133
+ vulns = []
134
+
135
+ escape_quotes.each do |escape_quote|
136
+ escape_parens.each do |escape_paren|
137
+ terminations.each do |terminate|
138
+ vulns.concat(super(url, escape_quote: escape_quote,
139
+ escape_parens: escape_paren,
140
+ terminate: terminate,
141
+ http: http,
142
+ **kwargs,
143
+ &block))
144
+ end
145
+ end
146
+ end
147
+
148
+ return vulns
149
+ end
150
+
151
+ #
152
+ # Escapes the given SQL and turns it into a SQL injection.
153
+ #
154
+ # @param [#to_s] sql
155
+ # The SQL expression to escape.
156
+ #
157
+ # @return [String]
158
+ # The escaped SQL expression.
159
+ #
160
+ def escape(sql)
161
+ sqli = if sql.start_with?(';')
162
+ "#{@escape_string}#{sql}"
163
+ else
164
+ "#{@escape_string} #{sql}"
165
+ end
166
+
167
+ if @terminate
168
+ sqli << '--'
169
+ else
170
+ sqli.chop! if (@escape_parens && sqli.end_with?(')'))
171
+ sqli.chop! if (@escape_quote && sqli.end_with?("'"))
172
+ end
173
+
174
+ return sqli
175
+ end
176
+
177
+ #
178
+ # Encodes the SQL payload.
179
+ #
180
+ # @see #escape
181
+ #
182
+ def encode_payload(sql)
183
+ escape(sql)
184
+ end
185
+
186
+ #
187
+ # Tests whether the URL is vulnerable to SQL injection.
188
+ #
189
+ # @return [Boolean]
190
+ #
191
+ def vulnerable?
192
+ test_or_true_and_false || test_sleep
193
+ end
194
+
195
+ # SQL error message patterns for various databases.
196
+ ERROR_PATTERNS = {
197
+ postgresql: ErrorPattern[
198
+ /PostgreSQL.*ERROR/,
199
+ /Warning.*\Wpg_/,
200
+ /valid PostgreSQL result/,
201
+ /Npgsql\./,
202
+ /PG::SyntaxError:/,
203
+ /org\.postgresql\.util\.PSQLException/,
204
+ /ERROR:\s\ssyntax error at or near/,
205
+ /ERROR: parser: parse error at or near/,
206
+ /PostgreSQL query failed/,
207
+ /org\.postgresql\.jdbc/,
208
+ /Pdo[.\/_\\]Pgsql/,
209
+ /PSQLException/
210
+ ],
211
+
212
+ mysql: ErrorPattern[
213
+ /SQL syntax.*MySQL/,
214
+ /Warning.*\Wmysqli?_/,
215
+ /MySQLSyntaxErrorException/,
216
+ /valid MySQL result/,
217
+ /check the manual that corresponds to your (MySQL|MariaDB) server version/,
218
+ /Unknown column '[^ ]+' in 'field list'/,
219
+ /MySqlClient\./,
220
+ /com\.mysql\.jdbc/,
221
+ /Zend_Db_(?:Adapter|Statement)_Mysqli_Exception/,
222
+ /Pdo[.\/_\\]Mysql/,
223
+ /MySqlException/
224
+ ],
225
+
226
+ sqlite: ErrorPattern[
227
+ /SQLite\/JDBCDriver/,
228
+ /SQLite\.Exception/,
229
+ /(Microsoft|System)\.Data\.SQLite\.SQLiteException/,
230
+ /Warning.*\W(?:sqlite_|SQLite3::)/,
231
+ /\[SQLITE_ERROR\]/,
232
+ /SQLite error \d+:/,
233
+ /sqlite3\.OperationalError:/,
234
+ /SQLite3::SQLException/,
235
+ /org\.sqlite\.JDBC/,
236
+ /Pdo[.\/_\\]Sqlite/,
237
+ /SQLiteException/
238
+ ],
239
+
240
+ mssql: ErrorPattern[
241
+ /Driver.* SQL[\-\_\ ]*Server/,
242
+ /OLE DB.* SQL Server/,
243
+ /\bSQL Server[^<"]+Driver/,
244
+ /Warning.*\W(?:mssql|sqlsrv)_/,
245
+ /\bSQL Server[^<"]+[0-9a-fA-F]{8}/,
246
+ /System\.Data\.SqlClient\.SqlException/,
247
+ /Exception.*\bRoadhouse\.Cms\./m,
248
+ /Microsoft SQL Native Client error '[0-9a-fA-F]{8}/,
249
+ /\[SQL Server\]/,
250
+ /ODBC SQL Server Driver/,
251
+ /ODBC Driver \d+ for SQL Server/,
252
+ /SQLServer JDBC Driver/,
253
+ /com\.jnetdirect\.jsql/,
254
+ /macromedia\.jdbc\.sqlserver/,
255
+ /Zend_Db_(?:Adapter|Statement)_Sqlsrv_Exception/,
256
+ /com\.microsoft\.sqlserver\.jdbc/,
257
+ /Pdo[.\/_\\](?:Mssql|SqlSrv)/,
258
+ /SQL(?:Srv|Server)Exception/
259
+ ],
260
+
261
+ oracle: ErrorPattern[
262
+ /\bORA-\d{5}/,
263
+ /Oracle error/,
264
+ /Oracle.*Driver/,
265
+ /Warning.*\W(?:oci|ora)_/,
266
+ /quoted string not properly terminated/,
267
+ /SQL command not properly ended/,
268
+ /macromedia\.jdbc\.oracle/,
269
+ /oracle\.jdbc/,
270
+ /Zend_Db_(?:Adapter|Statement)_Oracle_Exception/,
271
+ /Pdo[.\/_\\](?:Oracle|OCI)/,
272
+ /OracleException/
273
+ ]
274
+ }
275
+
276
+ #
277
+ # Checks if the response contains a SQL error message.
278
+ #
279
+ # @param [Net::HTTPResponse] response
280
+ # The HTTP response object to check.
281
+ #
282
+ # @return [Boolean]
283
+ # Indicates whether the response was a `500` and if the respones body
284
+ # contained a SQL error message.
285
+ #
286
+ def check_for_sql_errors(response)
287
+ if response.code == '500'
288
+ ERROR_PATTERNS.each do |database,error_pattern|
289
+ if error_pattern =~ response.body
290
+ return true
291
+ end
292
+ end
293
+ end
294
+
295
+ return false
296
+ end
297
+
298
+ #
299
+ # Returns a random ID.
300
+ #
301
+ # @return [Integer]
302
+ # A four digit ID.
303
+ #
304
+ # @api private
305
+ #
306
+ def random_id
307
+ rand(8_999) + 1_000
308
+ end
309
+
310
+ #
311
+ # Tests whether the URL is vulnerable to SQL injection, using the
312
+ # ` OR 1=1` vs. ` AND 1=0` technique.
313
+ #
314
+ # @return [Boolean]
315
+ #
316
+ # @api private
317
+ #
318
+ def test_or_true_and_false
319
+ id = random_id
320
+ response1 = exploit("OR #{id}=#{id}")
321
+ response2 = exploit("AND #{random_id}=#{random_id}")
322
+
323
+ # check for SQL errors in both responses
324
+ if check_for_sql_errors(response1) || check_for_sql_errors(response2)
325
+ return true
326
+ end
327
+
328
+ if response1.code =~ /^20[0-6]$/ && response2.code =~ /^20[0-6]$/
329
+ # the first response contained more results than the second response
330
+ return response1.body.length > response2.body.length
331
+ elsif response1.code =~ /^20[0-6]$/ && response2.code =~ /^(?:404|500)$/
332
+ # if the second response return an error, that indicates the
333
+ # SQL expression evaluated to false and returned no results.
334
+ return true
335
+ end
336
+ end
337
+
338
+ # Various SQL sleep functions or statements.
339
+ #
340
+ # @api private
341
+ SLEEP_TESTS = [
342
+ 'SLEEP(5)',
343
+ "PG_SLEEP(5)",
344
+ "WAITFOR DELAY '0:0:5'"
345
+ ]
346
+
347
+ #
348
+ # Tests whether the URL is vulnerable to SQL injection, by calling SQL
349
+ # sleep functions to see if it takes longer for the response to be
350
+ # returned.
351
+ #
352
+ # @return [Boolean]
353
+ #
354
+ # @api private
355
+ #
356
+ def test_sleep
357
+ SLEEP_TESTS.each do |sql|
358
+ [sql, ";SELECT #{sql}"].each do |sqli|
359
+ start_time = Time.now
360
+ response = exploit(sqli)
361
+ stop_time = Time.now
362
+ delta = (stop_time - start_time)
363
+
364
+ # check for SQL errors first
365
+ if check_for_sql_errors(response)
366
+ return true
367
+ end
368
+
369
+ # if the response took more than 5 seconds, our SQL sleep function
370
+ # probably worked.
371
+ return true if delta > 5.0
372
+ end
373
+ end
374
+
375
+ return false
376
+ end
377
+
378
+ #
379
+ # Returns the type or kind of vulnerability.
380
+ #
381
+ # @return [Symbol]
382
+ #
383
+ # @note
384
+ # This is used internally to map an vulnerability class to a printable
385
+ # type.
386
+ #
387
+ # @api private
388
+ #
389
+ # @abstract
390
+ #
391
+ def self.vuln_type
392
+ :sqli
393
+ end
394
+
395
+ end
396
+ end
397
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-vulns - A Ruby library for blind vulnerability testing.
4
+ #
5
+ # Copyright (c) 2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-vulns is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-vulns is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-vulns. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/vulns/web_vuln'
22
+
23
+ module Ronin
24
+ module Vulns
25
+ #
26
+ # Represents a Server Side Template Injection (SSTI) vulnerability.
27
+ #
28
+ class SSTI < WebVuln
29
+ #
30
+ # Represents a expression to test SSTI with (ex: `7*7`).
31
+ #
32
+ class TestExpression
33
+
34
+ # The expression string.
35
+ #
36
+ # @return [String]
37
+ attr_reader :string
38
+
39
+ # The expected result of the string.
40
+ #
41
+ # @return [String]
42
+ attr_reader :result
43
+
44
+ #
45
+ # Initializes the test expression.
46
+ #
47
+ # @param [String] string
48
+ # The expression string.
49
+ #
50
+ # @param [String] result
51
+ # The expected result of the expression.
52
+ #
53
+ def initialize(string,result)
54
+ @string = string
55
+ @result = result
56
+ end
57
+
58
+ #
59
+ # Parses an expression string and calculates the result.
60
+ #
61
+ # @param [String] string
62
+ # The expression string to parse.
63
+ #
64
+ # @return [TestExpression]
65
+ # The parsed test expression.
66
+ #
67
+ # @raise [ArgumentError]
68
+ # Could not parse the test expression.
69
+ #
70
+ def self.parse(string)
71
+ unless (match = string.match(/\A(\d+)\s*([\*\/\+\-])\s*(\d+)\z/))
72
+ raise(ArgumentError,"could not parse the expression: #{string.inspect}")
73
+ end
74
+
75
+ lvalue = match[1].to_i
76
+ op = match[2]
77
+ rvalue = match[3].to_i
78
+
79
+ result = case op
80
+ when '*' then lvalue * rvalue
81
+ when '/' then lvalue / rvalue
82
+ when '+' then lvalue + rvalue
83
+ when '-' then lvalue - rvalue
84
+ else
85
+ raise(NotImplementedError,"unsupported expression operator: #{op.inspect}")
86
+ end
87
+
88
+ return new(string,result.to_s)
89
+ end
90
+
91
+ #
92
+ # The test expression as a String.
93
+ #
94
+ # @return [String]
95
+ # The {#string} value.
96
+ #
97
+ def to_s
98
+ @string
99
+ end
100
+
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-vulns - A Ruby library for blind vulnerability testing.
4
+ #
5
+ # Copyright (c) 2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-vulns is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-vulns is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-vulns. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/vulns/web_vuln'
22
+ require 'ronin/vulns/ssti/test_expression'
23
+
24
+ module Ronin
25
+ module Vulns
26
+ #
27
+ # Represents a Server Side Template Injection (SSTI) vulnerability.
28
+ #
29
+ class SSTI < WebVuln
30
+
31
+ # List of common Server Side Template Injection (SSTI) escapes.
32
+ #
33
+ # @api private
34
+ ESCAPES = [
35
+ nil, # does not escape the expression
36
+ ->(expression) { "{{#{expression}}}" },
37
+ ->(expression) { "${#{expression}}" },
38
+ ->(expression) { "${{#{expression}}}" },
39
+ ->(expression) { "\#{#{expression}}" },
40
+ ->(expression) { "<%= #{expression} %>" }
41
+ ]
42
+
43
+ # How to escape the payload so that it's executed.
44
+ #
45
+ # @return [Proc, nil]
46
+ # The proc that will accept a String and return a String, or `nil` to
47
+ # indicate that the payload will not be escaped.
48
+ attr_reader :escape
49
+
50
+ # The test expression to use when testing the URL for SSTI.
51
+ #
52
+ # @return [TestExpression]
53
+ attr_reader :test_expr
54
+
55
+ #
56
+ # Initializes the Server Side Template Injection (SSTI) vulnerability.
57
+ #
58
+ # @param [String, URI::HTTP] url
59
+ # The URL to exploit.
60
+ #
61
+ # @param [Proc, nil] escape
62
+ # How to escape a given payload. Either a proc that will accept a String
63
+ # and return a String, or `nil` to indicate that the payload will not
64
+ # be escaped.
65
+ #
66
+ # @param [TestExpression] test_expr
67
+ # The test payload and expected result to check for when testing the URL
68
+ # for SSTI.
69
+ #
70
+ def initialize(url, escape: nil,
71
+ test_expr: self.class.random_test,
72
+ **kwargs)
73
+ super(url,**kwargs)
74
+
75
+ @escape = escape
76
+ @test_expr = test_expr
77
+
78
+ unless @test_expr
79
+ raise(ArgumentError,"must specify both a test expression")
80
+ end
81
+ end
82
+
83
+ #
84
+ # Generates a random `N*M` SSTI test.
85
+ #
86
+ # @return [TestExpression]
87
+ # A random test expression.
88
+ #
89
+ def self.random_test
90
+ int1 = rand(999) + 1_000
91
+ int2 = rand(999) + 1_000
92
+
93
+ string = "#{int1}*#{int2}"
94
+ result = (int1 * int2).to_s
95
+
96
+ return TestExpression.new(string,result)
97
+ end
98
+
99
+ #
100
+ # Scans the URL for Server Side Template Injection (SSTI) vulnerabilities.
101
+ #
102
+ # @param [URI::HTTP, String] url
103
+ # The URL to scan.
104
+ #
105
+ # @param [Hash{Symbol => Object}] kwargs
106
+ # Additional keyword arguments for {#initialize}.
107
+ #
108
+ # @option kwargs [Proc, nil] :escape
109
+ # The escape method to use. If `escape:` is not given, then all escapes
110
+ # in {ESCAPES} will be tested..
111
+ #
112
+ # @option kwargs [Array<Symbol, String>, Symbol, String, true, nil] :query_params
113
+ # The query param name(s) to test.
114
+ #
115
+ # @option kwargs [Array<Symbol, String>, Symbol, String, nil] :header_names
116
+ # The header name(s) to test.
117
+ #
118
+ # @option kwargs [Array<Symbol, String>, Symbol, String, true, nil] :cookie_params
119
+ # The cookie param name(s) to test.
120
+ #
121
+ # @option kwargs [Array<Symbol, String>, Symbol, String, nil] :form_params
122
+ # The form param name(s) to test.
123
+ #
124
+ # @option kwargs [Ronin::Support::Network::HTTP, nil] :http
125
+ # An HTTP session to use for testing the LFI.
126
+ #
127
+ # @option kwargs [Hash{String => String}, nil] :headers
128
+ # Additional headers to send with requests.
129
+ #
130
+ # @option kwargs [String, Ronin::Support::Network::HTTP::Cookie, nil] :cookie
131
+ # Additional cookie params to send with requests.
132
+ #
133
+ # @option kwargs [String, nil] :referer
134
+ # Optional `Referer` header to send with requests.
135
+ #
136
+ # @option kwargs [Hash{String => String}, nil] :form_data
137
+ # Additional form data to send with requests.
138
+ #
139
+ # @yield [vuln]
140
+ # If a block is given it will be yielded each discovered vulnerability.
141
+ #
142
+ # @yieldparam [SSTI] vuln
143
+ # A discovered SSTI vulnerability in the URL.
144
+ #
145
+ # @return [Array<SSTI>]
146
+ # All discovered SSTI vulnerabilities.
147
+ #
148
+ def self.scan(url, **kwargs,&block)
149
+ if kwargs.has_key?(:escape)
150
+ super(url, **kwargs, &block)
151
+ else
152
+ ESCAPES.each do |escape|
153
+ super(url, escape: escape, **kwargs, &block)
154
+ end
155
+ end
156
+ end
157
+
158
+ #
159
+ # Escapes the payload using {#escape}.
160
+ #
161
+ # @param [String] payload
162
+ #
163
+ # @return [String]
164
+ #
165
+ def encode_payload(payload)
166
+ if @escape then @escape.call(payload)
167
+ else payload
168
+ end
169
+ end
170
+
171
+ #
172
+ # Determine whether the URL is vulnerable to Server Side Template
173
+ # Injection (SSTI).
174
+ #
175
+ # @return [Boolean]
176
+ #
177
+ def vulnerable?
178
+ response = exploit(@test_expr.string)
179
+ body = response.body
180
+
181
+ return body.include?(@test_expr.result)
182
+ end
183
+
184
+ #
185
+ # Returns the type or kind of vulnerability.
186
+ #
187
+ # @return [Symbol]
188
+ #
189
+ # @note
190
+ # This is used internally to map an vulnerability class to a printable
191
+ # type.
192
+ #
193
+ # @api private
194
+ #
195
+ # @abstract
196
+ #
197
+ def self.vuln_type
198
+ :ssti
199
+ end
200
+
201
+ end
202
+ end
203
+ end