Nippon, we have a problem.
RUBY_PATCHLEVEL.Ich möchte versuchen, Licht ins Dunkel zu bringen.
Folgende Änderungen unterscheiden Ruby 1.8.5-ps (2006-12-04) von Ruby 1.8.5 (2006-08-29):
ChangeLogMon 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.
stdinput.read gab einen leeren String zurück anstatt nil, wenn das Ende des Inputs erreicht war.
Dadurch entstand eine Endlosschleife. Auslösen konnte man das einfach, indem man eine Multipart-Form an cgi.rb schickt,
die nicht mit dem erwarteten Zeichen endet.boundary wurde nicht maskiert. Wenn man boundary auf (?!) oder so etwas setzt, wird es nie gefunden.
Oder man fügt einer dieser "Milliarden Jahre Rechenzeit"-Regexps ein.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.
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
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
[...] Ä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. [...]