• Stars
    star
    133
  • Rank 272,600 (Top 6 %)
  • Language
    Ruby
  • Created over 5 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

RCE on Rails 5.2.2 using a path traversal (CVE-2019-5418) and a deserialization of Ruby objects (CVE-2019-5420)

Rails-doubletap-exploit

RCE on Rails 5.2.2 using a path traversal (CVE-2019-5418) and a deserialization of Ruby objects (CVE-2019-5420)

capture d'Γ©cran

Technical Analysis:

Security Adivsory:


Exploit

  1. The exploit check if the Rails application is vulnerable to the CVE-2019-5418
  2. Then gets the content of the files: credentials.yml.enc and master.key
  3. Decrypt the credentials.yml.enc and get the secret_key_base value
  4. Craft a request to the ressource /rails/active_storage/disk/:encoded_key/*filename(.:format) => CVE-2019-5420
  5. Send the request to the vulnerable server
  6. The code is executed on the server

capture d'Γ©cran_1

Mitigations


Fix of CVE-2019-5420

From 7f5ccda38bfecbe0bf00f15e5b8f5e40d52ab3f1 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <[email protected]>
Date: Sun, 10 Mar 2019 16:37:46 -0700
Subject: [PATCH] Fix possible dev mode RCE

If the secret_key_base is nil in dev or test generate a key from random
bytes and store it in a tmp file. This prevents the app developers from
having to share / checkin the secret key for dev / test but also
maintains a key between app restarts in dev/test.

[CVE-2019-5420]

Co-Authored-By: eileencodes <[email protected]>
Co-Authored-By: John Hawthorn <[email protected]>
---
 .../middleware/session/cookie_store.rb        |  7 +++---
 railties/lib/rails/application.rb             | 19 ++++++++++++++--
 .../test/application/configuration_test.rb    | 22 ++++++++++++++++++-
 railties/test/isolation/abstract_unit.rb      |  1 +
 4 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index 4ea96196d3..b7475d3682 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -29,9 +29,10 @@
     #
     #   Rails.application.config.session_store :cookie_store, key: '_your_app_session'
     #
-    # By default, your secret key base is derived from your application name in
-    # the test and development environments. In all other environments, it is stored
-    # encrypted in the <tt>config/credentials.yml.enc</tt> file.
+    # In the development and test environments your application's secret key base is
+    # generated by Rails and stored in a temporary file in <tt>tmp/development_secret.txt</tt>.
+    # In all other environments, it is stored encrypted in the
+    # <tt>config/credentials.yml.enc</tt> file.
     #
     # If your application was not updated to Rails 5.2 defaults, the secret_key_base
     # will be found in the old <tt>config/secrets.yml</tt> file.
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index e346d5cc3a..6a30e8cfa0 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -426,8 +426,8 @@ def secrets=(secrets) #:nodoc:
     # then credentials.secret_key_base, and finally secrets.secret_key_base. For most applications,
     # the correct place to store it is in the encrypted credentials file.
     def secret_key_base
-      if Rails.env.test? || Rails.env.development?
-        secrets.secret_key_base || Digest::MD5.hexdigest(self.class.name)
+      if Rails.env.development? || Rails.env.test?
+        secrets.secret_key_base ||= generate_development_secret
       else
         validate_secret_key_base(
           ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
@@ -588,6 +588,21 @@ def validate_secret_key_base(secret_key_base)
 
     private
 
+      def generate_development_secret
+        if secrets.secret_key_base.nil?
+          key_file = Rails.root.join("tmp/development_secret.txt")
+
+          if !File.exist?(key_file)
+            random_key = SecureRandom.hex(64)
+            File.binwrite(key_file, random_key)
+          end
+
+          secrets.secret_key_base = File.binread(key_file)
+        end
+
+        secrets.secret_key_base
+      end
+
       def build_request(env)
         req = super
         env["ORIGINAL_FULLPATH"] = req.fullpath
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 293a1a7dbd..68c2199aba 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -513,6 +513,27 @@ def index
     end
 
 
+    test "application will generate secret_key_base in tmp file if blank in development" do
+      app_file "config/initializers/secret_token.rb", <<-RUBY
+        Rails.application.credentials.secret_key_base = nil
+      RUBY
+
+      app "development"
+
+      assert_not_nil app.secrets.secret_key_base
+      assert File.exist?(app_path("tmp/development_secret.txt"))
+    end
+
+    test "application will not generate secret_key_base in tmp file if blank in production" do
+      app_file "config/initializers/secret_token.rb", <<-RUBY
+        Rails.application.credentials.secret_key_base = nil
+      RUBY
+
+      assert_raises ArgumentError do
+        app "production"
+      end
+    end
+
     test "raises when secret_key_base is blank" do
       app_file "config/initializers/secret_token.rb", <<-RUBY
         Rails.application.credentials.secret_key_base = nil
@@ -550,7 +571,6 @@ def index
 
     test "application verifier can build different verifiers" do
       make_basic_app do |application|
-        application.credentials.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33"
         application.config.session_store :disabled
       end
 
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index 6568a356d6..fe850d45ec 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -155,6 +155,7 @@ def self.name; "RailtiesTestApp"; end
       @app.config.active_support.deprecation = :log
       @app.config.active_support.test_order = :random
       @app.config.log_level = :info
+      @app.secrets.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33"
 
       yield @app if block_given?
       @app.initialize!
-- 
2.21.0

Fix of CVE-2019-5418

From d7fac9c09a535ec7f11bb9aa8addb4af37b7d4b5 Mon Sep 17 00:00:00 2001
From: John Hawthorn <[email protected]>
Date: Mon, 4 Mar 2019 18:24:51 -0800
Subject: [PATCH] Only accept formats from registered mime types

[CVE-2019-5418]
[CVE-2019-5419]
---
 .../lib/action_dispatch/http/mime_negotiation.rb   |  5 +++++
 actionpack/test/controller/mime/respond_to_test.rb | 10 ++++++----
 .../new_base/content_negotiation_test.rb           | 14 ++++++++++++--
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index d7435fa8df..ada52adfeb 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -74,6 +74,11 @@ def formats
           else
             [Mime[:html]]
           end
+
+          v = v.select do |format|
+            format.symbol || format.ref == "*/*"
+          end
+
           set_header k, v
         end
       end
diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb
index f9ffd5f54c..a80cef83b7 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -105,7 +105,7 @@ def made_for_content_type
   def custom_type_handling
     respond_to do |type|
       type.html { render body: "HTML"    }
-      type.custom("application/crazy-xml")  { render body: "Crazy XML"  }
+      type.custom("application/fancy-xml")  { render body: "Fancy XML"  }
       type.all  { render body: "Nothing" }
     end
   end
@@ -294,12 +294,14 @@ def setup
     @request.host = "www.example.com"
     Mime::Type.register_alias("text/html", :iphone)
     Mime::Type.register("text/x-mobile", :mobile)
+    Mime::Type.register("application/fancy-xml", :fancy_xml)
   end
 
   def teardown
     super
     Mime::Type.unregister(:iphone)
     Mime::Type.unregister(:mobile)
+    Mime::Type.unregister(:fancy_xml)
   end
 
   def test_html
@@ -455,10 +457,10 @@ def test_synonyms
   end
 
   def test_custom_types
-    @request.accept = "application/crazy-xml"
+    @request.accept = "application/fancy-xml"
     get :custom_type_handling
-    assert_equal "application/crazy-xml", @response.content_type
-    assert_equal "Crazy XML", @response.body
+    assert_equal "application/fancy-xml", @response.content_type
+    assert_equal "Fancy XML", @response.body
 
     @request.accept = "text/html"
     get :custom_type_handling
diff --git a/actionpack/test/controller/new_base/content_negotiation_test.rb b/actionpack/test/controller/new_base/content_negotiation_test.rb
index 7205e90176..6de91c57b7 100644
--- a/actionpack/test/controller/new_base/content_negotiation_test.rb
+++ b/actionpack/test/controller/new_base/content_negotiation_test.rb
@@ -20,9 +20,19 @@ def all
       assert_body "Hello world */*!"
     end
 
-    test "Not all mimes are converted to symbol" do
+    test "A js or */* Accept header will return HTML" do
+      get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "text/javascript, */*" }
+      assert_body "Hello world text/html!"
+    end
+
+    test "A js or */* Accept header on xhr will return HTML" do
+      get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "text/javascript, */*" }, xhr: true
+      assert_body "Hello world text/javascript!"
+    end
+
+    test "Unregistered mimes are ignored" do
       get "/content_negotiation/basic/all", headers: { "HTTP_ACCEPT" => "text/plain, mime/another" }
-      assert_body '[:text, "mime/another"]'
+      assert_body '[:text]'
     end
   end
 end
-- 
2.21.0

More Repositories

1

BackupOperatorToDA

From an account member of the group Backup Operators to Domain Admin without RDP or WinRM on the Domain Controller
C++
389
star
2

Padding-oracle-attack

πŸ”“ Padding oracle attack against PKCS7 πŸ”“
Python
319
star
3

Spring-Boot-Actuator-Exploit

Spring Boot Actuator (jolokia) XXE/RCE
Java
318
star
4

poodle-PoC

🐩 Poodle (Padding Oracle On Downgraded Legacy Encryption) attack CVE-2014-3566 🐩
Python
246
star
5

CVE-2019-0192

RCE on Apache Solr using deserialization of untrusted data via jmx.serviceUrl
Python
209
star
6

ByP-SOP

πŸ΄β€β˜ οΈ Bypass Same Origin Policy with DNS-rebinding to retrieve local server files πŸ΄β€β˜ οΈ
HTML
195
star
7

CVE-2019-5418

CVE-2019-5418 - File Content Disclosure on Ruby on Rails
192
star
8

CVE-2019-19781

CVE-2019-19781 - Remote Code Execution on Citrix ADC Netscaler exploit
Python
155
star
9

CVE-2019-7238

πŸ±β€πŸ’» Poc of CVE-2019-7238 - Nexus Repository Manager 3 Remote Code Execution πŸ±β€πŸ’»
Python
149
star
10

discord-e2e-encryption

πŸ”‘ Tampermonkey script that encrypt and decrypt your messages on Discord πŸ”‘
JavaScript
87
star
11

heartbleed-PoC

πŸ’” Hearbleed exploit to retrieve sensitive information CVE-2014-0160 πŸ’”
Python
78
star
12

BEAST-PoC

πŸ’ͺ Proof Of Concept of the BEAST attack against SSL/TLS CVE-2011-3389 πŸ’ͺ
Python
67
star
13

CVE-2018-17246

CVE-2018-17246 - Kibana LFI < 6.4.3 & 5.6.13
58
star
14

CVE-2019-7609

RCE on Kibana versions before 5.6.15 and 6.6.0 in the Timelion visualizer
52
star
15

CVE-2019-9580

CVE-2019-9580 - StackStorm: exploiting CORS misconfiguration (null origin) to gain RCE
HTML
32
star
16

CVE-2019-3799

CVE-2019-3799 - Spring Cloud Config Server: Directory Traversal < 2.1.2, 2.0.4, 1.4.6
31
star
17

CRIME-poc

πŸ”ͺ CRIME attack PoC : a compression oracle attacks CVE-2012-4929 πŸ”ͺ
Python
27
star
18

astudiaeth

Master CSI
TeX
26
star
19

CVE-2018-16341

CVE-2018-16341 - Nuxeo Remote Code Execution without authentication using Server Side Template Injection
Python
24
star
20

ntlmrelayx-prettyloot

Convert the loot directory of ntlmrelayx into an enum4linux like output
Python
21
star
21

CVE-2018-19276

CVE-2018-19276 - OpenMRS Insecure Object Deserialization RCE
Python
16
star
22

HallOfFame-Root-me.org

πŸ’€ Root-me Hall Of Fame dashboard πŸ’€
Python
14
star
23

DllInjectExec

πŸ’‰ Dll injection for executable file πŸ’‰
C++
13
star
24

Slanger-RCE

RCE in Slanger using deserialization of Ruby objects
Python
11
star
25

CVE-2018-3760

Rails Asset Pipeline Directory Traversal Vulnerability
8
star
26

ropycat

Scripts that allow you to copy/past text into another Windows process to bypass Citrix copy/paste limitation
C#
8
star
27

CVE-2019-9978

CVE-2019-9978 - RCE on a Wordpress plugin: Social Warfare < 3.5.3
8
star
28

discourse-cookie-token-domain

πŸͺ Allow to setup cookie token to authenticate user πŸͺ
Ruby
7
star
29

CVE-2018-11686

CVE-2018-11686 - FlexPaper PHP Publish Service RCE <= 2.3.6
Python
6
star
30

ShareP0wn

ShareP0wn
Python
6
star
31

copper-jekyll-theme

Copper Jekyll theme - simple and useful
CSS
5
star
32

YTC-ID

πŸ“Œ Get the YouTube channel ID ! πŸ“Œ
HTML
4
star
33

DllInjectService

πŸ’‰ Dll ready to be injected into a service πŸ’‰
C++
4
star
34

docker_dashboard

Python
4
star
35

impacket-cme

Python
2
star
36

AChat-Reverse-TCP-Exploit

Tested on AChat 0.150 Beta 7 Windows 7/8/10 x86/x64
Python
2
star
37

Ipsum

Small app for YouTube Network. Get a free submit form for YouTube Channel who want join your network. With AngularJS
JavaScript
1
star
38

Pyrox

For Youtube Network with YouTube API V3 Public
PHP
1
star
39

swindle

Swindle is a project for YouTube Network
PHP
1
star