cgi_multipart_eof_fix 2.0.1

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.
data/README.txt ADDED
@@ -0,0 +1,43 @@
1
+
2
+ DESCRIPTION
3
+
4
+ Fix an exploitable bug in CGI multipart parsing which affects Ruby <= 1.8.5
5
+ when multipart boundary attribute contains a non-halting regular expression
6
+ string. The boundary searcher in the CGI module does not properly escape
7
+ the user-supplied parameter and will execute arbitrary regular expressions.
8
+ The fix adds escaping for the user data.
9
+
10
+ This is fix is cumulative with previous CGI multipart vulnerability fixes; see
11
+ version 1.0.0 of the gem by Zed Shaw.
12
+
13
+ SCOPE
14
+
15
+ Affected: standalone CGI, Mongrel, WEBrick
16
+ Unaffected: FastCGI
17
+ Unknown: mod_ruby
18
+
19
+ USAGE
20
+
21
+ Install the hotfix gem and run the included test to verify the flaw is
22
+ corrected. You must require the gem in every affected application, as follows:
23
+
24
+ require 'rubygems'
25
+ require 'cgi_multipart_eof_fix'
26
+
27
+ If you only use mongrel_rails for application hosting, you may install mongrel
28
+ like so:
29
+
30
+ sudo gem install mongrel --source=http://mongrel.rubyforge.org/releases
31
+
32
+ Then mongrel will require the fix for you, provided you have installed version 2.0.0
33
+ of this gem. This is a hack, and mongrel may change in the future.
34
+
35
+ RESOURCES
36
+
37
+ http://www.ruby-lang.org/en/news/2006/12/04/another-dos-vulnerability-in-cgi-library/
38
+ http://blog.evanweaver.com/articles/2006/12/05/cgi-rb-vulnerability-hotfix
39
+
40
+ LICENSE
41
+
42
+ Licensed under the same license as Ruby itself. Software contains the work of others.
43
+
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ NAME = "cgi_multipart_eof_fix"
5
+
6
+ begin
7
+ require 'rake/clean'
8
+ require 'echoe'
9
+ require 'fileutils'
10
+
11
+ AUTHOR = "Evan Weaver"
12
+ EMAIL = "evan at cloudbur dot st"
13
+ DESCRIPTION = "Fix an exploitable bug in CGI multipart parsing which affects Ruby <= 1.8.5 when multipart boundary attribute contains a non-halting regular expression string."
14
+ RUBYFORGE_NAME = "fauna"
15
+ GEM_NAME = "cgi_multipart_eof_fix"
16
+ HOMEPATH = "http://blog.evanweaver.com"
17
+ RELEASE_TYPES = ["gem"]
18
+ REV = nil
19
+ VERS = "2.0.1"
20
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config']
21
+ RDOC_OPTS = ['--quiet', '--title', "cgi_multipart_eof_fix documentation",
22
+ "--opname", "index.html",
23
+ "--line-numbers",
24
+ "--main", "README",
25
+ "--inline-source"]
26
+
27
+ include FileUtils
28
+ require File.join(File.dirname(__FILE__), 'lib', 'cgi_multipart_eof_fix')
29
+
30
+ echoe = Echoe.new(GEM_NAME, VERS) do |p|
31
+ p.author = AUTHOR
32
+ p.rubyforge_name = RUBYFORGE_NAME
33
+ p.name = NAME
34
+ p.description = DESCRIPTION
35
+ p.email = EMAIL
36
+ p.summary = DESCRIPTION
37
+ p.url = HOMEPATH
38
+ p.test_globs = ["*_test.rb"]
39
+ p.clean_globs = CLEAN
40
+ end
41
+
42
+ rescue LoadError => boom
43
+ puts "You are missing a dependency required for meta-operations on this gem."
44
+ puts "#{boom.to_s.capitalize}."
45
+
46
+ desc 'Run the default tasks'
47
+ task :default => :test
48
+
49
+ desc 'Run the test suite.'
50
+ task :test do
51
+ system "ruby -Ibin:lib:test #{NAME}_test.rb"
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ require 'cgi'
3
+ require 'stringio'
4
+ require 'timeout'
5
+
6
+ def test_read_multipart_eof_fix
7
+ boundary = '%?%(\w*)\\((\w*)\\)'
8
+ data = "--#{boundary}\r\nContent-Disposition: form-data; name=\"a_field\"\r\n\r\nBang!\r\n--#{boundary}--\r\n"
9
+
10
+ ENV['REQUEST_METHOD'] = "POST"
11
+ ENV['CONTENT_TYPE'] = "multipart/form-data; boundary=\"#{boundary}\""
12
+ ENV['CONTENT_LENGTH'] = data.length.to_s
13
+
14
+ $stdin = StringIO.new(data)
15
+
16
+ begin
17
+ Timeout.timeout(3) { CGI.new }
18
+ $stderr.puts ' => CGI is safe: read_multipart does not hang on malicious multipart requests.'
19
+ rescue TimeoutError
20
+ $stderr.puts ' => CGI is exploitable: read_multipart hangs on malicious multipart requests.'
21
+ end
22
+ end
23
+
24
+ $stderr.puts 'Testing malicious multipart boundary request injection'
25
+ test_read_multipart_eof_fix
26
+
27
+ $stderr.puts 'Patching CGI::QueryExtension.read_multipart'
28
+ require 'rubygems'
29
+ require 'cgi_multipart_eof_fix'
30
+
31
+ test_read_multipart_eof_fix
@@ -0,0 +1,112 @@
1
+ require 'cgi'
2
+
3
+ class CGI
4
+ module QueryExtension
5
+ def read_multipart(boundary, content_length)
6
+ params = Hash.new([])
7
+ boundary = "--" + boundary
8
+ quoted_boundary = Regexp.quote(boundary, "n")
9
+ buf = ""
10
+ bufsize = 10 * 1024
11
+ boundary_end=""
12
+
13
+ # start multipart/form-data
14
+ stdinput.binmode if defined? stdinput.binmode
15
+ boundary_size = boundary.size + EOL.size
16
+ content_length -= boundary_size
17
+ status = stdinput.read(boundary_size)
18
+ if nil == status
19
+ raise EOFError, "no content body"
20
+ elsif boundary + EOL != status
21
+ raise EOFError, "bad content body #{status.inspect} expected, got #{(boundary + EOL).inspect}"
22
+ end
23
+
24
+ loop do
25
+ head = nil
26
+ if 10240 < content_length
27
+ require "tempfile"
28
+ body = Tempfile.new("CGI")
29
+ else
30
+ begin
31
+ require "stringio"
32
+ body = StringIO.new
33
+ rescue LoadError
34
+ require "tempfile"
35
+ body = Tempfile.new("CGI")
36
+ end
37
+ end
38
+ body.binmode if defined? body.binmode
39
+
40
+ until head and /#{quoted_boundary}(?:#{EOL}|--)/n.match(buf)
41
+
42
+ if (not head) and /#{EOL}#{EOL}/n.match(buf)
43
+ buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
44
+ head = $1.dup
45
+ ""
46
+ end
47
+ next
48
+ end
49
+
50
+ if head and ( (EOL + boundary + EOL).size < buf.size )
51
+ body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
52
+ buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
53
+ end
54
+
55
+ c = if bufsize < content_length
56
+ stdinput.read(bufsize)
57
+ else
58
+ stdinput.read(content_length)
59
+ end
60
+ if c.nil? || c.empty?
61
+ raise EOFError, "bad content body"
62
+ end
63
+ buf.concat(c)
64
+ content_length -= c.size
65
+ end
66
+
67
+ buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do
68
+ body.print $1
69
+ if "--" == $2
70
+ content_length = -1
71
+ end
72
+ boundary_end = $2.dup
73
+ ""
74
+ end
75
+
76
+ body.rewind
77
+
78
+ /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
79
+ filename = ($1 or "")
80
+ if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and
81
+ /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and
82
+ (not /MSIE/ni.match(env_table['HTTP_USER_AGENT']))
83
+ filename = CGI::unescape(filename)
84
+ end
85
+
86
+ /Content-Type: (.*)/ni.match(head)
87
+ content_type = ($1 or "")
88
+
89
+ (class << body; self; end).class_eval do
90
+ alias local_path path
91
+ define_method(:original_filename) {filename.dup.taint}
92
+ define_method(:content_type) {content_type.dup.taint}
93
+ end
94
+
95
+ /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
96
+ name = $1.dup
97
+
98
+ if params.has_key?(name)
99
+ params[name].push(body)
100
+ else
101
+ params[name] = [body]
102
+ end
103
+ break if buf.size == 0
104
+ break if content_length === -1
105
+ end
106
+ raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/
107
+
108
+ params
109
+ end # read_multipart
110
+ private :read_multipart
111
+ end
112
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0.9
3
+ specification_version: 1
4
+ name: cgi_multipart_eof_fix
5
+ version: !ruby/object:Gem::Version
6
+ version: 2.0.1
7
+ date: 2007-01-10 00:00:00 -05:00
8
+ summary: Fix an exploitable bug in CGI multipart parsing which affects Ruby <= 1.8.5 when multipart boundary attribute contains a non-halting regular expression string.
9
+ require_paths:
10
+ - lib
11
+ email: evan at cloudbur dot st
12
+ homepage: http://blog.evanweaver.com
13
+ rubyforge_project: fauna
14
+ description: Fix an exploitable bug in CGI multipart parsing which affects Ruby <= 1.8.5 when multipart boundary attribute contains a non-halting regular expression string.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Evan Weaver
31
+ files:
32
+ - README.txt
33
+ - Rakefile
34
+ - lib/cgi_multipart_eof_fix.rb
35
+ - cgi_multipart_eof_fix_test.rb
36
+ test_files:
37
+ - cgi_multipart_eof_fix_test.rb
38
+ rdoc_options: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ executables: []
43
+
44
+ extensions: []
45
+
46
+ requirements: []
47
+
48
+ dependencies: []
49
+