ronin-exploits 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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