ronin-exploits 0.1.1 → 0.2.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.
Files changed (89) hide show
  1. data/History.txt +80 -2
  2. data/Manifest.txt +63 -16
  3. data/README.txt +89 -2
  4. data/Rakefile +1 -1
  5. data/TODO.txt +1 -1
  6. data/bin/ronin-exploits +12 -0
  7. data/bin/ronin-payload +12 -0
  8. data/bin/ronin-payloads +12 -0
  9. data/lib/ronin/exploits.rb +13 -10
  10. data/lib/ronin/exploits/{impact.rb → allow.rb} +9 -4
  11. data/lib/ronin/exploits/exceptions.rb +3 -0
  12. data/lib/ronin/exploits/exceptions/target_data_missing.rb +29 -0
  13. data/lib/ronin/exploits/exceptions/target_unspecified.rb +29 -0
  14. data/lib/ronin/exploits/exceptions/unknown_helper.rb +29 -0
  15. data/lib/ronin/exploits/exploit.rb +330 -77
  16. data/lib/ronin/exploits/{format_string_target.rb → ftp.rb} +5 -11
  17. data/lib/ronin/exploits/helpers.rb +27 -0
  18. data/lib/ronin/exploits/helpers/binary.rb +44 -0
  19. data/lib/ronin/exploits/helpers/buffer_overflow.rb +102 -0
  20. data/lib/ronin/exploits/helpers/format_string.rb +107 -0
  21. data/lib/ronin/exploits/helpers/padding.rb +84 -0
  22. data/lib/ronin/exploits/http.rb +37 -0
  23. data/lib/ronin/exploits/{requirement.rb → local.rb} +2 -14
  24. data/lib/ronin/exploits/remote.rb +34 -0
  25. data/lib/ronin/exploits/remote_tcp.rb +70 -0
  26. data/lib/ronin/exploits/remote_udp.rb +70 -0
  27. data/lib/ronin/exploits/target.rb +134 -0
  28. data/lib/ronin/exploits/targets.rb +29 -0
  29. data/lib/ronin/exploits/{buffer_overflow_target.rb → targets/buffer_overflow.rb} +13 -11
  30. data/lib/ronin/exploits/{exploit_target.rb → targets/format_string.rb} +11 -14
  31. data/lib/ronin/exploits/version.rb +1 -1
  32. data/lib/ronin/exploits/{web_exploit.rb → web.rb} +3 -3
  33. data/lib/ronin/model/targets_arch.rb +59 -0
  34. data/lib/ronin/model/targets_os.rb +59 -0
  35. data/lib/ronin/payloads.rb +7 -3
  36. data/lib/ronin/payloads/binary_payload.rb +3 -7
  37. data/lib/ronin/payloads/{ability.rb → control.rb} +7 -2
  38. data/lib/ronin/payloads/encoder.rb +78 -0
  39. data/lib/ronin/payloads/encoders.rb +33 -0
  40. data/lib/ronin/payloads/encoders/xor.rb +81 -0
  41. data/lib/ronin/payloads/exceptions.rb +24 -0
  42. data/lib/ronin/payloads/exceptions/unknown_helper.rb +29 -0
  43. data/lib/ronin/payloads/helpers.rb +26 -0
  44. data/lib/ronin/payloads/helpers/exceptions.rb +24 -0
  45. data/lib/ronin/payloads/helpers/exceptions/program_not_found.rb +31 -0
  46. data/lib/ronin/payloads/helpers/exceptions/unimplemented.rb +31 -0
  47. data/lib/ronin/payloads/helpers/file_system.rb +187 -0
  48. data/lib/ronin/payloads/helpers/rpc.rb +83 -0
  49. data/lib/ronin/payloads/helpers/shell.rb +91 -0
  50. data/lib/ronin/payloads/nops.rb +32 -0
  51. data/lib/ronin/payloads/payload.rb +90 -53
  52. data/lib/ronin/payloads/shellcode.rb +1 -1
  53. data/lib/ronin/payloads/web_payload.rb +2 -1
  54. data/lib/ronin/targeted_arch.rb +38 -0
  55. data/lib/ronin/targeted_os.rb +38 -0
  56. data/lib/ronin/targeted_product.rb +34 -0
  57. data/lib/ronin/ui/command_line/commands/exploits.rb +77 -0
  58. data/lib/ronin/ui/command_line/commands/payload.rb +106 -0
  59. data/lib/ronin/ui/command_line/commands/payloads.rb +73 -0
  60. data/spec/exploits/binary_exploit_spec.rb +44 -0
  61. data/spec/exploits/buffer_overflow_exploit_spec.rb +70 -0
  62. data/spec/exploits/exploit_spec.rb +122 -25
  63. data/spec/exploits/format_string_exploit_spec.rb +32 -0
  64. data/spec/exploits/ftp_spec.rb +17 -0
  65. data/spec/exploits/http_spec.rb +17 -0
  66. data/spec/exploits/padding_exploit_spec.rb +44 -0
  67. data/spec/exploits/remote_tcp_spec.rb +24 -0
  68. data/spec/exploits/remote_udp_spec.rb +24 -0
  69. data/spec/exploits/target_spec.rb +91 -0
  70. data/spec/exploits/targets/buffer_overflow_spec.rb +18 -0
  71. data/spec/exploits/{web_exploit_spec.rb → web_spec.rb} +5 -5
  72. data/spec/helpers/database.rb +5 -0
  73. data/spec/helpers/objects.rb +22 -0
  74. data/spec/objects/exploits/test.rb +28 -0
  75. data/spec/objects/payloads/example.rb +19 -0
  76. data/spec/objects/payloads/test.rb +11 -0
  77. data/spec/payloads/encoder_spec.rb +26 -0
  78. data/spec/payloads/encoders/xor_spec.rb +20 -0
  79. data/spec/payloads/payload_spec.rb +48 -13
  80. data/spec/spec_helper.rb +3 -5
  81. metadata +71 -22
  82. data/lib/ronin/exploits/binary_exploit.rb +0 -139
  83. data/lib/ronin/exploits/buffer_overflow.rb +0 -80
  84. data/lib/ronin/exploits/exploitable.rb +0 -77
  85. data/lib/ronin/exploits/format_string.rb +0 -88
  86. data/lib/ronin/models.rb +0 -38
  87. data/lib/ronin/translators/xor.rb +0 -96
  88. data/spec/exploits/exploitable_spec.rb +0 -21
  89. data/spec/translators/xor_spec.rb +0 -26
@@ -0,0 +1,29 @@
1
+ #
2
+ #--
3
+ # Ronin Exploits - A Ruby library for Ronin that provides exploitation and
4
+ # payload crafting functionality.
5
+ #
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program 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 General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ #++
22
+ #
23
+
24
+ module Ronin
25
+ module Exploits
26
+ class TargetUnspecified < RuntimeError
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ #
2
+ #--
3
+ # Ronin Exploits - A Ruby library for Ronin that provides exploitation and
4
+ # payload crafting functionality.
5
+ #
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program 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 General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ #++
22
+ #
23
+
24
+ module Ronin
25
+ module Exploits
26
+ class UnknownHelper < RuntimeError
27
+ end
28
+ end
29
+ end
@@ -21,21 +21,31 @@
21
21
  #++
22
22
  #
23
23
 
24
- require 'ronin/exploits/requirement'
25
- require 'ronin/exploits/impact'
24
+ require 'ronin/exploits/exceptions/unknown_helper'
25
+ require 'ronin/exploits/exceptions/target_unspecified'
26
+ require 'ronin/exploits/exceptions/target_data_missing'
27
+ require 'ronin/exploits/exceptions/restricted_char'
28
+ require 'ronin/exploits/exceptions/exploit_not_built'
26
29
  require 'ronin/exploits/exploit_author'
30
+ require 'ronin/exploits/target'
31
+ require 'ronin/exploits/allow'
32
+ require 'ronin/payloads/payload'
27
33
  require 'ronin/vuln/behavior'
28
- require 'ronin/objectify'
34
+ require 'ronin/cacheable'
29
35
  require 'ronin/has_license'
30
36
 
37
+ require 'parameters'
38
+ require 'chars/char_set'
39
+
31
40
  module Ronin
32
41
  module Exploits
33
42
  class Exploit
34
43
 
35
- include Objectify
44
+ include Parameters
45
+ include Cacheable
36
46
  include HasLicense
37
47
 
38
- objectify :ronin_exploit
48
+ contextify :ronin_exploit
39
49
 
40
50
  # Primary key of the exploit
41
51
  property :id, Serial
@@ -49,30 +59,63 @@ module Ronin
49
59
  # Description of the exploit
50
60
  property :description, Text
51
61
 
62
+ # The status of the exploit (either, :potential, :proven or
63
+ # :weaponized)
64
+ property :status, Enum[
65
+ :potential,
66
+ :proven,
67
+ :weaponized
68
+ ], :default => :potential
69
+
70
+ # The disclosure status of the exploit (any of, :private,
71
+ # :vendor_aware, :in_wild and :public)
72
+ property :disclosure, Flag[
73
+ :private,
74
+ :in_wild,
75
+ :vendor_aware,
76
+ :public
77
+ ]
78
+
52
79
  # Author(s) of the exploit
53
- has n, :authors, :class_name => 'ExploitAuthor'
80
+ has n, :authors, :class_name => 'Ronin::Exploits::ExploitAuthor'
54
81
 
55
- # The requirements of the exploit
56
- has n, :requirements
82
+ # Behaviors that the exploit allows
83
+ has n, :allows
57
84
 
58
- # Impact of the exploit
59
- has n, :impact, :class_name => 'Impact'
85
+ # Targets for the exploit
86
+ has n, :targets
60
87
 
61
88
  # Validations
62
89
  validates_present :name
63
90
  validates_is_unique :version, :scope => [:name]
64
91
 
92
+ # Exploit target
93
+ attr_accessor :target
94
+
65
95
  # Exploit payload
66
96
  attr_accessor :payload
67
97
 
98
+ # Characters to restrict
99
+ attr_reader :restricted_chars
100
+
101
+ # Encoders to run on the payload
102
+ attr_reader :encoders
103
+
104
+ # The encoded payload
105
+ attr_reader :encoded_payload
106
+
68
107
  #
69
108
  # Creates a new Exploit object with the given _attributes_.
70
109
  #
71
110
  def initialize(attributes={},&block)
72
111
  super(attributes)
73
112
 
113
+ @target = nil
74
114
  @built = false
75
115
 
116
+ @restricted_chars = Chars::CharSet.new
117
+ @encoders = []
118
+
76
119
  instance_eval(&block) if block
77
120
  end
78
121
 
@@ -103,35 +146,117 @@ module Ronin
103
146
  # If a _block_ is given, it will be passed to the newly created
104
147
  # ExploitAuthor object.
105
148
  #
149
+ # author :name => 'Anonymous',
150
+ # :email => 'anon@example.com',
151
+ # :organization => 'Anonymous LLC'
152
+ #
106
153
  def author(attributes={},&block)
107
- self.authors << ExploitAuthor.new(
108
- attributes.merge(:exploit => self),
109
- &block
110
- )
154
+ self.authors << ExploitAuthor.new(attributes,&block)
111
155
  end
112
156
 
113
157
  #
114
- # Adds a new Requirement for the specified _behavior_.
158
+ # Adds a new Allow object granting the specified _behavior_.
115
159
  #
116
- def requires(behavior)
117
- self.requirements << Requirement.new(
118
- :behavior => behavior,
119
- :exploit => self
120
- )
160
+ # allowing :code_exec
161
+ #
162
+ def allowing(behavior)
163
+ self.allows << Allow.new(:behavior => Vuln::Behavior[behavior])
164
+ end
121
165
 
122
- return self
166
+ #
167
+ # Adds a new Target with the given _attributes_ and _block_.
168
+ #
169
+ # targeting do |target|
170
+ # target.arch :i686
171
+ # target.os :name => 'Linux'
172
+ # end
173
+ #
174
+ def targeting(attributes={},&block)
175
+ self.targets << Target.new(attributes,&block)
123
176
  end
124
177
 
125
178
  #
126
- # Adds a new Impact granting the specified _behavior_.
179
+ # Adds the given _chars_ to the restricted list of characters.
180
+ #
181
+ # restrict 0x00, "\n"
182
+ # # => #<Chars::CharSet: {"\0", "\n"}>
127
183
  #
128
- def allows(behavior)
129
- self.impact << Impact.new(
130
- :behavior => behavior,
131
- :exploit => self
132
- )
184
+ def restrict(*chars)
185
+ @restricted_chars += chars
186
+ end
133
187
 
134
- return self
188
+ #
189
+ # Adds the specified _encoder_ to the list of encoders to use on the
190
+ # payload.
191
+ #
192
+ def encode_with(encoder)
193
+ @encoders << encoder
194
+ end
195
+
196
+ #
197
+ # Returns the Array of targeted architectures.
198
+ #
199
+ def targeted_archs
200
+ self.targets.map { |target| target.arch }.compact
201
+ end
202
+
203
+ #
204
+ # Returns the Array of targeted OSes.
205
+ #
206
+ def targeted_oses
207
+ self.targets.map { |target| target.os }.compact
208
+ end
209
+
210
+ #
211
+ # Returns the Array of targeted Products.
212
+ #
213
+ def targeted_products
214
+ self.targets.map { |target| target.product }.compact
215
+ end
216
+
217
+ #
218
+ # Explicitly selects the first target that matches the specified
219
+ # _block_.
220
+ #
221
+ # select_target { |target| target.arch == Arch.i686 }
222
+ #
223
+ def select_target(&block)
224
+ @target = self.targets.first(&block)
225
+ end
226
+
227
+ #
228
+ # Returns the current target.
229
+ #
230
+ def target
231
+ @target ||= self.targets.first
232
+ end
233
+
234
+ #
235
+ # Returns the currently targeted architecture.
236
+ #
237
+ def arch
238
+ target.arch if target
239
+ end
240
+
241
+ #
242
+ # Returns the currently targeted OS.
243
+ #
244
+ def os
245
+ target.os if target
246
+ end
247
+
248
+ #
249
+ # Returns the currently targeted Product.
250
+ #
251
+ def product
252
+ target.product if target
253
+ end
254
+
255
+ #
256
+ # Returns the behaviors allowed by the exploit.
257
+ #
258
+ def behaviors
259
+ self.allows.map { |allow| allow.behavior }
135
260
  end
136
261
 
137
262
  #
@@ -150,21 +275,31 @@ module Ronin
150
275
  end
151
276
 
152
277
  #
153
- # Default vulnerability test method. Returning +true+ symbolizes
154
- # that the target of the exploit is vulnerable. Returning +nil+
155
- # symbolizes that the exploit cannot determine if the target is
156
- # vulnerable or not. Returning +false+ symbolizes that the target
157
- # of the exploit is definitely not vulnerable. Returns +nil+ by
158
- # default.
278
+ # Builds and encodes the current payload, returning the encoded
279
+ # payload in String form.
159
280
  #
160
- def vulnerable?
161
- nil
162
- end
281
+ def encode_payload!
282
+ @encoded_payload = ''
163
283
 
164
- #
165
- # Default builder method.
166
- #
167
- def builder
284
+ if @payload
285
+ if @payload.class.include?(Parameters)
286
+ @payload.params = self.params
287
+ end
288
+
289
+ if @payload.kind_of?(Payloads::Payload)
290
+ @encoded_payload = @payload.build!
291
+ else
292
+ @encoded_payload = @payload.to_s
293
+ end
294
+
295
+ @encoders.each do |encoder|
296
+ if (new_payload = encoder.call(@encoded_payload))
297
+ @encoded_payload = new_payload
298
+ end
299
+ end
300
+ end
301
+
302
+ return @encoded_payload
168
303
  end
169
304
 
170
305
  #
@@ -180,87 +315,205 @@ module Ronin
180
315
  # patterns are found in the built exploit, a RestrictedText exception
181
316
  # will be raised.
182
317
  #
183
- def build(options={})
184
- self.params = options
185
-
186
- @payload = (options[:payload] || @payload)
187
-
188
- if (@payload && @payload.include?(Parameters))
189
- @payload.params = options
318
+ def build!(options={})
319
+ if options[:payload]
320
+ @payload ||= options.delete(:payload)
190
321
  end
191
322
 
323
+ self.params = options
324
+
192
325
  @built = false
193
326
 
194
- result = builder
327
+ encode_payload!
328
+ result = build
195
329
 
196
330
  @built = true
197
331
  return result
198
332
  end
199
333
 
200
- #
201
- # Default exploit verifier method.
202
- #
203
- def verifier
204
- end
205
-
206
334
  #
207
335
  # Verifies the exploit is properly configured, built and ready to be
208
336
  # deployed. An exception should be raised if the exploit is not ready
209
337
  # to be deployed, returns +true+ otherwise.
210
338
  #
211
- def verify
339
+ def verify!
212
340
  unless built?
213
341
  raise(ExploitNotBuilt,"cannot deploy an unbuilt exploit",caller)
214
342
  end
215
343
 
216
- verifier
344
+ verify
217
345
  return true
218
346
  end
219
347
 
220
- #
221
- # Default exploit deployer method, passes the exploit object to the
222
- # given _block_ by default.
223
- #
224
- def deployer(&block)
225
- block.call(self) if block
226
- end
227
-
228
348
  #
229
349
  # Deploys the exploit. If a _block_ is given and the payload used is
230
350
  # a kind of Payload, then the payloads deploy method will be passed
231
351
  # the given _block_. If the payload used is not a kind of Payload and
232
352
  # a _block_ is given, the _block_ will be passed to the exploits
233
- # deployer method. If the exploit has not been previously built, an
353
+ # deploy method. If the exploit has not been previously built, an
234
354
  # ExploitNotBuilt exception will be raised.
235
355
  #
236
- def deploy(&block)
237
- verify
356
+ def deploy!(&block)
357
+ verify!
238
358
 
239
- if (@payload && @payload.kind_of?(Payloads::Payload))
240
- deployer()
359
+ if @payload.kind_of?(Payloads::Payload)
360
+ deploy()
241
361
 
242
- return @payload.deploy(&block)
362
+ return @payload.deploy!(&block)
243
363
  else
244
- return deployer(&block)
364
+ return deploy(&block)
245
365
  end
246
366
  end
247
367
 
248
368
  #
249
- # Builds, deploys and then cleans the exploit with the given _options_.
369
+ # Builds the exploit with the given _options_, then deploys the
370
+ # exploit with the given _block_.
250
371
  #
251
- def exploit(options={},&block)
252
- build(options)
372
+ def exploit!(options={},&block)
373
+ build!(options)
253
374
 
254
- return deploy(&block)
375
+ return deploy!(&block)
255
376
  end
256
377
 
257
378
  #
258
- # Returns the built exploit.
379
+ # Returns the name and version of the exploit.
259
380
  #
260
381
  def to_s
261
382
  "#{self.name} #{self.version}"
262
383
  end
263
384
 
385
+ protected
386
+
387
+ #
388
+ # Extends the exploit with the helper module defined in
389
+ # Ronin::Exploits::Helpers that has the similar specified
390
+ # _name_. If no module can be found within
391
+ # Ronin::Exploits::Helpers with the similar _name_, an
392
+ # UnknownHelper exception will be raised.
393
+ #
394
+ # helper :buffer_overflow
395
+ #
396
+ def helper(name)
397
+ name = name.to_s
398
+ module_name = name.to_const_string
399
+
400
+ begin
401
+ require File.join('ronin','exploits','helpers',name)
402
+ rescue LoadError
403
+ raise(UnknownHelper,"unknown helper #{name.dump}",caller)
404
+ end
405
+
406
+ unless Ronin::Exploits::Helpers.const_defined?(module_name)
407
+ raise(UnknownHelper,"unknown helper #{name.dump}",caller)
408
+ end
409
+
410
+ helper_module = Ronin::Exploits::Helpers.const_get(module_name)
411
+
412
+ unless helper_module.kind_of?(Module)
413
+ raise(UnknownHelper,"unknown helper #{name.dump}",caller)
414
+ end
415
+
416
+ extend helper_module
417
+ return true
418
+ end
419
+
420
+ #
421
+ # Verifies that a target has been selected. If a target has not been
422
+ # selected, a TargetUnspecified exception will be raised, otherwise
423
+ # +true+ will be returned.
424
+ #
425
+ def verify_target!
426
+ if target.nil?
427
+ raise(TargetUnspecified,"no suitable target provided",caller)
428
+ end
429
+
430
+ return true
431
+ end
432
+
433
+ #
434
+ # Verifies that the selected target has an arch property.
435
+ # If the selected target does not have an arch property, a
436
+ # TargetDataMissing exception will be raised, otherwise
437
+ # +true+ will be return.
438
+ #
439
+ def verify_arch!
440
+ if arch.nil?
441
+ raise(TargetDataMissing,"no suitable arch was provided",caller)
442
+ end
443
+ end
444
+
445
+ #
446
+ # Verifies that the selected target has an os property.
447
+ # If the selected target does not have an os property, a
448
+ # TargetDataMissing exception will be raised, otherwise
449
+ # +true+ will be return.
450
+ #
451
+ def verify_os!
452
+ if os.nil?
453
+ raise(TargetDataMissing,"no suitable os was provided",caller)
454
+ end
455
+ end
456
+
457
+ #
458
+ # Verifies that the selected target has an product property.
459
+ # If the selected target does not have an product property, a
460
+ # TargetDataMissing exception will be raised, otherwise
461
+ # +true+ will be return.
462
+ #
463
+ def verify_product!
464
+ if product.nil?
465
+ raise(TargetDataMissing,"no suitable product was provided",caller)
466
+ end
467
+ end
468
+
469
+ #
470
+ # Returns +true+ if the specified _text_ contains any restricted
471
+ # characters, returns +false+ otherwise.
472
+ #
473
+ def is_restricted?(text)
474
+ text.each_byte do |b|
475
+ return true if @restricted_chars.include?(b)
476
+ end
477
+
478
+ return false
479
+ end
480
+
481
+ #
482
+ # Raises a RestrictedChar exception if the specified _text_ contains
483
+ # any restricted characters, returns +true+ otherwise.
484
+ #
485
+ def verify_restricted!(text)
486
+ found = @restricted_chars.select { |char|
487
+ text.include?(char)
488
+ }.map { |char| char.dump }
489
+
490
+ unless found.empty?
491
+ raise(RestrictedChar,"restricted characters #{found.join(', ')} was detected in #{text.dump}",caller)
492
+ end
493
+
494
+ return true
495
+ end
496
+
497
+ #
498
+ # Default build method.
499
+ #
500
+ def build
501
+ end
502
+
503
+ #
504
+ # Default exploit verify method.
505
+ #
506
+ def verify
507
+ end
508
+
509
+ #
510
+ # Default exploit deploy method, passes the exploit object to the
511
+ # given _block_ by default.
512
+ #
513
+ def deploy(&block)
514
+ block.call(self) if block
515
+ end
516
+
264
517
  end
265
518
  end
266
519
  end