ronin-exploits 1.0.0.beta2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -0
  3. data/README.md +29 -13
  4. data/gemspec.yml +10 -8
  5. data/lib/ronin/exploits/cli/commands/new.rb +1 -1
  6. data/lib/ronin/exploits/cli/commands/run.rb +55 -5
  7. data/lib/ronin/exploits/exploit.rb +7 -5
  8. data/lib/ronin/exploits/lfi.rb +1 -1
  9. data/lib/ronin/exploits/metadata/arch.rb +1 -1
  10. data/lib/ronin/exploits/metadata/default_filename.rb +1 -1
  11. data/lib/ronin/exploits/metadata/default_port.rb +1 -1
  12. data/lib/ronin/exploits/mixins/file_builder.rb +2 -2
  13. data/lib/ronin/exploits/mixins/nops.rb +1 -1
  14. data/lib/ronin/exploits/params/base_url.rb +1 -1
  15. data/lib/ronin/exploits/version.rb +1 -1
  16. data/ronin-exploits.gemspec +2 -1
  17. metadata +24 -129
  18. data/spec/advisory_spec.rb +0 -71
  19. data/spec/cli/exploit_command_spec.rb +0 -68
  20. data/spec/cli/exploit_methods_spec.rb +0 -208
  21. data/spec/cli/ruby_shell_spec.rb +0 -14
  22. data/spec/client_side_web_vuln_spec.rb +0 -117
  23. data/spec/exploit_spec.rb +0 -538
  24. data/spec/exploits_spec.rb +0 -8
  25. data/spec/heap_overflow_spec.rb +0 -14
  26. data/spec/lfi_spec.rb +0 -162
  27. data/spec/loot/file_spec.rb +0 -131
  28. data/spec/loot_spec.rb +0 -138
  29. data/spec/memory_corruption_spec.rb +0 -22
  30. data/spec/metadata/arch_spec.rb +0 -82
  31. data/spec/metadata/cookie_param_spec.rb +0 -67
  32. data/spec/metadata/default_filename_spec.rb +0 -62
  33. data/spec/metadata/default_port_spec.rb +0 -62
  34. data/spec/metadata/header_name_spec.rb +0 -67
  35. data/spec/metadata/os_spec.rb +0 -164
  36. data/spec/metadata/shouts_spec.rb +0 -100
  37. data/spec/metadata/url_path_spec.rb +0 -67
  38. data/spec/metadata/url_query_param_spec.rb +0 -67
  39. data/spec/mixins/binary_spec.rb +0 -129
  40. data/spec/mixins/build_dir.rb +0 -66
  41. data/spec/mixins/file_builder_spec.rb +0 -67
  42. data/spec/mixins/format_string_spec.rb +0 -44
  43. data/spec/mixins/has_payload_spec.rb +0 -333
  44. data/spec/mixins/has_targets_spec.rb +0 -434
  45. data/spec/mixins/html_spec.rb +0 -772
  46. data/spec/mixins/http_spec.rb +0 -1227
  47. data/spec/mixins/loot_spec.rb +0 -20
  48. data/spec/mixins/nops_spec.rb +0 -165
  49. data/spec/mixins/remote_tcp_spec.rb +0 -217
  50. data/spec/mixins/remote_udp_spec.rb +0 -217
  51. data/spec/mixins/seh_spec.rb +0 -89
  52. data/spec/mixins/stack_overflow_spec.rb +0 -87
  53. data/spec/mixins/text_spec.rb +0 -43
  54. data/spec/open_redirect_spec.rb +0 -71
  55. data/spec/params/base_url_spec.rb +0 -71
  56. data/spec/params/bind_host_spec.rb +0 -34
  57. data/spec/params/bind_port_spec.rb +0 -35
  58. data/spec/params/filename_spec.rb +0 -77
  59. data/spec/params/host_spec.rb +0 -34
  60. data/spec/params/port_spec.rb +0 -77
  61. data/spec/rfi_spec.rb +0 -107
  62. data/spec/seh_overflow_spec.rb +0 -18
  63. data/spec/spec_helper.rb +0 -8
  64. data/spec/sqli_spec.rb +0 -306
  65. data/spec/ssti_spec.rb +0 -121
  66. data/spec/stack_overflow_spec.rb +0 -18
  67. data/spec/target_spec.rb +0 -92
  68. data/spec/test_result_spec.rb +0 -32
  69. data/spec/use_after_free_spec.rb +0 -14
  70. data/spec/web_spec.rb +0 -12
  71. data/spec/web_vuln_spec.rb +0 -854
  72. data/spec/xss_spec.rb +0 -69
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b7d601e1580ea5719c365a686d579659df4deb60d77eff285d74ac1280d93b3
4
- data.tar.gz: 87e9cef6168d40862c0442aabdaaa69d51563cbae6ff93abb8a3c4c0ef0b6704
3
+ metadata.gz: f4fb437a6634a2eef3dae27f5d940718e94d1e5d7839113e9b02d849daeb2f81
4
+ data.tar.gz: 661bbae01973ba0ec2e367abef7fd137534dff1597b8486dde94e64afcc6e780
5
5
  SHA512:
6
- metadata.gz: 37e77fed488fdcfed0357d792738b3bb231cbeae749631291aa12544a8b225ca14fe548cf70985ae88d9946f5e1f8ead8c1d0078d486fa4d0ed837b33fca9aa6
7
- data.tar.gz: e032ca57e0b63ca63b93e79d6479c631a8939eaa5406d4d4d68bafebfd5b16ffdfc5e6f58f245440036ec0f2869937709c84cf915ce78e10efc4fb03c0bcc303
6
+ metadata.gz: 9c40d3ba6b13842ddb66b762cac6aaa26a22f3feb03a8f68abf1fdc7d90696fb4cc03da0fd4472ea77af9e861eb92cf4a7165a5fc023b4ecb4e59f0ef13fa234
7
+ data.tar.gz: 8b81f266e3b256f028a01b1d10a85d0d1d09cfbcdfecab07e5bf25ebae0f96adee5b7881515eb4cfaccae5ae0e4807377315f50db9213ab5268b179db3e87640
@@ -21,6 +21,7 @@ jobs:
21
21
  uses: ruby/setup-ruby@v1
22
22
  with:
23
23
  ruby-version: ${{ matrix.ruby }}
24
+ bundler-cache: true
24
25
  - name: Install libsqlite3
25
26
  run: |
26
27
  sudo apt update -y && \
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/ronin-rb/ronin-exploits/actions/workflows/ruby.yml/badge.svg)](https://github.com/ronin-rb/ronin-exploits/actions/workflows/ruby.yml)
4
4
  [![Code Climate](https://codeclimate.com/github/ronin-rb/ronin-exploits.svg)](https://codeclimate.com/github/ronin-rb/ronin-exploits)
5
+ [![Gem Version](https://badge.fury.io/rb/ronin-exploits.svg)](https://badge.fury.io/rb/ronin-exploits)
5
6
 
6
7
  * [Source](https://github.com/ronin-rb/ronin-exploits)
7
8
  * [Issues](https://github.com/ronin-rb/ronin-exploits/issues)
@@ -17,27 +18,30 @@ ronin-exploits allows one to write exploits as plain old Ruby classes.
17
18
  ronin-exploits can be distributed as Ruby files or as git repositories that can
18
19
  be installed using [ronin-repos].
19
20
 
21
+ **tl;dr** It's like a simpler and more modular version of
22
+ [Metasploit](https://www.metasploit.com/).
23
+
20
24
  ronin-exploits is part of the [ronin-rb] project, a [Ruby] toolkit for security
21
25
  research and development.
22
26
 
23
27
  ## Features
24
28
 
25
- * Provides a succinct syntax and API for writing exploits in as few lines as
26
- possible.
27
- * Supports defining exploits as plain old Ruby classes.
29
+ * Provides a succinct [syntax](#examples) and [API][docs-exploit] for writing
30
+ exploits in as few lines as possible.
31
+ * Supports [defining exploits as plain old Ruby classes][docs-exploit].
28
32
  * Supports loading exploits from Ruby files or from installed 3rd-party
29
33
  git repositories.
30
34
  * Provides base classes and mixin modules for a variety of exploit types:
31
- * Stack Overflows
32
- * SEH Overflows
33
- * Heap Overflows
34
- * Use After Free (UAF)
35
- * Open Redirect
36
- * Local File Inclusions (LFI)
37
- * Remote File Inclusions (RFI)
38
- * SQL injections (SQLi)
39
- * Cross-Site Scripting (XSS)
40
- * Server-Side Template Injection (SSTI)
35
+ * [Stack Overflows][docs-stack-overflow]
36
+ * [SEH Overflows][docs-seh-overflow]
37
+ * [Heap Overflows][docs-heap-overflow]
38
+ * [Use After Free (UAF)][docs-use-after-free]
39
+ * [Open Redirect][docs-open-redirect]
40
+ * [Local File Inclusions (LFI)][docs-lfi]
41
+ * [Remote File Inclusions (RFI)][docs-rfi]
42
+ * [SQL injections (SQLi)][docs-sqli]
43
+ * [Cross-Site Scripting (XSS)][docs-xss]
44
+ * [Server-Side Template Injection (SSTI)][docs-ssti]
41
45
  * Uses the [ronin-payloads] library for exploit payloads.
42
46
  * Uses the [ronin-post_ex] library for post-exploitation.
43
47
  * Provides a simple CLI for listing, displaying, running, and generating new
@@ -46,6 +50,18 @@ research and development.
46
50
  * Has 86% documentation coverage.
47
51
  * Small memory footprint (~47Kb).
48
52
 
53
+ [docs-exploit]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/Exploit.html
54
+ [docs-stack-overflow]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/StackOverflow.html
55
+ [docs-seh-overflow]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/SEHOverflow.html
56
+ [docs-heap-overflow]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/HeapOverflow.html
57
+ [docs-use-after-free]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/UseAfterFree.html
58
+ [docs-open-redirect]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/OpenRedirect.html
59
+ [docs-lfi]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/LFI.html
60
+ [docs-rfi]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/RFI.html
61
+ [docs-sqli]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/SQLI.html
62
+ [docs-xss]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/XSS.html
63
+ [docs-ssti]: https://ronin-rb.dev/docs/ronin-exploits/Ronin/Exploits/SSTI.html
64
+
49
65
  ## Anti-Features
50
66
 
51
67
  * No magic: exploits are defined as classes in files.
data/gemspec.yml CHANGED
@@ -1,11 +1,13 @@
1
1
  name: ronin-exploits
2
2
  summary: A Ruby micro-framework for writing and running exploits and payloads.
3
- description:
3
+ description: |
4
4
  ronin-exploits is a Ruby micro-framework for writing and running exploits.
5
5
  ronin-exploits allows one to write exploits as plain old Ruby classes.
6
6
  ronin-exploits can be distributed as Ruby files or as git repositories that
7
7
  can be installed using ronin-reps.
8
8
 
9
+ It's like a simpler version of Metasploit.
10
+
9
11
  license: LGPL-3.0
10
12
  authors: Postmodern
11
13
  email: postmodern.mod3@gmail.com
@@ -32,13 +34,13 @@ generated_files:
32
34
  dependencies:
33
35
  uri-query_params: ~> 0.6
34
36
  # Ronin dependencies:
35
- ronin-support: ~> 1.0.0.beta1
36
- ronin-code-sql: ~> 2.0.0.beta1
37
- ronin-payloads: ~> 0.1.0.beta1
38
- ronin-vulns: ~> 0.1.0.beta1
39
- ronin-post_ex: ~> 0.1.0.beta1
40
- ronin-core: ~> 0.1.0.beta1
41
- ronin-repos: ~> 0.1.0.beta1
37
+ ronin-support: ~> 1.0
38
+ ronin-code-sql: ~> 2.0
39
+ ronin-payloads: ~> 0.1
40
+ ronin-vulns: ~> 0.1
41
+ ronin-post_ex: ~> 0.1
42
+ ronin-core: ~> 0.1
43
+ ronin-repos: ~> 0.1
42
44
 
43
45
  development_dependencies:
44
46
  bundler: ~> 2.0
@@ -252,7 +252,7 @@ module Ronin
252
252
  man_page 'ronin-exploits-new.1'
253
253
 
254
254
  #
255
- # Initialies the `ronin-exploits new` command.
255
+ # Initializes the `ronin-exploits new` command.
256
256
  #
257
257
  # @param [Hash{Symbol => Object}] kwargs
258
258
  # Additional keyword arguments.
@@ -118,7 +118,11 @@ module Ronin
118
118
  type: /\A[^=\s]+=.+\z/,
119
119
  usage: 'NAME=VALUE'
120
120
  },
121
- desc: 'Sets a param on the payload'
121
+ desc: 'Sets a param on the payload' do |param|
122
+ name, value = param.split('=',2)
123
+
124
+ @payload_params[name.to_sym] = value
125
+ end
122
126
 
123
127
  # Encoder options
124
128
  option :encoder_file, value: {
@@ -228,6 +232,7 @@ module Ronin
228
232
 
229
233
  @load_encoders = []
230
234
  @encoder_params = Hash.new { |hash,key| hash[key] = {} }
235
+ @payload_params = {}
231
236
  @target_kwargs = {}
232
237
  end
233
238
 
@@ -244,6 +249,7 @@ module Ronin
244
249
  load_payload
245
250
  initialize_encoders
246
251
  initialize_payload
252
+ validate_payload
247
253
  initialize_exploit
248
254
  validate_exploit
249
255
  run_exploit
@@ -257,6 +263,10 @@ module Ronin
257
263
  perform_cleanup
258
264
  end
259
265
 
266
+ #
267
+ # Loads the payload encoder classes specified by `--encoder` or
268
+ # `--encoder-file`.
269
+ #
260
270
  def load_encoders
261
271
  @encoder_classes = @load_encoders.map do |(type,value)|
262
272
  case type
@@ -266,12 +276,20 @@ module Ronin
266
276
  end
267
277
  end
268
278
 
279
+ #
280
+ # Initializes the payload encoders specified by `--encoder` or
281
+ # `--encoder-file`.
282
+ #
269
283
  def initialize_encoders
270
284
  @encoders = @encoder_classes.map do |encoder_class|
271
285
  encoder_class.new(params: @encoder_params[encoder_class.id])
272
286
  end
273
287
  end
274
288
 
289
+ #
290
+ # Loads the payload class specified by `--payload` or
291
+ # `--payload-file`.
292
+ #
275
293
  def load_payload
276
294
  @payload_class = if options[:payload]
277
295
  super(options[:payload])
@@ -280,6 +298,10 @@ module Ronin
280
298
  end
281
299
  end
282
300
 
301
+ #
302
+ # Initializes the payload specified by `--payload`, `--payload-file`,
303
+ # `--read-payload`, or `--payload-string`.
304
+ #
283
305
  def initialize_payload
284
306
  @payload = if @payload_class
285
307
  super(@payload_class, params: @payload_params,
@@ -291,6 +313,16 @@ module Ronin
291
313
  end
292
314
  end
293
315
 
316
+ #
317
+ # Validates the payload.
318
+ #
319
+ def validate_payload
320
+ super(@payload)
321
+ end
322
+
323
+ #
324
+ # Initializes the exploit.
325
+ #
294
326
  def initialize_exploit
295
327
  kwargs = {params: @params}
296
328
 
@@ -309,13 +341,16 @@ module Ronin
309
341
  super(**kwargs)
310
342
  end
311
343
 
344
+ #
345
+ # Runs the exploit.
346
+ #
312
347
  def run_exploit
313
348
  log_info "Running exploit #{@exploit.class_id} ..."
314
349
 
315
350
  begin
316
351
  @exploit.exploit(dry_run: options[:dry_run])
317
352
  rescue ExploitError => error
318
- print_error("failed to run exploit #{@exploit.class_id}: #{error.message}")
353
+ print_error "failed to run exploit #{@exploit.class_id}: #{error.message}"
319
354
  exit(1)
320
355
  rescue => error
321
356
  print_exception(error)
@@ -324,6 +359,9 @@ module Ronin
324
359
  end
325
360
  end
326
361
 
362
+ #
363
+ # Starts an interactive ruby shell within the exploit object.
364
+ #
327
365
  def start_shell
328
366
  log_info "Exploit #{@exploit.class_id} launched!"
329
367
  log_info "Starting interactive Ruby shell ..."
@@ -331,12 +369,15 @@ module Ronin
331
369
  RubyShell.start(name: @exploit_class.name, context: @exploit)
332
370
  end
333
371
 
372
+ #
373
+ # Performs the post-exploitation stage.
374
+ #
334
375
  def post_exploitation
335
376
  if @exploit_class.include?(Mixins::HasPayload) &&
336
377
  @exploit.payload.kind_of?(Ronin::Payloads::Payload) &&
337
- @exploit.payload.kind_of?(Ronin::Payloads::Mixins::PostExt)
378
+ @exploit.payload.kind_of?(Ronin::Payloads::Mixins::PostEx)
338
379
  unless @exploit.payload.session
339
- print_error("payload (#{@exploit.payload.class_id}) did not create a post-exploitation session")
380
+ print_error "payload (#{@exploit.payload.class_id}) did not create a post-exploitation session"
340
381
 
341
382
  perform_cleanup
342
383
  eixt(1)
@@ -349,6 +390,9 @@ module Ronin
349
390
  end
350
391
  end
351
392
 
393
+ #
394
+ # Prints any loot collected by the exploit.
395
+ #
352
396
  def print_loot
353
397
  unless @exploit.loot.empty?
354
398
  log_info "Exploit found the following loot:"
@@ -372,15 +416,21 @@ module Ronin
372
416
  end
373
417
  end
374
418
 
419
+ #
420
+ # Saves the collected loot to the `--save-loot` directory.
421
+ #
375
422
  def save_loot
376
423
  @exploit.loot.save(options.fetch(:save_loot))
377
424
  end
378
425
 
426
+ #
427
+ # Performs the cleanup stage of the exploit.
428
+ #
379
429
  def perform_cleanup
380
430
  begin
381
431
  @exploit.perform_cleanup
382
432
  rescue ExploitError => error
383
- print_error("failed to cleanup exploit #{@exploit.class_id}: #{error.message}")
433
+ print_error "failed to cleanup exploit #{@exploit.class_id}: #{error.message}"
384
434
  exit(1)
385
435
  rescue => error
386
436
  print_exception(error)
@@ -52,7 +52,7 @@ module Ronin
52
52
  # The {Exploit} class defines six key parts:
53
53
  #
54
54
  # 1. Metadata - defines information about the exploit.
55
- # 2. Params - user configurable parameters.
55
+ # 2. [Params] - user configurable parameters.
56
56
  # 3. {Exploit#test test} - optional method that tests whether the target is
57
57
  # vulnerable or not.
58
58
  # 4. {Exploit#build build} - method which builds the exploit.
@@ -60,6 +60,8 @@ module Ronin
60
60
  # 6. {Exploit#cleanup cleanup} - optional Method which performs additional
61
61
  # cleanup steps.
62
62
  #
63
+ # [Params]: https://ronin-rb.dev/docs/ronin-core/Ronin/Core/Params/Mixin.html
64
+ #
63
65
  # ## Example
64
66
  #
65
67
  # require 'ronin/exploits/exploit'
@@ -136,7 +138,7 @@ module Ronin
136
138
  #
137
139
  # ### description
138
140
  #
139
- # Defines a longer multi-paragraph escription of the exploit.
141
+ # Defines a longer multi-paragraph description of the exploit.
140
142
  #
141
143
  # description <<~EOS
142
144
  # This is my first exploit.
@@ -313,7 +315,7 @@ module Ronin
313
315
  end
314
316
 
315
317
  #
316
- # Determines whether the exploit has been publically released yet.
318
+ # Determines whether the exploit has been publicly released yet.
317
319
  #
318
320
  # @return [Boolean]
319
321
  #
@@ -526,7 +528,7 @@ module Ronin
526
528
  end
527
529
 
528
530
  #
529
- # Builds the exploit and then launchs the exploit.
531
+ # Builds the exploit and then launches the exploit.
530
532
  #
531
533
  # @param [Boolean] dry_run
532
534
  # If `true` performs a dry-run by only calling {#build} and **not**
@@ -633,7 +635,7 @@ module Ronin
633
635
  end
634
636
 
635
637
  #
636
- # Place holder method for testing whether the targeet is vulnerable.
638
+ # Place holder method for testing whether the target is vulnerable.
637
639
  #
638
640
  # @return [Test::Vulnerable, Test::NotVulnerable, Test::Unknown]
639
641
  #
@@ -73,7 +73,7 @@ module Ronin
73
73
  # Gets or sets the directory traversal depth for the LFI vulnerability.
74
74
  #
75
75
  # @param [Integer, nil] new_depth
76
- # The optional new directory trasversal depth to set.
76
+ # The optional new directory traversal depth to set.
77
77
  #
78
78
  # @return [Integer]
79
79
  # The LFI vulnerability's directory traverse depth.
@@ -40,7 +40,7 @@ module Ronin
40
40
 
41
41
  module ClassMethods
42
42
  #
43
- # Gets or sets the exploits's targetted architecture.
43
+ # Gets or sets the exploit's targeted architecture.
44
44
  #
45
45
  # @param [:x86, :x86_64, :ia64, :amd64, :ppc, :ppc64, :mips, :mips_le, :mips_be, :mips64, :mips64_le, :mips64_be, :arm, :arm_le, :arm_be, :arm64, :arm64_le, :arm64_be, nil] new_arch
46
46
  # The optional new architecture to set.
@@ -40,7 +40,7 @@ module Ronin
40
40
 
41
41
  module ClassMethods
42
42
  #
43
- # Gets or sets the exploits's default filename.
43
+ # Gets or sets the exploit's default filename.
44
44
  #
45
45
  # @param [Integer, nil] new_default_filename
46
46
  # The optional new default filename to set.
@@ -40,7 +40,7 @@ module Ronin
40
40
 
41
41
  module ClassMethods
42
42
  #
43
- # Gets or sets the exploits's default port.
43
+ # Gets or sets the exploit's default port.
44
44
  #
45
45
  # @param [Integer, nil] new_default_port
46
46
  # The optional new default port number to set.
@@ -24,8 +24,8 @@ module Ronin
24
24
  module Exploits
25
25
  module Mixins
26
26
  #
27
- # Adds methods for building exploit files. Also adds a `filenam`
28
- # param and a
27
+ # Adds methods for building exploit files. Also adds a `filename` param
28
+ # and a
29
29
  # {Metadata::DefaultFilename::ClassMethods#default_filename default_filename}
30
30
  # class method.
31
31
  #
@@ -81,7 +81,7 @@ module Ronin
81
81
  end
82
82
 
83
83
  #
84
- # An individual NOP instructure for the target architecture of the
84
+ # An individual NOP instruction for the target architecture of the
85
85
  # exploit.
86
86
  #
87
87
  # @return [String]
@@ -64,7 +64,7 @@ module Ronin
64
64
  end
65
65
 
66
66
  #
67
- # Expands the URL or path into a fully qualitifed URL.
67
+ # Expands the URL or path into a fully qualified URL.
68
68
  #
69
69
  # @param [String] path
70
70
  # The URL or path to expand.
@@ -21,6 +21,6 @@
21
21
  module Ronin
22
22
  module Exploits
23
23
  # ronin-exploits version
24
- VERSION = '1.0.0.beta2'
24
+ VERSION = '1.0.0'
25
25
  end
26
26
  end
@@ -27,6 +27,8 @@ Gem::Specification.new do |gem|
27
27
  gem.files = `git ls-files`.split($/)
28
28
  gem.files = glob[gemspec['files']] if gemspec['files']
29
29
  gem.files += Array(gemspec['generated_files'])
30
+ # exclude test files from the packages gem
31
+ gem.files -= glob[gemspec['test_files'] || 'spec/{**/}*']
30
32
 
31
33
  gem.executables = gemspec.fetch('executables') do
32
34
  glob['bin/*'].map { |path| File.basename(path) }
@@ -34,7 +36,6 @@ Gem::Specification.new do |gem|
34
36
  gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
35
37
 
36
38
  gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
37
- gem.test_files = glob[gemspec['test_files'] || 'spec/{**/}*_spec.rb']
38
39
  gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
39
40
 
40
41
  gem.require_paths = Array(gemspec.fetch('require_paths') {