ronin-support 0.3.0 → 0.4.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog.md +77 -7
- data/README.md +19 -3
- data/gemspec.yml +2 -2
- data/lib/ronin/extensions/regexp.rb +50 -2
- data/lib/ronin/extensions/string.rb +1 -0
- data/lib/ronin/formatting.rb +1 -0
- data/lib/ronin/formatting/extensions.rb +1 -0
- data/lib/ronin/formatting/extensions/binary/string.rb +56 -5
- data/lib/ronin/formatting/extensions/html/string.rb +6 -7
- data/lib/ronin/formatting/extensions/sql/string.rb +34 -0
- data/lib/ronin/formatting/extensions/text/string.rb +0 -180
- data/lib/ronin/fuzzing.rb +21 -0
- data/lib/ronin/fuzzing/extensions.rb +20 -0
- data/lib/ronin/fuzzing/extensions/string.rb +380 -0
- data/lib/ronin/fuzzing/fuzzing.rb +191 -0
- data/lib/ronin/network/esmtp.rb +94 -1
- data/lib/ronin/network/extensions/esmtp/net.rb +2 -82
- data/lib/ronin/network/extensions/http/net.rb +1 -736
- data/lib/ronin/network/extensions/imap/net.rb +1 -103
- data/lib/ronin/network/extensions/pop3/net.rb +1 -71
- data/lib/ronin/network/extensions/smtp/net.rb +2 -157
- data/lib/ronin/network/extensions/ssl/net.rb +1 -132
- data/lib/ronin/network/extensions/tcp/net.rb +2 -296
- data/lib/ronin/network/extensions/telnet/net.rb +1 -135
- data/lib/ronin/network/extensions/udp/net.rb +2 -214
- data/lib/ronin/network/http/http.rb +750 -5
- data/lib/ronin/network/imap.rb +105 -2
- data/lib/ronin/network/mixins.rb +1 -1
- data/lib/ronin/network/mixins/esmtp.rb +49 -52
- data/lib/ronin/network/mixins/http.rb +49 -53
- data/lib/ronin/network/mixins/imap.rb +47 -44
- data/lib/ronin/network/mixins/mixin.rb +58 -0
- data/lib/ronin/network/mixins/pop3.rb +44 -38
- data/lib/ronin/network/mixins/smtp.rb +49 -51
- data/lib/ronin/network/mixins/tcp.rb +56 -69
- data/lib/ronin/network/mixins/telnet.rb +57 -50
- data/lib/ronin/network/mixins/udp.rb +48 -52
- data/lib/ronin/network/network.rb +1 -0
- data/lib/ronin/network/pop3.rb +72 -2
- data/lib/ronin/network/smtp/email.rb +1 -0
- data/lib/ronin/network/smtp/smtp.rb +159 -3
- data/lib/ronin/network/ssl.rb +131 -2
- data/lib/ronin/network/tcp.rb +306 -1
- data/lib/ronin/network/telnet.rb +136 -2
- data/lib/ronin/network/udp.rb +229 -1
- data/lib/ronin/support.rb +2 -3
- data/lib/ronin/support/support.rb +38 -0
- data/lib/ronin/support/version.rb +1 -1
- data/lib/ronin/templates/erb.rb +2 -1
- data/lib/ronin/ui/output/helpers.rb +35 -1
- data/lib/ronin/ui/shell.rb +12 -2
- data/lib/ronin/wordlist.rb +157 -0
- data/spec/extensions/regexp_spec.rb +38 -0
- data/spec/formatting/html/string_spec.rb +1 -1
- data/spec/formatting/sql/string_spec.rb +23 -3
- data/spec/formatting/text/string_spec.rb +0 -110
- data/spec/fuzzing/string_spec.rb +158 -0
- data/spec/wordlist_spec.rb +65 -0
- metadata +35 -27
data/lib/ronin/templates/erb.rb
CHANGED
@@ -29,6 +29,7 @@ module Ronin
|
|
29
29
|
#
|
30
30
|
module Erb
|
31
31
|
include Template
|
32
|
+
|
32
33
|
#
|
33
34
|
# Renders the inline ERB template in the scope of the object.
|
34
35
|
#
|
@@ -50,7 +51,7 @@ module Ronin
|
|
50
51
|
# @api public
|
51
52
|
#
|
52
53
|
def erb(template)
|
53
|
-
ERB.new(template).result(binding)
|
54
|
+
ERB.new(template,nil,'-').result(binding)
|
54
55
|
end
|
55
56
|
|
56
57
|
#
|
@@ -184,7 +184,7 @@ module Ronin
|
|
184
184
|
# @api public
|
185
185
|
#
|
186
186
|
def print_warning(*message)
|
187
|
-
|
187
|
+
unless Output.silent?
|
188
188
|
Output.handler.print_warning(format_message(message))
|
189
189
|
return true
|
190
190
|
end
|
@@ -220,6 +220,40 @@ module Ronin
|
|
220
220
|
return false
|
221
221
|
end
|
222
222
|
|
223
|
+
#
|
224
|
+
# Prints an exception.
|
225
|
+
#
|
226
|
+
# @param [Exception] exception
|
227
|
+
# The exception to print.
|
228
|
+
#
|
229
|
+
# @return [Boolean]
|
230
|
+
# Specifies whether the exception was printed or not.
|
231
|
+
#
|
232
|
+
# @example
|
233
|
+
# begin
|
234
|
+
# socket.write(buffer)
|
235
|
+
# rescue => e
|
236
|
+
# print_exception(e)
|
237
|
+
# end
|
238
|
+
#
|
239
|
+
# @since 0.4.0
|
240
|
+
#
|
241
|
+
# @api public
|
242
|
+
#
|
243
|
+
def print_exception(exception)
|
244
|
+
return false if Output.silent?
|
245
|
+
|
246
|
+
print_error "#{exception.class}: #{exception.message}"
|
247
|
+
|
248
|
+
if Output.verbose?
|
249
|
+
exception.backtrace[0,5].each do |line|
|
250
|
+
print_error " #{line}"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
return true
|
255
|
+
end
|
256
|
+
|
223
257
|
protected
|
224
258
|
|
225
259
|
#
|
data/lib/ronin/ui/shell.rb
CHANGED
@@ -74,7 +74,15 @@ module Ronin
|
|
74
74
|
@prompt = options.fetch(:prompt,DEFAULT_PROMPT)
|
75
75
|
|
76
76
|
@commands = Set[:help, :exit]
|
77
|
-
|
77
|
+
|
78
|
+
self.class.ancestors.each do |subclass|
|
79
|
+
if subclass < Shell
|
80
|
+
subclass.protected_instance_methods(false).each do |name|
|
81
|
+
@commands << name.to_sym
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
78
86
|
|
79
87
|
@input_handler = block
|
80
88
|
end
|
@@ -126,7 +134,7 @@ module Ronin
|
|
126
134
|
history_rollback += 1
|
127
135
|
|
128
136
|
begin
|
129
|
-
|
137
|
+
call(line)
|
130
138
|
rescue => e
|
131
139
|
print_error "#{e.class.name}: #{e.message}"
|
132
140
|
end
|
@@ -169,6 +177,8 @@ module Ronin
|
|
169
177
|
end
|
170
178
|
end
|
171
179
|
|
180
|
+
alias << write
|
181
|
+
|
172
182
|
protected
|
173
183
|
|
174
184
|
#
|
@@ -0,0 +1,157 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
|
3
|
+
#
|
4
|
+
# This file is part of Ronin Support.
|
5
|
+
#
|
6
|
+
# Ronin Support is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Lesser General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# Ronin Support is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public License
|
17
|
+
# along with Ronin Support. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'ronin/fuzzing/extensions'
|
21
|
+
|
22
|
+
module Ronin
|
23
|
+
#
|
24
|
+
# An Enumerable class for iterating over wordlist files or lists of words.
|
25
|
+
#
|
26
|
+
# @since 0.4.0
|
27
|
+
#
|
28
|
+
class Wordlist
|
29
|
+
|
30
|
+
include Enumerable
|
31
|
+
|
32
|
+
# The path to the wordlist file or a list of words
|
33
|
+
attr_accessor :list
|
34
|
+
|
35
|
+
# Mutation rules to apply to every word in the list
|
36
|
+
attr_reader :mutations
|
37
|
+
|
38
|
+
#
|
39
|
+
# Initializes the wordlist.
|
40
|
+
#
|
41
|
+
# @param [String, Enumerable] list
|
42
|
+
# The path of the wordlist or list of words.
|
43
|
+
#
|
44
|
+
# @param [Hash{Regexp,String,Symbol => Symbol,#each}] mutations
|
45
|
+
# Additional mutation rules to perform on each word in the list.
|
46
|
+
#
|
47
|
+
# @yield [wordlist]
|
48
|
+
# The given block will be passed the new wordlist.
|
49
|
+
#
|
50
|
+
# @yieldparam [Wordlist] wordlist
|
51
|
+
# The new wordlist object.
|
52
|
+
#
|
53
|
+
# @example Use a file wordlist
|
54
|
+
# wordlist = Wordlist.new('passwords.txt')
|
55
|
+
#
|
56
|
+
# @example Use a range of Strings
|
57
|
+
# wordlist = Wordlist.new('aaaa'..'zzzz')
|
58
|
+
#
|
59
|
+
# @example Specify mutation rules
|
60
|
+
# wordlist = Wordlist.new('passwords.txt', /e/ => ['E', '3'])
|
61
|
+
#
|
62
|
+
# @see String#mutate
|
63
|
+
#
|
64
|
+
# @api public
|
65
|
+
#
|
66
|
+
def initialize(list,mutations={})
|
67
|
+
@list = list
|
68
|
+
@mutations = {}
|
69
|
+
@mutations.merge!(mutations)
|
70
|
+
|
71
|
+
yield self if block_given?
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Iterates over each word in the list.
|
76
|
+
#
|
77
|
+
# @yield [word]
|
78
|
+
# The given block will be passed each word.
|
79
|
+
#
|
80
|
+
# @yieldparam [String] word
|
81
|
+
# A word from the list.
|
82
|
+
#
|
83
|
+
# @return [Enumerator]
|
84
|
+
# If no block is given, an Enumerator will be returned.
|
85
|
+
#
|
86
|
+
# @raise [TypeError]
|
87
|
+
# The list was not a path to a wordlist file, nor a list of words.
|
88
|
+
#
|
89
|
+
# @api public
|
90
|
+
#
|
91
|
+
def each_word(&block)
|
92
|
+
return enum_for(:each_word) unless block
|
93
|
+
|
94
|
+
case @list
|
95
|
+
when String
|
96
|
+
File.open(@list) do |file|
|
97
|
+
file.each_line do |line|
|
98
|
+
yield line.chomp
|
99
|
+
end
|
100
|
+
end
|
101
|
+
when Enumerable
|
102
|
+
@list.each(&block)
|
103
|
+
else
|
104
|
+
raise(TypeError,"list must be a path or Enumerable")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Iterates over each word, and each mutation, from the list.
|
110
|
+
#
|
111
|
+
# @yield [word]
|
112
|
+
# The given block will be passed each word.
|
113
|
+
#
|
114
|
+
# @yieldparam [String] word
|
115
|
+
# A word from the list.
|
116
|
+
#
|
117
|
+
# @return [Enumerator]
|
118
|
+
# If no block is given, an Enumerator will be returned.
|
119
|
+
#
|
120
|
+
# @api public
|
121
|
+
#
|
122
|
+
def each(&block)
|
123
|
+
return enum_for(:each) unless block
|
124
|
+
|
125
|
+
each_word do |word|
|
126
|
+
yield word
|
127
|
+
|
128
|
+
unless @mutations.empty?
|
129
|
+
# perform additional mutations
|
130
|
+
word.mutate(@mutations,&block)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Iterates over every n words.
|
137
|
+
#
|
138
|
+
# @param [Integer, Range, Array] n
|
139
|
+
# The number of words to combine.
|
140
|
+
#
|
141
|
+
# @yield [words]
|
142
|
+
# The given block will be passed every combination of `n` words.
|
143
|
+
#
|
144
|
+
# @yieldparam [String]
|
145
|
+
# The combination of `n` words.
|
146
|
+
#
|
147
|
+
# @return [Enumerator]
|
148
|
+
# If no block is given, an Enumerator will be returned.
|
149
|
+
#
|
150
|
+
# @api public
|
151
|
+
#
|
152
|
+
def each_n_words(n,&block)
|
153
|
+
String.generate([each, n],&block)
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ronin/extensions/regexp'
|
3
|
+
|
4
|
+
describe Regexp do
|
5
|
+
describe Regexp::IPv4 do
|
6
|
+
subject { Regexp::IPv4 }
|
7
|
+
|
8
|
+
it "should match valid addresses" do
|
9
|
+
ip = '127.0.0.1'
|
10
|
+
|
11
|
+
subject.match(ip)[0].should == ip
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should match the Any address" do
|
15
|
+
ip = '0.0.0.0'
|
16
|
+
|
17
|
+
subject.match(ip)[0].should == ip
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should match the broadcast address" do
|
21
|
+
ip = '255.255.255.255'
|
22
|
+
|
23
|
+
subject.match(ip)[0].should == ip
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should not match addresses with octets > 255" do
|
27
|
+
ip = '10.1.256.1'
|
28
|
+
|
29
|
+
subject.match(ip).should be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not match addresses with more than three digits per octet" do
|
33
|
+
ip = '10.1111.1.1'
|
34
|
+
|
35
|
+
subject.match(ip).should be_nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -74,7 +74,7 @@ describe String do
|
|
74
74
|
"%u006F%u006E%u0065%u0020%u0026%u0020%u0074%u0077%u006F"
|
75
75
|
end
|
76
76
|
let(:js_hex) { "%6F%6E%65%20%26%20%74%77%6F" }
|
77
|
-
let(:js_mixed) { "
|
77
|
+
let(:js_mixed) { "%u6F%u6E%u65 %26 two" }
|
78
78
|
|
79
79
|
it "should unescape JavaScript unicode characters" do
|
80
80
|
js_unicode.js_unescape.should == subject
|
@@ -20,7 +20,7 @@ describe String do
|
|
20
20
|
@string.should respond_to(:sql_decode)
|
21
21
|
end
|
22
22
|
|
23
|
-
describe "
|
23
|
+
describe "#sql_escape" do
|
24
24
|
it "should be able to single-quote escape" do
|
25
25
|
@string_with_quotes.sql_escape(:single).should == %{'"O''Brian"'}
|
26
26
|
end
|
@@ -30,7 +30,7 @@ describe String do
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
describe "
|
33
|
+
describe "#sql_encode" do
|
34
34
|
it "should be able to be SQL-hex encoded" do
|
35
35
|
@string.sql_encode.should == @sql_encoded
|
36
36
|
end
|
@@ -40,7 +40,7 @@ describe String do
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
describe "
|
43
|
+
describe "#sql_decode" do
|
44
44
|
it "should be able to be SQL-hex decoded" do
|
45
45
|
encoded = @string.sql_encode
|
46
46
|
|
@@ -52,4 +52,24 @@ describe String do
|
|
52
52
|
"'Conan O''Brian'".sql_decode.should == "Conan O'Brian"
|
53
53
|
end
|
54
54
|
end
|
55
|
+
|
56
|
+
describe "#sql_inject" do
|
57
|
+
context "when there is a leading quote character" do
|
58
|
+
it "should remove the first and last quote character" do
|
59
|
+
"'1' OR '1'='1'".sql_inject.should == "1' OR '1'='1"
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when there is no matching leading/trailing quote characters" do
|
63
|
+
it "should comment-terminate the String" do
|
64
|
+
"'1' OR 1=1".sql_inject.should == "1' OR 1=1--"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when there is no leading quote character" do
|
70
|
+
it "should not modify the String" do
|
71
|
+
"1 OR 1=1".sql_inject.should == "1 OR 1=1"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
55
75
|
end
|
@@ -4,10 +4,6 @@ require 'ronin/formatting/text'
|
|
4
4
|
describe String do
|
5
5
|
subject { "hello" }
|
6
6
|
|
7
|
-
it "should provide String.generate" do
|
8
|
-
described_class.should respond_to(:generate)
|
9
|
-
end
|
10
|
-
|
11
7
|
it "should provide String#format_chars" do
|
12
8
|
should respond_to(:format_chars)
|
13
9
|
end
|
@@ -28,112 +24,6 @@ describe String do
|
|
28
24
|
should respond_to(:insert_after)
|
29
25
|
end
|
30
26
|
|
31
|
-
describe "generate" do
|
32
|
-
subject { described_class }
|
33
|
-
|
34
|
-
it "should generate Strings from CharSets" do
|
35
|
-
strings = subject.generate(:lowercase_hexadecimal, :numeric).to_a
|
36
|
-
|
37
|
-
strings.grep(/^[0-9a-f][0-9]$/).should == strings
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should generate Strings from lengths of CharSets" do
|
41
|
-
strings = subject.generate([:numeric, 2]).to_a
|
42
|
-
|
43
|
-
strings.grep(/^[0-9]{2}$/).should == strings
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should generate Strings from varying lengths of CharSets" do
|
47
|
-
strings = subject.generate([:numeric, 1..2]).to_a
|
48
|
-
|
49
|
-
strings.grep(/^[0-9]{1,2}$/).should == strings
|
50
|
-
end
|
51
|
-
|
52
|
-
it "should generate Strings from custom CharSets" do
|
53
|
-
strings = subject.generate([%w[a b c], 2]).to_a
|
54
|
-
|
55
|
-
strings.grep(/^[abc]{2}$/).should == strings
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should generate Strings containing known Strings" do
|
59
|
-
strings = subject.generate('foo', [%w[a b c], 2]).to_a
|
60
|
-
|
61
|
-
strings.grep(/^foo[abc]{2}$/).should == strings
|
62
|
-
end
|
63
|
-
|
64
|
-
it "should raise a TypeError for non String, Symbol, Enumerable CharSets" do
|
65
|
-
lambda {
|
66
|
-
subject.generate([Object.new, 2]).to_a
|
67
|
-
}.should raise_error(TypeError)
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should raise an ArgumentError for unknown CharSets" do
|
71
|
-
lambda {
|
72
|
-
subject.generate([:foo_bar, 2]).to_a
|
73
|
-
}.should raise_error(ArgumentError)
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should raise a TypeError for non Integer,Array,Range lengths" do
|
77
|
-
lambda {
|
78
|
-
subject.generate([:numeric, 'foo']).to_a
|
79
|
-
}.should raise_error(TypeError)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
describe "#fuzz" do
|
84
|
-
subject { 'GET /one/two/three' }
|
85
|
-
|
86
|
-
it "should match Regexps" do
|
87
|
-
fuzzed = subject.fuzz(/GET/ => ['get']).to_a
|
88
|
-
|
89
|
-
fuzzed.should == ['get /one/two/three']
|
90
|
-
end
|
91
|
-
|
92
|
-
it "should match Strings" do
|
93
|
-
fuzzed = subject.fuzz('GET' => ['get']).to_a
|
94
|
-
|
95
|
-
fuzzed.should == ['get /one/two/three']
|
96
|
-
end
|
97
|
-
|
98
|
-
it "should match Integers" do
|
99
|
-
fuzzed = subject.fuzz(0x20 => ["\t"]).to_a
|
100
|
-
|
101
|
-
fuzzed.should == ["GET\t/one/two/three"]
|
102
|
-
end
|
103
|
-
|
104
|
-
it "should substitute using Procs" do
|
105
|
-
fuzzed = subject.fuzz('GET' => [lambda { |s| s.downcase }]).to_a
|
106
|
-
|
107
|
-
fuzzed.should == ['get /one/two/three']
|
108
|
-
end
|
109
|
-
|
110
|
-
it "should substitute using Integers" do
|
111
|
-
fuzzed = subject.fuzz(' ' => [0x09]).to_a
|
112
|
-
|
113
|
-
fuzzed.should == ["GET\t/one/two/three"]
|
114
|
-
end
|
115
|
-
|
116
|
-
it "should incrementally replace each occurrence" do
|
117
|
-
fuzzed = subject.fuzz('/' => ["\n\r"]).to_a
|
118
|
-
|
119
|
-
fuzzed.should == [
|
120
|
-
"GET \n\rone/two/three",
|
121
|
-
"GET /one\n\rtwo/three",
|
122
|
-
"GET /one/two\n\rthree"
|
123
|
-
]
|
124
|
-
end
|
125
|
-
|
126
|
-
it "should replace each occurrence with each substitution" do
|
127
|
-
fuzzed = subject.fuzz('GET' => ["\n\rGET", "G\n\rET", "GET\n\r"]).to_a
|
128
|
-
|
129
|
-
fuzzed.should == [
|
130
|
-
"\n\rGET /one/two/three",
|
131
|
-
"G\n\rET /one/two/three",
|
132
|
-
"GET\n\r /one/two/three"
|
133
|
-
]
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
27
|
describe "#format_bytes" do
|
138
28
|
it "should format each byte in the String" do
|
139
29
|
subject.format_bytes { |b|
|