From a872bcce127a6f4a0f16af8f28b686955ba32814 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 26 May 2022 13:26:25 -0700 Subject: [PATCH] Restrict broken mime parsing This commit restricts broken mime parsing to deal with a ReDOS vulnerability. [CVE-2022-30122] --- lib/rack/multipart.rb | 3 +-- lib/rack/multipart/parser.rb | 3 ++- ...ame_with_escaped_quotes_and_modification_param | 2 +- test/spec_multipart.rb | 15 +-------------- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/lib/rack/multipart.rb b/lib/rack/multipart.rb index 45f43bb68..10f8e5fa3 100644 --- a/lib/rack/multipart.rb +++ b/lib/rack/multipart.rb @@ -16,8 +16,7 @@ module Multipart TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/ CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/ - BROKEN_QUOTED = /^#{CONDISP}.*;\s*filename="(.*?)"(?:\s*$|\s*;\s*#{TOKEN}=)/i - BROKEN_UNQUOTED = /^#{CONDISP}.*;\s*filename=(#{TOKEN})/i + BROKEN = /^#{CONDISP}.*;\s*filename=(#{VALUE})/i MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*;\s*name=(#{VALUE})/ni MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni diff --git a/lib/rack/multipart/parser.rb b/lib/rack/multipart/parser.rb index 2eb38380b..e8ed3e976 100644 --- a/lib/rack/multipart/parser.rb +++ b/lib/rack/multipart/parser.rb @@ -301,8 +301,9 @@ def get_filename(head) elsif filename = params['filename*'] encoding, _, filename = filename.split("'", 3) end - when BROKEN_QUOTED, BROKEN_UNQUOTED + when BROKEN filename = $1 + filename = $1 if filename =~ /^"(.*)"$/ end return unless filename diff --git a/test/multipart/filename_with_escaped_quotes_and_modification_param b/test/multipart/filename_with_escaped_quotes_and_modification_param index 7619bd507..929f6ad3f 100644 --- a/test/multipart/filename_with_escaped_quotes_and_modification_param +++ b/test/multipart/filename_with_escaped_quotes_and_modification_param @@ -1,6 +1,6 @@ --AaB03x Content-Type: image/jpeg -Content-Disposition: attachment; name="files"; filename=""human" genome.jpeg"; modification-date="Wed, 12 Feb 1997 16:29:51 -0500"; +Content-Disposition: attachment; name="files"; filename="\"human\" genome.jpeg"; modification-date="Wed, 12 Feb 1997 16:29:51 -0500"; Content-Description: a complete map of the human genome contents diff --git a/test/spec_multipart.rb b/test/spec_multipart.rb index 717e0dc81..0275fa52d 100644 --- a/test/spec_multipart.rb +++ b/test/spec_multipart.rb @@ -433,19 +433,6 @@ def initialize(*) params["files"][:tempfile].read.must_equal "contents" end - it "parse filename with unescaped quotes" do - env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_quotes)) - params = Rack::Multipart.parse_multipart(env) - params["files"][:type].must_equal "application/octet-stream" - params["files"][:filename].must_equal "escape \"quotes" - params["files"][:head].must_equal "Content-Disposition: form-data; " + - "name=\"files\"; " + - "filename=\"escape \"quotes\"\r\n" + - "Content-Type: application/octet-stream\r\n" - params["files"][:name].must_equal "files" - params["files"][:tempfile].read.must_equal "contents" - end - it "parse filename with escaped quotes and modification param" do env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_escaped_quotes_and_modification_param)) params = Rack::Multipart.parse_multipart(env) @@ -454,7 +441,7 @@ def initialize(*) params["files"][:head].must_equal "Content-Type: image/jpeg\r\n" + "Content-Disposition: attachment; " + "name=\"files\"; " + - "filename=\"\"human\" genome.jpeg\"; " + + "filename=\"\\\"human\\\" genome.jpeg\"; " + "modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";\r\n" + "Content-Description: a complete map of the human genome\r\n" params["files"][:name].must_equal "files"