cgi_multipart_eof_fix 2.0.1

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