ronin-vulns 0.1.4 → 0.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +3 -2
- data/.gitignore +1 -0
- data/ChangeLog.md +52 -0
- data/Gemfile +14 -4
- data/README.md +7 -3
- data/Rakefile +9 -0
- data/data/completions/ronin-vulns +139 -0
- data/gemspec.yml +7 -1
- data/lib/ronin/vulns/cli/command.rb +1 -1
- data/lib/ronin/vulns/cli/commands/command_injection.rb +163 -0
- data/lib/ronin/vulns/cli/commands/completion.rb +63 -0
- data/lib/ronin/vulns/cli/commands/irb.rb +59 -0
- data/lib/ronin/vulns/cli/commands/lfi.rb +21 -9
- data/lib/ronin/vulns/cli/commands/open_redirect.rb +13 -1
- data/lib/ronin/vulns/cli/commands/reflected_xss.rb +13 -1
- data/lib/ronin/vulns/cli/commands/rfi.rb +13 -1
- data/lib/ronin/vulns/cli/commands/scan.rb +21 -9
- data/lib/ronin/vulns/cli/commands/sqli.rb +13 -1
- data/lib/ronin/vulns/cli/commands/ssti.rb +13 -1
- data/lib/ronin/vulns/cli/importable.rb +76 -0
- data/lib/ronin/vulns/cli/printing.rb +184 -0
- data/lib/ronin/vulns/cli/ruby_shell.rb +53 -0
- data/lib/ronin/vulns/cli/web_vuln_command.rb +216 -20
- data/lib/ronin/vulns/cli.rb +3 -2
- data/lib/ronin/vulns/command_injection.rb +267 -0
- data/lib/ronin/vulns/importer.rb +116 -0
- data/lib/ronin/vulns/lfi/test_file.rb +1 -1
- data/lib/ronin/vulns/lfi.rb +1 -1
- data/lib/ronin/vulns/open_redirect.rb +30 -6
- data/lib/ronin/vulns/reflected_xss/context.rb +1 -1
- data/lib/ronin/vulns/reflected_xss/test_string.rb +1 -1
- data/lib/ronin/vulns/reflected_xss.rb +1 -1
- data/lib/ronin/vulns/rfi.rb +64 -9
- data/lib/ronin/vulns/root.rb +1 -1
- data/lib/ronin/vulns/sqli/error_pattern.rb +1 -1
- data/lib/ronin/vulns/sqli.rb +37 -29
- data/lib/ronin/vulns/ssti/test_expression.rb +1 -1
- data/lib/ronin/vulns/ssti.rb +69 -53
- data/lib/ronin/vulns/url_scanner.rb +20 -1
- data/lib/ronin/vulns/version.rb +2 -2
- data/lib/ronin/vulns/vuln.rb +1 -1
- data/lib/ronin/vulns/web_vuln/http_request.rb +40 -1
- data/lib/ronin/vulns/web_vuln.rb +86 -16
- data/man/ronin-vulns-command-injection.1 +109 -0
- data/man/ronin-vulns-command-injection.1.md +112 -0
- data/man/ronin-vulns-completion.1 +76 -0
- data/man/ronin-vulns-completion.1.md +78 -0
- data/man/ronin-vulns-irb.1 +27 -0
- data/man/ronin-vulns-irb.1.md +26 -0
- data/man/ronin-vulns-lfi.1 +55 -52
- data/man/ronin-vulns-lfi.1.md +52 -20
- data/man/ronin-vulns-open-redirect.1 +52 -48
- data/man/ronin-vulns-open-redirect.1.md +50 -18
- data/man/ronin-vulns-reflected-xss.1 +51 -46
- data/man/ronin-vulns-reflected-xss.1.md +49 -17
- data/man/ronin-vulns-rfi.1 +55 -53
- data/man/ronin-vulns-rfi.1.md +52 -20
- data/man/ronin-vulns-scan.1 +69 -70
- data/man/ronin-vulns-scan.1.md +61 -29
- data/man/ronin-vulns-sqli.1 +55 -53
- data/man/ronin-vulns-sqli.1.md +52 -20
- data/man/ronin-vulns-ssti.1 +53 -49
- data/man/ronin-vulns-ssti.1.md +50 -18
- data/man/ronin-vulns.1 +73 -0
- data/man/ronin-vulns.1.md +69 -0
- data/scripts/setup +58 -0
- metadata +37 -6
- data/lib/ronin/vulns/cli/logging.rb +0 -81
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2022-2024 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/db'
|
22
|
+
|
23
|
+
module Ronin
|
24
|
+
module Vulns
|
25
|
+
#
|
26
|
+
# Handles importing discovered {WebVuln web vulnerability} objects into
|
27
|
+
# [ronin-db].
|
28
|
+
#
|
29
|
+
# [ronin-db]: https://github.com/ronin-rb/ronin-db#readme
|
30
|
+
#
|
31
|
+
# ## Examples
|
32
|
+
#
|
33
|
+
# require 'ronin/vulns/url_scanner'
|
34
|
+
# require 'ronin/vulns/importer'
|
35
|
+
#
|
36
|
+
# Ronin::Vulns::URLScanner.scan(url) do |vuln|
|
37
|
+
# Ronin::Vulns::Importer.import(vuln)
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# @since 0.2.0
|
41
|
+
#
|
42
|
+
module Importer
|
43
|
+
#
|
44
|
+
# Imports a web vulnerability into database.
|
45
|
+
#
|
46
|
+
# @param [WebVuln] vuln
|
47
|
+
# The web vulnerability to import.
|
48
|
+
#
|
49
|
+
# @yield [imported]
|
50
|
+
# If a block is given, it will be passed the imported database records.
|
51
|
+
#
|
52
|
+
# @yieldparam [Ronin::DB::WebVuln] imported
|
53
|
+
# The imported web vulnerability record.
|
54
|
+
#
|
55
|
+
# @return [Ronin::DB::WebVuln]
|
56
|
+
# The imported web vuln record.
|
57
|
+
#
|
58
|
+
def self.import(vuln)
|
59
|
+
imported_url = import_url(vuln.url)
|
60
|
+
|
61
|
+
attributes = {
|
62
|
+
url: imported_url,
|
63
|
+
type: vuln.class.vuln_type,
|
64
|
+
|
65
|
+
query_param: vuln.query_param,
|
66
|
+
header_name: vuln.header_name,
|
67
|
+
cookie_param: vuln.cookie_param,
|
68
|
+
form_param: vuln.form_param,
|
69
|
+
request_method: vuln.request_method
|
70
|
+
}
|
71
|
+
|
72
|
+
case vuln
|
73
|
+
when LFI
|
74
|
+
attributes[:lfi_os] = vuln.os
|
75
|
+
attributes[:lfi_depth] = vuln.depth
|
76
|
+
attributes[:lfi_filter_bypass] = vuln.filter_bypass
|
77
|
+
when RFI
|
78
|
+
attributes[:rfi_script_lang] = vuln.script_lang
|
79
|
+
attributes[:rfi_filter_bypass] = vuln.filter_bypass
|
80
|
+
when SQLI
|
81
|
+
attributes[:sqli_escape_quote] = vuln.escape_quote
|
82
|
+
attributes[:sqli_escape_parens] = vuln.escape_parens
|
83
|
+
attributes[:sqli_terminate] = vuln.terminate
|
84
|
+
when SSTI
|
85
|
+
attributes[:ssti_escape_type] = vuln.escape_type
|
86
|
+
when CommandInjection
|
87
|
+
attributes[:command_injection_escape_quote] = vuln.escape_quote
|
88
|
+
attributes[:command_injection_escape_operator] = vuln.escape_operator
|
89
|
+
attributes[:command_injection_terminator] = vuln.terminator
|
90
|
+
end
|
91
|
+
|
92
|
+
imported_vuln = DB::WebVuln.transaction do
|
93
|
+
DB::WebVuln.find_or_create_by(attributes)
|
94
|
+
end
|
95
|
+
|
96
|
+
yield imported_vuln if block_given?
|
97
|
+
return imported_vuln
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Imports a URL into the database.
|
102
|
+
#
|
103
|
+
# @param [URI, String] url
|
104
|
+
# The URL to import.
|
105
|
+
#
|
106
|
+
# @return [Ronin::DB::URL]
|
107
|
+
# The imported URL record.
|
108
|
+
#
|
109
|
+
def self.import_url(url)
|
110
|
+
DB::URL.transaction do
|
111
|
+
DB::URL.find_or_import(url)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library to blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
data/lib/ronin/vulns/lfi.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
@@ -80,7 +80,7 @@ module Ronin
|
|
80
80
|
when '301', '302', '303', '307', '308'
|
81
81
|
if (locations = response.get_fields('Location'))
|
82
82
|
escaped_test_url = Regexp.escape(@test_url)
|
83
|
-
regexp = /\A#{escaped_test_url}
|
83
|
+
regexp = /\A#{escaped_test_url}.*\z/
|
84
84
|
|
85
85
|
locations.last =~ regexp
|
86
86
|
end
|
@@ -95,10 +95,34 @@ module Ronin
|
|
95
95
|
http-equiv\s*=\s*(?: "refresh" | 'refresh' | refresh )\s+
|
96
96
|
content\s*=\s*
|
97
97
|
(?:
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
98
|
+
# content="..."
|
99
|
+
"\s*\d+\s*;\s*url\s*=\s*
|
100
|
+
(?:
|
101
|
+
# content="0; url='...'"
|
102
|
+
'\s*#{escaped_test_url}[^'"]*' |
|
103
|
+
# content="0; url=..."
|
104
|
+
#{escaped_test_url}[^"]*
|
105
|
+
)\s*" |
|
106
|
+
# content='...'
|
107
|
+
'\s*\d+\s*;\s*url\s*=\s*
|
108
|
+
(?:
|
109
|
+
# content='0; url="..."'
|
110
|
+
"\s*#{escaped_test_url}[^"']*" |
|
111
|
+
# content='0; url=...'
|
112
|
+
#{escaped_test_url}[^']*
|
113
|
+
)\s*' |
|
114
|
+
# content=...
|
115
|
+
\s*\d+;url=(?:
|
116
|
+
# content=0;url="..."
|
117
|
+
"\s*#{escaped_test_url}[^\s"]*" |
|
118
|
+
# content=0;url='...'
|
119
|
+
'\s*#{escaped_test_url}[^\s']*' |
|
120
|
+
# content=0;url=...
|
121
|
+
#{escaped_test_url}[^\s/>]*
|
122
|
+
)
|
123
|
+
)
|
124
|
+
\s*
|
125
|
+
# /> or / >
|
102
126
|
(?:/\s*)?>
|
103
127
|
}xi
|
104
128
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
data/lib/ronin/vulns/rfi.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
@@ -47,11 +47,11 @@ module Ronin
|
|
47
47
|
|
48
48
|
# Mapping of scripting languages to RFI test scripts.
|
49
49
|
TEST_SCRIPT_URLS = {
|
50
|
+
php: "#{GITHUB_BASE_URL}/rfi_test.php",
|
50
51
|
asp: "#{GITHUB_BASE_URL}/rfi_test.asp",
|
51
52
|
asp_net: "#{GITHUB_BASE_URL}/rfi_test.aspx",
|
52
|
-
cold_fusion: "#{GITHUB_BASE_URL}/rfi_test.cfm",
|
53
53
|
jsp: "#{GITHUB_BASE_URL}/rfi_test.jsp",
|
54
|
-
|
54
|
+
cold_fusion: "#{GITHUB_BASE_URL}/rfi_test.cfm",
|
55
55
|
perl: "#{GITHUB_BASE_URL}/rfi_test.pl"
|
56
56
|
}
|
57
57
|
|
@@ -59,6 +59,13 @@ module Ronin
|
|
59
59
|
# script is executed.
|
60
60
|
VULN_RESPONSE_STRING = "Security Alert: Remote File Inclusion Detected!"
|
61
61
|
|
62
|
+
# The scripting language that the URL is using.
|
63
|
+
#
|
64
|
+
# @return [:asp, :asp_net, :cold_fusion, :jsp, :php, :perl, nil]
|
65
|
+
#
|
66
|
+
# @since 0.2.0
|
67
|
+
attr_reader :script_lang
|
68
|
+
|
62
69
|
# The filter bypass technique to use.
|
63
70
|
#
|
64
71
|
# @return [nil, :double_encode, :suffix_escape, :null_byte]
|
@@ -93,15 +100,18 @@ module Ronin
|
|
93
100
|
# The URL of the RFI test script. If not specified, it will default to
|
94
101
|
# {test_script_for}.
|
95
102
|
#
|
96
|
-
def initialize(url, script_lang:
|
103
|
+
def initialize(url, script_lang: nil,
|
104
|
+
test_script_url: nil,
|
105
|
+
filter_bypass: nil,
|
106
|
+
**kwargs)
|
97
107
|
super(url,**kwargs)
|
98
108
|
|
109
|
+
@script_lang = script_lang || self.class.infer_script_lang(@url)
|
110
|
+
|
99
111
|
@test_script_url = if test_script_url
|
100
112
|
test_script_url
|
101
|
-
elsif script_lang
|
102
|
-
self.class.test_script_url_for(script_lang)
|
103
|
-
else
|
104
|
-
self.class.test_script_for(@url)
|
113
|
+
elsif @script_lang
|
114
|
+
self.class.test_script_url_for(@script_lang)
|
105
115
|
end
|
106
116
|
|
107
117
|
@filter_bypass = filter_bypass
|
@@ -196,12 +206,57 @@ module Ronin
|
|
196
206
|
# Specifies whether the URL and query parameter are vulnerable to RFI.
|
197
207
|
#
|
198
208
|
def vulnerable?
|
199
|
-
|
209
|
+
if @test_script_url
|
210
|
+
test_a_test_script(@test_script_url)
|
211
|
+
else
|
212
|
+
test_each_test_script
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
#
|
217
|
+
# Determines if a specific test script URL can be remotely injected.
|
218
|
+
#
|
219
|
+
# @param [String] test_script_url
|
220
|
+
# The test script URL to attempt injecting.
|
221
|
+
#
|
222
|
+
# @return [Boolean]
|
223
|
+
# Indicates whether the test script was successfully executed or not.
|
224
|
+
#
|
225
|
+
# @api private
|
226
|
+
#
|
227
|
+
def test_a_test_script(test_script_url)
|
228
|
+
response = exploit(test_script_url)
|
200
229
|
body = response.body
|
201
230
|
|
202
231
|
return body.include?(VULN_RESPONSE_STRING)
|
203
232
|
end
|
204
233
|
|
234
|
+
#
|
235
|
+
# Test each scripting language and RFI test payload in {TEST_SCRIPT_URLS}
|
236
|
+
# until one succeeds.
|
237
|
+
#
|
238
|
+
# @return [Boolean]
|
239
|
+
# Indicates whether one of the test script was successfully executed or
|
240
|
+
# not.
|
241
|
+
#
|
242
|
+
# @note
|
243
|
+
# If one of the test script URLs successfully executes, then
|
244
|
+
# {#script_lang} and {#test_script_url} will be updated accordingly.
|
245
|
+
#
|
246
|
+
# @api private
|
247
|
+
#
|
248
|
+
def test_each_test_script
|
249
|
+
TEST_SCRIPT_URLS.each do |script_lang,test_script_url|
|
250
|
+
if test_a_test_script(test_script_url)
|
251
|
+
@script_lang = script_lang
|
252
|
+
@test_script_url = test_script_url
|
253
|
+
return true
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
return false
|
258
|
+
end
|
259
|
+
|
205
260
|
#
|
206
261
|
# Returns the type or kind of vulnerability.
|
207
262
|
#
|
data/lib/ronin/vulns/root.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
data/lib/ronin/vulns/sqli.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
@@ -100,10 +100,12 @@ module Ronin
|
|
100
100
|
public
|
101
101
|
|
102
102
|
#
|
103
|
-
#
|
103
|
+
# Tests the URL and a specific query param, header name, cookie param, or
|
104
|
+
# form param for SQL injections by enumerating over various SQLi
|
105
|
+
# configurations.
|
104
106
|
#
|
105
|
-
# @param [URI::HTTP
|
106
|
-
# The URL to test
|
107
|
+
# @param [URI::HTTP] url
|
108
|
+
# The URL to test.
|
107
109
|
#
|
108
110
|
# @param [Array<Boolean>, Boolean] escape_quote
|
109
111
|
# Controls whether to escape a quoted string value. If not specified,
|
@@ -123,40 +125,46 @@ module Ronin
|
|
123
125
|
# @param [Hash{Symbol => Object}] kwargs
|
124
126
|
# Additional keyword arguments for {WebVuln.scan}.
|
125
127
|
#
|
126
|
-
# @
|
127
|
-
#
|
128
|
-
# vulnerability.
|
128
|
+
# @option kwargs [Symbol, String, nil] :query_param
|
129
|
+
# The query param name to test.
|
129
130
|
#
|
130
|
-
# @
|
131
|
-
#
|
131
|
+
# @option kwargs [Symbol, String, nil] :header_name
|
132
|
+
# The header name to test.
|
132
133
|
#
|
133
|
-
# @
|
134
|
-
#
|
134
|
+
# @option kwargs [Symbol, String, true, nil] :cookie_param
|
135
|
+
# The cookie param name to test.
|
135
136
|
#
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
137
|
+
# @option kwargs [Symbol, String, nil] :form_param
|
138
|
+
# The form param name to test.
|
139
|
+
#
|
140
|
+
# @return [SQLI] sqli
|
141
|
+
# The first discovered SQLi vulnerability for the specific query param,
|
142
|
+
# header name, cookie param, or form param.
|
143
|
+
#
|
144
|
+
# @api private
|
145
|
+
#
|
146
|
+
# @since 0.2.0
|
147
|
+
#
|
148
|
+
def self.test_param(url, escape_quote: [false, true],
|
149
|
+
escape_parens: [false, true],
|
150
|
+
terminate: [false, true],
|
151
|
+
# keyword arguments for initialize
|
152
|
+
http: , **kwargs)
|
146
153
|
Array(escape_quote).each do |escape_quote_value|
|
147
154
|
Array(escape_parens).each do |escape_parens_value|
|
148
155
|
Array(terminate).each do |terminate_value|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
156
|
+
vuln = new(url, escape_quote: escape_quote_value,
|
157
|
+
escape_parens: escape_parens_value,
|
158
|
+
terminate: terminate_value,
|
159
|
+
http: http,
|
160
|
+
**kwargs)
|
161
|
+
|
162
|
+
return vuln if vuln.vulnerable?
|
155
163
|
end
|
156
164
|
end
|
157
165
|
end
|
158
166
|
|
159
|
-
return
|
167
|
+
return nil
|
160
168
|
end
|
161
169
|
|
162
170
|
#
|
@@ -296,7 +304,7 @@ module Ronin
|
|
296
304
|
#
|
297
305
|
def check_for_sql_errors(response)
|
298
306
|
if response.code == '500'
|
299
|
-
ERROR_PATTERNS.
|
307
|
+
ERROR_PATTERNS.each_value do |error_pattern|
|
300
308
|
if error_pattern =~ response.body
|
301
309
|
return true
|
302
310
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
data/lib/ronin/vulns/ssti.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2022-
|
5
|
+
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-vulns is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU Lesser General Public License as published
|
@@ -31,14 +31,22 @@ module Ronin
|
|
31
31
|
# List of common Server Side Template Injection (SSTI) escapes.
|
32
32
|
#
|
33
33
|
# @api private
|
34
|
-
ESCAPES =
|
35
|
-
nil, # does not escape the expression
|
36
|
-
|
37
|
-
->(expression) { "
|
38
|
-
->(expression) { "${
|
39
|
-
->(expression) { "
|
40
|
-
->(expression) { "
|
41
|
-
|
34
|
+
ESCAPES = {
|
35
|
+
nil => nil, # does not escape the expression
|
36
|
+
|
37
|
+
double_curly_braces: ->(expression) { "{{#{expression}}}" },
|
38
|
+
dollar_curly_braces: ->(expression) { "${#{expression}}" },
|
39
|
+
dollar_double_curly_braces: ->(expression) { "${{#{expression}}}" },
|
40
|
+
pound_curly_braces: ->(expression) { "\#{#{expression}}" },
|
41
|
+
angle_brackets_percent: ->(expression) { "<%= #{expression} %>" }
|
42
|
+
}
|
43
|
+
|
44
|
+
# The type of SSTI escape used.
|
45
|
+
#
|
46
|
+
# @return [:double_curly_braces, :dollar_curly_braces, :dollar_double_curly_braces, :pound_curly_braces, :angle_brackets_percent, :custom, nil]
|
47
|
+
#
|
48
|
+
# @since 0.2.0
|
49
|
+
attr_reader :escape_type
|
42
50
|
|
43
51
|
# How to escape the payload so that it's executed.
|
44
52
|
#
|
@@ -58,21 +66,38 @@ module Ronin
|
|
58
66
|
# @param [String, URI::HTTP] url
|
59
67
|
# The URL to exploit.
|
60
68
|
#
|
61
|
-
# @param [Proc, nil] escape
|
69
|
+
# @param [:double_curly_braces, :dollar_curly_braces, :dollar_double_curly_braces, :pound_curly_braces, :angle_brackets_percent, :custom, Proc, nil] escape
|
62
70
|
# How to escape a given payload. Either a proc that will accept a String
|
63
|
-
# and return a String,
|
64
|
-
# be escaped.
|
71
|
+
# and return a String, a Symbol describing the template syntax to use,
|
72
|
+
# or `nil` to indicate that the payload will not be escaped.
|
65
73
|
#
|
66
74
|
# @param [TestExpression] test_expr
|
67
75
|
# The test payload and expected result to check for when testing the URL
|
68
76
|
# for SSTI.
|
69
77
|
#
|
70
|
-
|
78
|
+
# @raise [ArgumentError]
|
79
|
+
# An unknown `escape_type:` or `escape:` value was given, or no
|
80
|
+
# `test_expr:` was given.
|
81
|
+
#
|
82
|
+
def initialize(url, escape: nil,
|
71
83
|
test_expr: self.class.random_test,
|
72
84
|
**kwargs)
|
73
85
|
super(url,**kwargs)
|
74
86
|
|
75
|
-
|
87
|
+
case escape
|
88
|
+
when Symbol
|
89
|
+
@escape_type = escape
|
90
|
+
@escape = ESCAPES.fetch(escape) do
|
91
|
+
raise(ArgumentError,"unknown template syntax: #{escape_type.inspect}")
|
92
|
+
end
|
93
|
+
when Proc
|
94
|
+
@escape_type = :custom
|
95
|
+
@escape = escape
|
96
|
+
when nil # no-op
|
97
|
+
else
|
98
|
+
raise(ArgumentError,"invalid escape type, must be a Symbol, Proc, or nil: #{escape.inspect}")
|
99
|
+
end
|
100
|
+
|
76
101
|
@test_expr = test_expr
|
77
102
|
|
78
103
|
unless @test_expr
|
@@ -97,62 +122,53 @@ module Ronin
|
|
97
122
|
end
|
98
123
|
|
99
124
|
#
|
100
|
-
#
|
125
|
+
# Tests the URL and a specific query param, header name, cookie param, or
|
126
|
+
# form param for a Server Side Template Injection (SSTI) vulnerability
|
127
|
+
# by enumerating over various SSTI syntaxes.
|
101
128
|
#
|
102
|
-
# @param [URI::HTTP
|
103
|
-
# The URL to
|
129
|
+
# @param [URI::HTTP] url
|
130
|
+
# The URL to test.
|
104
131
|
#
|
105
|
-
# @param [Array<Proc>, Proc, nil] escape
|
132
|
+
# @param [Array<Symbol, Proc>, Symbol, Proc, nil] escape
|
106
133
|
# The escape method to use. If `escape:` is not given, then all escapes
|
107
|
-
# in {ESCAPES} will be tested..
|
134
|
+
# names in {ESCAPES} will be tested..
|
135
|
+
#
|
136
|
+
# @param [Ronin::Support::Network::HTTP] http
|
137
|
+
# The HTTP session to use for testing the URL.
|
108
138
|
#
|
109
139
|
# @param [Hash{Symbol => Object}] kwargs
|
110
140
|
# Additional keyword arguments for {#initialize}.
|
111
141
|
#
|
112
|
-
# @option kwargs [
|
113
|
-
# The query param name
|
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.
|
142
|
+
# @option kwargs [Symbol, String, true, nil] :query_param
|
143
|
+
# The query param name to test.
|
123
144
|
#
|
124
|
-
# @option kwargs [
|
125
|
-
#
|
145
|
+
# @option kwargs [Symbol, String, nil] :header_name
|
146
|
+
# The header name to test.
|
126
147
|
#
|
127
|
-
# @option kwargs [
|
128
|
-
#
|
148
|
+
# @option kwargs [Symbol, String, true, nil] :cookie_param
|
149
|
+
# The cookie param name to test.
|
129
150
|
#
|
130
|
-
# @option kwargs [
|
131
|
-
#
|
151
|
+
# @option kwargs [Symbol, String, nil] :form_param
|
152
|
+
# The form param name to test.
|
132
153
|
#
|
133
|
-
# @
|
134
|
-
#
|
154
|
+
# @return [SSTI, nil]
|
155
|
+
# The first discovered web vulnerability for the specific query param,
|
156
|
+
# header name, cookie param, or form param.
|
135
157
|
#
|
136
|
-
# @
|
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.
|
158
|
+
# @api private
|
144
159
|
#
|
145
|
-
# @
|
146
|
-
# All discovered SSTI vulnerabilities.
|
160
|
+
# @since 0.2.0
|
147
161
|
#
|
148
|
-
def self.
|
149
|
-
|
162
|
+
def self.test_param(url, escape: ESCAPES.keys,
|
163
|
+
# initialize keyword arguments
|
164
|
+
http: , **kwargs)
|
165
|
+
Array(escape).each do |escape_value|
|
166
|
+
vuln = new(url, escape: escape_value, http: http, **kwargs)
|
150
167
|
|
151
|
-
|
152
|
-
vulns.concat(super(url, escape: escape_char, **kwargs, &block))
|
168
|
+
return vuln if vuln.vulnerable?
|
153
169
|
end
|
154
170
|
|
155
|
-
return
|
171
|
+
return nil
|
156
172
|
end
|
157
173
|
|
158
174
|
#
|