ronin-vulns 0.1.0.beta1
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/.document +5 -0
- data/.github/workflows/ruby.yml +31 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +22 -0
- data/Gemfile +34 -0
- data/README.md +328 -0
- data/Rakefile +34 -0
- data/bin/ronin-vulns +19 -0
- data/data/rfi_test.asp +21 -0
- data/data/rfi_test.aspx +25 -0
- data/data/rfi_test.cfm +27 -0
- data/data/rfi_test.jsp +19 -0
- data/data/rfi_test.php +24 -0
- data/data/rfi_test.pl +25 -0
- data/gemspec.yml +41 -0
- data/lib/ronin/vulns/cli/command.rb +39 -0
- data/lib/ronin/vulns/cli/commands/lfi.rb +145 -0
- data/lib/ronin/vulns/cli/commands/open_redirect.rb +119 -0
- data/lib/ronin/vulns/cli/commands/reflected_xss.rb +99 -0
- data/lib/ronin/vulns/cli/commands/rfi.rb +156 -0
- data/lib/ronin/vulns/cli/commands/scan.rb +316 -0
- data/lib/ronin/vulns/cli/commands/sqli.rb +133 -0
- data/lib/ronin/vulns/cli/commands/ssti.rb +126 -0
- data/lib/ronin/vulns/cli/logging.rb +78 -0
- data/lib/ronin/vulns/cli/web_vuln_command.rb +347 -0
- data/lib/ronin/vulns/cli.rb +45 -0
- data/lib/ronin/vulns/lfi/test_file.rb +91 -0
- data/lib/ronin/vulns/lfi.rb +266 -0
- data/lib/ronin/vulns/open_redirect.rb +118 -0
- data/lib/ronin/vulns/reflected_xss/context.rb +224 -0
- data/lib/ronin/vulns/reflected_xss/test_string.rb +149 -0
- data/lib/ronin/vulns/reflected_xss.rb +184 -0
- data/lib/ronin/vulns/rfi.rb +224 -0
- data/lib/ronin/vulns/root.rb +28 -0
- data/lib/ronin/vulns/sqli/error_pattern.rb +89 -0
- data/lib/ronin/vulns/sqli.rb +397 -0
- data/lib/ronin/vulns/ssti/test_expression.rb +104 -0
- data/lib/ronin/vulns/ssti.rb +203 -0
- data/lib/ronin/vulns/url_scanner.rb +218 -0
- data/lib/ronin/vulns/version.rb +26 -0
- data/lib/ronin/vulns/vuln.rb +49 -0
- data/lib/ronin/vulns/web_vuln/http_request.rb +223 -0
- data/lib/ronin/vulns/web_vuln.rb +774 -0
- data/man/ronin-vulns-lfi.1 +107 -0
- data/man/ronin-vulns-lfi.1.md +80 -0
- data/man/ronin-vulns-open-redirect.1 +98 -0
- data/man/ronin-vulns-open-redirect.1.md +73 -0
- data/man/ronin-vulns-reflected-xss.1 +95 -0
- data/man/ronin-vulns-reflected-xss.1.md +71 -0
- data/man/ronin-vulns-rfi.1 +107 -0
- data/man/ronin-vulns-rfi.1.md +80 -0
- data/man/ronin-vulns-scan.1 +138 -0
- data/man/ronin-vulns-scan.1.md +103 -0
- data/man/ronin-vulns-sqli.1 +107 -0
- data/man/ronin-vulns-sqli.1.md +80 -0
- data/man/ronin-vulns-ssti.1 +99 -0
- data/man/ronin-vulns-ssti.1.md +74 -0
- data/ronin-vulns.gemspec +60 -0
- metadata +161 -0
@@ -0,0 +1,149 @@
|
|
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
|
+
|
24
|
+
module Ronin
|
25
|
+
module Vulns
|
26
|
+
class ReflectedXSS < WebVuln
|
27
|
+
#
|
28
|
+
# A test string of characters to determine which special characters are
|
29
|
+
# escaped/filtered and which are passed through.
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
#
|
33
|
+
class TestString
|
34
|
+
|
35
|
+
# The test string.
|
36
|
+
#
|
37
|
+
# @return [String]
|
38
|
+
attr_reader :string
|
39
|
+
|
40
|
+
# The test regexp to determine which special characters were
|
41
|
+
# escaped/filtered and which were passed through unescaped.
|
42
|
+
#
|
43
|
+
# @return [Regexp]
|
44
|
+
attr_reader :regexp
|
45
|
+
|
46
|
+
#
|
47
|
+
# Initializes the test string.
|
48
|
+
#
|
49
|
+
# @param [String] string
|
50
|
+
# The test string.
|
51
|
+
#
|
52
|
+
# @param [Regexp] regexp
|
53
|
+
# The test regexp to determine which special characters were
|
54
|
+
# escaped/filtered and which were passed through unescaped.
|
55
|
+
#
|
56
|
+
def initialize(string,regexp)
|
57
|
+
@string = string
|
58
|
+
@regexp = regexp
|
59
|
+
end
|
60
|
+
|
61
|
+
# Special characters and their common escaped equivalents.
|
62
|
+
ESCAPED_CHARS = {
|
63
|
+
"'" => ['%27', ''', "\\'"],
|
64
|
+
'"' => ['%22', '"', "\\\""],
|
65
|
+
' ' => ['+', '%20', ' '],
|
66
|
+
'=' => ['%3D'],
|
67
|
+
'/' => ['%2F'],
|
68
|
+
'<' => ['%3C', '<'],
|
69
|
+
'>' => ['%3E', '>'],
|
70
|
+
'&' => ['%26', '&'],
|
71
|
+
}
|
72
|
+
|
73
|
+
#
|
74
|
+
# Builds a test string from a mapping of characters and their HTML
|
75
|
+
# escaped equivalents.
|
76
|
+
#
|
77
|
+
# @param [String] chars
|
78
|
+
# The characters for the test string.
|
79
|
+
#
|
80
|
+
# @return [TestString]
|
81
|
+
# The built test string.
|
82
|
+
#
|
83
|
+
def self.build(chars)
|
84
|
+
string = String.new
|
85
|
+
regexp = String.new
|
86
|
+
|
87
|
+
chars.each_char do |char|
|
88
|
+
string << char
|
89
|
+
|
90
|
+
regexp << "(?:(#{Regexp.escape(char)})"
|
91
|
+
|
92
|
+
if (escaped_chars = ESCAPED_CHARS[char])
|
93
|
+
escaped_chars.each do |string|
|
94
|
+
regexp << "|#{Regexp.escape(string)}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
regexp << ')?'
|
99
|
+
end
|
100
|
+
|
101
|
+
return new(string,Regexp.new(regexp))
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Wraps the test string with a prefix and suffix.
|
106
|
+
#
|
107
|
+
# @param [String] prefix
|
108
|
+
# The prefix string to prepend to the test string.
|
109
|
+
#
|
110
|
+
# @param [String] suffix
|
111
|
+
# The suffix string to append to the test string.
|
112
|
+
#
|
113
|
+
# @return [TestString]
|
114
|
+
# The new test string with the prefix and suffix.
|
115
|
+
#
|
116
|
+
def wrap(prefix,suffix)
|
117
|
+
self.class.new(
|
118
|
+
"#{prefix}#{@string}#{suffix}",
|
119
|
+
/#{Regexp.escape(prefix)}#{@regexp}#{Regexp.escape(suffix)}/
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# Matches the response body against {#regexp}.
|
125
|
+
#
|
126
|
+
# @param [String] body
|
127
|
+
# The response body to try matching.
|
128
|
+
#
|
129
|
+
# @return [MatchData, nil]
|
130
|
+
# The match data or `nil` if the body did not match {#regexp}.
|
131
|
+
#
|
132
|
+
def match(body)
|
133
|
+
body.match(@regexp)
|
134
|
+
end
|
135
|
+
|
136
|
+
#
|
137
|
+
# Converts the test string to a String.
|
138
|
+
#
|
139
|
+
# @return [String]
|
140
|
+
# The {#string}.
|
141
|
+
#
|
142
|
+
def to_s
|
143
|
+
@string
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,184 @@
|
|
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/reflected_xss/test_string'
|
24
|
+
require 'ronin/vulns/reflected_xss/context'
|
25
|
+
|
26
|
+
require 'set'
|
27
|
+
|
28
|
+
module Ronin
|
29
|
+
module Vulns
|
30
|
+
#
|
31
|
+
# Represents a (Reflected) Cross Site Scripting (XSS) vulnerability.
|
32
|
+
#
|
33
|
+
# ## Features
|
34
|
+
#
|
35
|
+
# * Tests a URL with just one HTTP request (per param).
|
36
|
+
# * Tests which HTML special characters are allowed.
|
37
|
+
# * Identifies the context, tag name, and/or attribute name of the XSS.
|
38
|
+
# * Determines viability of XSS based on the context.
|
39
|
+
# * Includes random data in the test values.
|
40
|
+
#
|
41
|
+
class ReflectedXSS < WebVuln
|
42
|
+
|
43
|
+
# The characters that are allowed and will not be escaped or filtered.
|
44
|
+
#
|
45
|
+
# @return [Set<String>, nil]
|
46
|
+
attr_reader :allowed_chars
|
47
|
+
|
48
|
+
# The context the XSS occurred in.
|
49
|
+
#
|
50
|
+
# @return [Context, nil]
|
51
|
+
attr_reader :context
|
52
|
+
|
53
|
+
#
|
54
|
+
# Tests the test string by sending an HTTP request with the test string
|
55
|
+
# embedded.
|
56
|
+
#
|
57
|
+
# @param [TestString] test_string
|
58
|
+
#
|
59
|
+
# @yield [body, match]
|
60
|
+
# If the response was `text/html` and the test string appears (at least
|
61
|
+
# partially) in the response body, the response body and match data will
|
62
|
+
# be yielded.
|
63
|
+
#
|
64
|
+
# @yieldparam [String] body
|
65
|
+
# The response body.
|
66
|
+
#
|
67
|
+
# @yieldparam [MatchData] match
|
68
|
+
# The matched data for the test string.
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
#
|
72
|
+
def test_string(test_string)
|
73
|
+
test_string = test_string.wrap(random_value,random_value)
|
74
|
+
|
75
|
+
response = exploit("#{original_value}#{test_string}")
|
76
|
+
content_type = response.content_type
|
77
|
+
body = response.body
|
78
|
+
|
79
|
+
if content_type && content_type.include?('text/html')
|
80
|
+
if (match = test_string.match(body))
|
81
|
+
yield body, match
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Tests whether characters in the test string will be escaped/filtered or
|
88
|
+
# passed through and updates {#allowed_chars}.
|
89
|
+
#
|
90
|
+
# @param [TestString] test_string
|
91
|
+
# The test string to send.
|
92
|
+
#
|
93
|
+
# @yield [body, match]
|
94
|
+
# If a block is given, it will be passed the response body and the
|
95
|
+
# regular expression match data, if the response contains the test
|
96
|
+
# string.
|
97
|
+
#
|
98
|
+
# @yieldparam [String] body
|
99
|
+
# The response body.
|
100
|
+
#
|
101
|
+
# @yieldparam [MatchData] match
|
102
|
+
# The matched data for the test string.
|
103
|
+
#
|
104
|
+
# @api private
|
105
|
+
#
|
106
|
+
def test_chars(test_string)
|
107
|
+
test_string(test_string) do |body,match|
|
108
|
+
@allowed_chars ||= Set.new
|
109
|
+
@allowed_chars.merge(match.captures.compact)
|
110
|
+
|
111
|
+
yield body, match if block_given?
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# HTML special characters to test.
|
116
|
+
HTML_TEST_STRING = TestString.build("'\"= /><")
|
117
|
+
|
118
|
+
#
|
119
|
+
# Tests which HTML characters are accepted or escaped/filtered.
|
120
|
+
#
|
121
|
+
# @yield [body, match]
|
122
|
+
# If a block is given, it will be passed the response body and the
|
123
|
+
# regular expression match data, if the response contains the test
|
124
|
+
# string.
|
125
|
+
#
|
126
|
+
# @yieldparam [String] body
|
127
|
+
# The response body.
|
128
|
+
#
|
129
|
+
# @yieldparam [MatchData] match
|
130
|
+
# The matched data for the test string.
|
131
|
+
#
|
132
|
+
# @api private
|
133
|
+
#
|
134
|
+
def test_html_chars(&block)
|
135
|
+
test_chars(HTML_TEST_STRING,&block)
|
136
|
+
end
|
137
|
+
|
138
|
+
#
|
139
|
+
# Tests whether the URL is vulnerable to (Reflected) Cross Site Scripting
|
140
|
+
# (XSS).
|
141
|
+
#
|
142
|
+
# @return [Boolean]
|
143
|
+
# Indicates whether the URL is vulnerable to (Reflected) Cross Site
|
144
|
+
# Scripting (XSS).
|
145
|
+
#
|
146
|
+
# @note
|
147
|
+
# If the URL is vulnerable, {#allowed_chars} and {#context} will be set.
|
148
|
+
#
|
149
|
+
def vulnerable?
|
150
|
+
# test HTML special characters
|
151
|
+
test_html_chars do |body,match|
|
152
|
+
xss_index = match.begin(0)
|
153
|
+
|
154
|
+
# determine the contents which the XSS occurs
|
155
|
+
if (@context = Context.identify(body,xss_index))
|
156
|
+
# determine whether enough special HTML characters are allowed to
|
157
|
+
# escape the context which the XSS occurs.
|
158
|
+
return @context.viable?(@allowed_chars)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
return false
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Returns the type or kind of vulnerability.
|
167
|
+
#
|
168
|
+
# @return [Symbol]
|
169
|
+
#
|
170
|
+
# @note
|
171
|
+
# This is used internally to map an vulnerability class to a printable
|
172
|
+
# type.
|
173
|
+
#
|
174
|
+
# @api private
|
175
|
+
#
|
176
|
+
# @abstract
|
177
|
+
#
|
178
|
+
def self.vuln_type
|
179
|
+
:reflected_xss
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,224 @@
|
|
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/version'
|
23
|
+
|
24
|
+
require 'ronin/support/network/http'
|
25
|
+
require 'uri/query_params'
|
26
|
+
|
27
|
+
module Ronin
|
28
|
+
module Vulns
|
29
|
+
#
|
30
|
+
# Represents a Remote File Inclusion (RFI) vulnerability.
|
31
|
+
#
|
32
|
+
class RFI < WebVuln
|
33
|
+
|
34
|
+
# The script extensions and their languages
|
35
|
+
URL_EXTS = {
|
36
|
+
'.asp' => :asp,
|
37
|
+
'.aspx' => :asp_net,
|
38
|
+
'.cfm' => :cold_fusion,
|
39
|
+
'.cfml' => :cold_fusion,
|
40
|
+
'.jsp' => :jsp,
|
41
|
+
'.php' => :php,
|
42
|
+
'.pl' => :perl
|
43
|
+
}
|
44
|
+
|
45
|
+
# The github.com base URL for all RFI test scripts.
|
46
|
+
GITHUB_BASE_URL = "https://raw.githubusercontent.com/ronin-rb/ronin-vulns/#{VERSION}/data"
|
47
|
+
|
48
|
+
# Mapping of scripting languages to RFI test scripts.
|
49
|
+
TEST_SCRIPT_URLS = {
|
50
|
+
asp: "#{GITHUB_BASE_URL}/rfi_test.asp",
|
51
|
+
asp_net: "#{GITHUB_BASE_URL}/rfi_test.aspx",
|
52
|
+
cold_fusion: "#{GITHUB_BASE_URL}/rfi_test.cfm",
|
53
|
+
jsp: "#{GITHUB_BASE_URL}/rfi_test.jsp",
|
54
|
+
php: "#{GITHUB_BASE_URL}/rfi_test.php",
|
55
|
+
perl: "#{GITHUB_BASE_URL}/rfi_test.pl"
|
56
|
+
}
|
57
|
+
|
58
|
+
# The string that will be returned if the Remote File Inclusion (RFI)
|
59
|
+
# script is executed.
|
60
|
+
VULN_RESPONSE_STRING = "Security Alert: Remote File Inclusion Detected!"
|
61
|
+
|
62
|
+
# The filter bypass technique to use.
|
63
|
+
#
|
64
|
+
# @return [nil, :double_encode, :suffix_escape, :null_byte]
|
65
|
+
attr_reader :filter_bypass
|
66
|
+
|
67
|
+
# URL of the Remote File Inclusion (RFI) Test script
|
68
|
+
#
|
69
|
+
# @return [URI::HTTP, String]
|
70
|
+
attr_reader :test_script_url
|
71
|
+
|
72
|
+
#
|
73
|
+
# Creates a new Remote File Inclusion (RFI) object.
|
74
|
+
#
|
75
|
+
# @param [String, URI::HTTP] url
|
76
|
+
# The URL to attempt to exploit.
|
77
|
+
#
|
78
|
+
# @param [:null_byte, :double_encode, nil] filter_bypass
|
79
|
+
# Specifies which filter bypass technique to use.
|
80
|
+
# * `:double_encode` - will cause the inclusion URL to be URI escaped
|
81
|
+
# twice.
|
82
|
+
# * `:suffix_escape` - escape any appended suffix (ex: `param + ".php"`)
|
83
|
+
# by adding a URI fragment character (`#`) to the end of the RFI
|
84
|
+
# script URL. The fragment component of the URI is not sent to the
|
85
|
+
# web server.
|
86
|
+
# * `:null_byte` - will cause the inclusion URL to be appended with a
|
87
|
+
# `%00` character. **Note:* this technique only works on PHP < 5.3.
|
88
|
+
#
|
89
|
+
# @param [:asp, :asp_net, :cold_fusion, :jsp, :php, :perl, nil] script_lang
|
90
|
+
# Explicitly specifies the scripting language that the URL uses.
|
91
|
+
#
|
92
|
+
# @param [String, URI::HTTP, nil] test_script_url
|
93
|
+
# The URL of the RFI test script. If not specified, it will default to
|
94
|
+
# {test_script_for}.
|
95
|
+
#
|
96
|
+
def initialize(url, script_lang: nil, test_script_url: nil, filter_bypass: nil, **kwargs)
|
97
|
+
super(url,**kwargs)
|
98
|
+
|
99
|
+
@test_script_url = if test_script_url
|
100
|
+
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)
|
105
|
+
end
|
106
|
+
|
107
|
+
@filter_bypass = filter_bypass
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Returns the test script URL for the given scripting language.
|
112
|
+
#
|
113
|
+
# @param [:asp, :asp_net, :cold_fusion, :jsp, :php, :perl] script_lang
|
114
|
+
# The scripting language.
|
115
|
+
#
|
116
|
+
# @return [String]
|
117
|
+
# The test script URL for the given scripting language.
|
118
|
+
#
|
119
|
+
# @raise [ArgumentError]
|
120
|
+
# An unknown scripting language value was given.
|
121
|
+
#
|
122
|
+
def self.test_script_url_for(script_lang)
|
123
|
+
TEST_SCRIPT_URLS.fetch(script_lang) do
|
124
|
+
raise(ArgumentError,"unknown scripting language: #{script_lang.inspect}")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Attempts to infer the programming language used for the web page at the
|
130
|
+
# given URL.
|
131
|
+
#
|
132
|
+
# @param [String, URI::HTTP] url
|
133
|
+
# The URL to infer from.
|
134
|
+
#
|
135
|
+
# @return [:asp, :cold_fusion, :jsp, :php, :perl, nil]
|
136
|
+
# The programming language inferred from the URL.
|
137
|
+
#
|
138
|
+
def self.infer_script_lang(url)
|
139
|
+
url = URI(url)
|
140
|
+
|
141
|
+
return URL_EXTS[File.extname(url.path)]
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Selects the RFI test script for the scripting language used by the given
|
146
|
+
# URL.
|
147
|
+
#
|
148
|
+
# @param [String, URI::HTTP] url
|
149
|
+
# The URL to test.
|
150
|
+
#
|
151
|
+
# @return [String, nil]
|
152
|
+
# The RFI test script URL or `nil` if the scripting language could not
|
153
|
+
# be inferred from the URL.
|
154
|
+
#
|
155
|
+
def self.test_script_for(url)
|
156
|
+
if (lang = infer_script_lang(url))
|
157
|
+
TEST_SCRIPT_URLS.fetch(lang)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
#
|
162
|
+
# Optionally applies a filter bypass technique to the RFI URL.
|
163
|
+
#
|
164
|
+
# @param [URI::HTTP, String] url
|
165
|
+
# The RFI URL to optionall encode before it will be injected into a
|
166
|
+
# HTTP request.
|
167
|
+
#
|
168
|
+
# @return [String]
|
169
|
+
# The optionally encoded RFI URL.
|
170
|
+
#
|
171
|
+
def encode_payload(url)
|
172
|
+
url = url.to_s
|
173
|
+
|
174
|
+
case @filter_bypass
|
175
|
+
when :double_encode
|
176
|
+
# Optionally double URI encodes the script URL
|
177
|
+
url = URI::QueryParams.escape(url)
|
178
|
+
when :suffix_escape
|
179
|
+
# Optionally append a '#' character to escape any appended suffixes
|
180
|
+
# (ex: `param + ".php"`).
|
181
|
+
url = "#{url}#"
|
182
|
+
when :null_byte
|
183
|
+
# Optionally append a null-byte
|
184
|
+
# NOTE: uri-query_params will automatically URI encode the null byte
|
185
|
+
url = "#{url}\0"
|
186
|
+
end
|
187
|
+
|
188
|
+
return url
|
189
|
+
end
|
190
|
+
|
191
|
+
#
|
192
|
+
# Tests whether the URL and query parameter are vulnerable to Remote File
|
193
|
+
# Inclusion (RFI).
|
194
|
+
#
|
195
|
+
# @return [Boolean]
|
196
|
+
# Specifies whether the URL and query parameter are vulnerable to RFI.
|
197
|
+
#
|
198
|
+
def vulnerable?
|
199
|
+
response = exploit(@test_script_url)
|
200
|
+
body = response.body
|
201
|
+
|
202
|
+
return body.include?(VULN_RESPONSE_STRING)
|
203
|
+
end
|
204
|
+
|
205
|
+
#
|
206
|
+
# Returns the type or kind of vulnerability.
|
207
|
+
#
|
208
|
+
# @return [Symbol]
|
209
|
+
#
|
210
|
+
# @note
|
211
|
+
# This is used internally to map an vulnerability class to a printable
|
212
|
+
# type.
|
213
|
+
#
|
214
|
+
# @api private
|
215
|
+
#
|
216
|
+
# @abstract
|
217
|
+
#
|
218
|
+
def self.vuln_type
|
219
|
+
:rfi
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-vulns - A Ruby library for blind vulnerability testing.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2007-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
|
+
module Ronin
|
22
|
+
module Vulns
|
23
|
+
# Path to `ronin-vulns` root directory.
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
ROOT = File.expand_path(File.join(__dir__,'..','..','..'))
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,89 @@
|
|
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
|
+
class SQLI < WebVuln
|
26
|
+
#
|
27
|
+
# Represents a collection of patterns for SQL error messages for a
|
28
|
+
# particular database.
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
#
|
32
|
+
class ErrorPattern
|
33
|
+
|
34
|
+
# The combined error message regexp.
|
35
|
+
#
|
36
|
+
# @return [Regexp]
|
37
|
+
attr_reader :regexp
|
38
|
+
|
39
|
+
#
|
40
|
+
# Initializes the error pattern.
|
41
|
+
#
|
42
|
+
# @param [Regexp] regexp
|
43
|
+
# The combined of regular expression.
|
44
|
+
#
|
45
|
+
def initialize(regexp)
|
46
|
+
@regexp = regexp
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Creates an error pattern from multiple different regexps.
|
51
|
+
#
|
52
|
+
# @param [Array<Regexp>] regexps
|
53
|
+
# The collection of regular expressions.
|
54
|
+
#
|
55
|
+
def self.[](*regexps)
|
56
|
+
new(Regexp.union(regexps))
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Tests whether the respones body contains a SQL error.
|
61
|
+
#
|
62
|
+
# @param [String] response_body
|
63
|
+
# The HTTP response body.
|
64
|
+
#
|
65
|
+
# @return [MatchData, nil]
|
66
|
+
# The match data if the {#regexp} is found within the response body.
|
67
|
+
#
|
68
|
+
def match(response_body)
|
69
|
+
@regexp.match(response_body)
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Tests whether the file was successfully included into the response
|
74
|
+
# body.
|
75
|
+
#
|
76
|
+
# @param [String] response_body
|
77
|
+
# The HTTP response body.
|
78
|
+
#
|
79
|
+
# @return [Integer, nil]
|
80
|
+
# Indicates whether the {#regexp} was found in the response body.
|
81
|
+
#
|
82
|
+
def =~(response_body)
|
83
|
+
response_body =~ @regexp
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|