ruby-mine

exploring the mine

Gefährliche Sicherheitslücken in cgi.rb

von murphy am 04.12.2006 (20 Uhr)

Nippon, we have a problem.

Was ist passiert?

Ich möchte versuchen, Licht ins Dunkel zu bringen.

diff -r

Folgende Änderungen unterscheiden Ruby 1.8.5-ps (2006-12-04) von Ruby 1.8.5 (2006-08-29):

ChangeLog
Mon Dec  4 10:22:26 2006  URABE Shyouhei  

    * stable version 1.8.5-p2 relased.

Sun Dec  3 17:11:12 2006  Shugo Maeda  

    * lib/cgi.rb (CGI::QueryExtension::read_multipart): should quote
      boundary. JVN#84798830

Sun Nov 26 16:36:46 2006  URABE Shyouhei  

    * version.h: addition of RUBY_PATCHLEVEL.
    * version.c: ditto.

Sat Sep 23 21:34:15 2006  Yukihiro Matsumoto  

    * lib/cgi.rb (CGI::QueryExtension::read_multipart): CGI content
      may be empty.  a patch from Jamis Buck .

Jetzt sehen wir auch mal, wer die Lücke gefunden hat: Danke, Jamis!

lib/cgi.rb
@@ -967,6 +967,7 @@  
       def read_multipart(boundary, content_length)
         params = Hash.new([])
         boundary = "--" + boundary
  +      quoted_boundary = Regexp.quote(boundary, "n")
         buf = "" 
         bufsize = 10 * 1024
         boundary_end="" 
@@ -998,7 +999,7 @@
           end
           body.binmode if defined? body.binmode

  -        until head and /#{boundary}(?:#{EOL}|--)/n.match(buf)
  +        until head and /#{quoted_boundary}(?:#{EOL}|--)/n.match(buf)

             if (not head) and /#{EOL}#{EOL}/n.match(buf)
               buf = buf.sub(/\\\\A((?:.|\\\\n)*?#{EOL})#{EOL}/n) do
@@ -1018,14 +1019,14 @@
                 else
                   stdinput.read(content_length)
                 end
  -          if c.nil?
  +          if c.nil? || c.empty?
               raise EOFError, "bad content body" 
             end
             buf.concat(c)
             content_length -= c.size
           end

  -        buf = buf.sub(/\\\\A((?:.|\\\\n)*?)(?:[\\\\r\\\\n]{1,2})?#{boundary}([\\\\r\\\\n]{1,2}|--)/n) do
  +        buf = buf.sub(/\\\\A((?:.|\\\\n)*?)(?:[\\\\r\\\\n]{1,2})?#{quoted_boundary}([\\\\r\\\\n]{1,2}|--)/n) do
             body.print $1
             if "--" == $2
               content_length = -1
  

Hier stecken also die eigentlichen Fehler.

Ich weiß leider nicht, wer die zweite Lücke gefunden hat.

Bleibt noch das neue Patchlevel:

version.c und version.h
const int ruby_patchlevel = RUBY_PATCHLEVEL;
...
rb_define_global_const("RUBY_PATCHLEVEL", INT2FIX(RUBY_PATCHLEVEL));
...
#define RUBY_PATCHLEVEL 2
...
RUBY_EXTERN const int ruby_patchlevel;

Die Diskussion um die Einführung des Patchlevels und eines neuen CVS-Branches (er schient jetzt ruby_1_8_5 zu heißen) findet ihr im Archiv.

Für Programmierer

Baut folgende Prüfung ein, wenn eure Skripte cgi.rb benutzen (soweit ich weiß, tun das unter anderem alle Rails-Applikationen; laut Jeremy Kemper ist Rails aber nicht betroffen, wenn man im production-Mode unter FastCGI arbeitet.)

if not defined? RUBY_PATCHLEVEL or (RUBY_VERSION <= '1.8.5' and RUBY_PATCHLEVEL < 2)
  raise SecurityError, 'Please use Ruby 1.8.5-p2 or later!'
end

Echo

Based on how the cgi.rb file is coded it's most likely that there will be more of these kinds of defects in the future.
(Zed A .Shaw, der Mongrel-Typ) [Edit: Prüfungscode für Ruby 1.9 angepasst (Patchlevel natürlich nur für bereits veröffentlichte Versionen.)]


Kommentare

  1. Ruby-Mine &raquo; Blog Archive &raquo; Ruby 1.8.5-12 OCI schrieb am 12.02.2007 (21 Uhr)

    [...] Änderungen: Die Ruby-IDE FreeRIDE ist nun mehr enthalten, dafür Ruby 1.8.5 patchlevel 12 (CGI-Sicherheitslücken, siehe Beitrag), RubyGems 0.9.2, Hpricot statt HTMLParser und weitere Updates. Die Ruby- und RubyOnRails-Websiten empfehlen Ruby 1.8.5-p12, und wir ebenfalls. [...]