diff --git a/lib/brakeman/checks/check_render_dos.rb b/lib/brakeman/checks/check_render_dos.rb new file mode 100644 index 0000000000000000000000000000000000000000..57d1e846a84917da55b5a866be9f6283481387eb --- /dev/null +++ b/lib/brakeman/checks/check_render_dos.rb @@ -0,0 +1,37 @@ +require 'brakeman/checks/base_check' + +class Brakeman::CheckRenderDoS < Brakeman::BaseCheck + Brakeman::Checks.add self + + @description = "Warn about denial of service with render :text (CVE-2014-0082)" + + def run_check + if version_between? "3.0.0", "3.0.20" or + version_between? "3.1.0", "3.1.12" or + version_between? "3.2.0", "3.2.16" + + tracker.find_call(:target => nil, :method => :render).each do |result| + if text_render? result + warn_about_text_render + break + end + end + end + end + + def text_render? result + node_type? result[:call], :render and + result[:call].render_type == :text + end + + def warn_about_text_render + message = "Rails #{tracker.config[:rails_version]} has a denial of service vulnerability (CVE-2014-0082). Upgrade to Rails version 3.2.17" + + warn :warning_type => "Denial of Service", + :warning_code => :CVE_2014_0082, + :message => message, + :confidence => CONFIDENCE[:high], + :link_path => "https://groups.google.com/d/msg/rubyonrails-security/LMxO_3_eCuc/ozGBEhKaJbIJ", + :file => gemfile_or_environment + end +end diff --git a/lib/brakeman/warning_codes.rb b/lib/brakeman/warning_codes.rb index 6c00db866c7600d13a0a7a9fd0ac76dbff32deda..6fb1b1a0fb83ece6583897121aca44d30bfab585 100644 --- a/lib/brakeman/warning_codes.rb +++ b/lib/brakeman/warning_codes.rb @@ -75,6 +75,7 @@ module Brakeman::WarningCodes :CVE_2014_0080 => 72, :CVE_2014_0081 => 73, :CVE_2014_0081_call => 74, + :CVE_2014_0082 => 75, } def self.code name diff --git a/test/apps/rails3.2/app/controllers/users_controller.rb b/test/apps/rails3.2/app/controllers/users_controller.rb index 7914c966c2b2e9ebb334f2309f34e47bcf23111c..4f782bec7875e6b9c0d3c5000e8a21fad7edfa3e 100644 --- a/test/apps/rails3.2/app/controllers/users_controller.rb +++ b/test/apps/rails3.2/app/controllers/users_controller.rb @@ -92,4 +92,8 @@ class UsersController < ApplicationController def show_detailed_exceptions? false # no warning end + + def render_text + render :text => "oh noes my service" + end end diff --git a/test/apps/rails3/app/controllers/products_controller.rb b/test/apps/rails3/app/controllers/products_controller.rb index 8c771612471fbcd46cb83d32a225e79113899984..9804f6a6875273e69e8c9def3eebb74baab2f053 100644 --- a/test/apps/rails3/app/controllers/products_controller.rb +++ b/test/apps/rails3/app/controllers/products_controller.rb @@ -80,4 +80,8 @@ class ProductsController < ApplicationController format.xml { head :ok } end end + + def render_some_text + render :text => "jello" + end end diff --git a/test/tests/rails3.rb b/test/tests/rails3.rb index 106c7fe2a3524b0573f6370d846c240072abf336..82fdc466d55533c60b7fcbb844e495a9a91364af 100644 --- a/test/tests/rails3.rb +++ b/test/tests/rails3.rb @@ -16,7 +16,7 @@ class Rails3Tests < Test::Unit::TestCase :controller => 1, :model => 8, :template => 38, - :generic => 70 + :generic => 71 } if RUBY_PLATFORM == 'java' @@ -1173,6 +1173,18 @@ class Rails3Tests < Test::Unit::TestCase :user_input => nil end + def test_denial_of_service_CVE_2014_0082 + assert_warning :type => :warning, + :warning_code => 75, + :fingerprint => "403a72d08a90043384fe56d3a6bc3e255b8799b380693914143d403607433db7", + :warning_type => "Denial of Service", + :line => nil, + :message => /^Rails\ 3\.0\.3\ has\ a\ denial\ of\ service\ vuln/, + :confidence => 0, + :relative_path => "Gemfile", + :user_input => nil + end + def test_http_only_session_setting assert_warning :type => :warning, :warning_type => "Session Setting", diff --git a/test/tests/rails32.rb b/test/tests/rails32.rb index 2d29ac90f184c523e12a8264994f857cedd71707..4bf07a897528c00666d118c9a971e73a4f3e66b8 100644 --- a/test/tests/rails32.rb +++ b/test/tests/rails32.rb @@ -11,7 +11,7 @@ class Rails32Tests < Test::Unit::TestCase :controller => 0, :model => 5, :template => 11, - :generic => 10 } + :generic => 11 } if RUBY_PLATFORM == 'java' @expected[:generic] += 1 @@ -123,6 +123,18 @@ class Rails32Tests < Test::Unit::TestCase :user_input => nil end + def test_denial_of_service_CVE_2014_0082 + assert_warning :type => :warning, + :warning_code => 75, + :fingerprint => "403a72d08a90043384fe56d3a6bc3e255b8799b380693914143d403607433db7", + :warning_type => "Denial of Service", + :line => nil, + :message => /^Rails\ 3\.2\.9\.rc2\ has\ a\ denial\ of\ service\ /, + :confidence => 0, + :relative_path => "Gemfile", + :user_input => nil + end + def test_redirect_1 assert_warning :type => :warning, :warning_type => "Redirect", diff --git a/test/tests/rescanner.rb b/test/tests/rescanner.rb index 0a08348c0dcbf60957675a8dfedbd7eaf267b292..30e01f6faac8d529d4d12fb44e63c2877c8a4201 100644 --- a/test/tests/rescanner.rb +++ b/test/tests/rescanner.rb @@ -267,4 +267,23 @@ class RescannerTests < Test::Unit::TestCase assert_new 0 assert_fixed 2 end + + def test_gemfile_rails_version_fix_CVE_2014_0082 + gemfile = "Gemfile.lock" + + before_rescan_of gemfile do + replace gemfile, "rails (3.2.9.rc2)", "rails (3.2.17)" + end + + #@original is actually modified + assert @original.config[:rails_version], "3.2.17" + assert_reindex :none + assert_changes + assert_new 0 + if RUBY_PLATFORM == "java" + assert_fixed 10 + else + assert_fixed 9 + end + end end