403Webshell
Server IP : 35.80.110.71  /  Your IP : 216.73.216.221
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux ip-172-31-21-44 6.17.0-1019-aws #19~24.04.1-Ubuntu SMP Tue Jun 23 18:53:06 UTC 2026 x86_64
User : ubuntu ( 1000)
PHP Version : 8.3.31
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/client-portal-laravel/releases/20260626120707/app/Rules/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/client-portal-laravel/releases/20260626120707/app/Rules/ValidFileContent.php
<?php

declare(strict_types=1);

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Http\UploadedFile;

/**
 * Validates that a file's content (magic bytes) matches its declared MIME type.
 *
 * This prevents attacks where a malicious file (e.g., PHP script) is renamed
 * with a safe extension (e.g., .pdf) to bypass MIME type checks.
 */
class ValidFileContent implements ValidationRule
{
    /**
     * Magic byte signatures for supported file types.
     *
     * @var array<string, array<string>>
     */
    private const SIGNATURES = [
        'application/pdf' => ['%PDF'],
        'image/png' => ["\x89PNG"],
        'image/jpeg' => ["\xFF\xD8\xFF"],
        'image/gif' => ['GIF87a', 'GIF89a'],
    ];

    /**
     * Map file extensions to expected MIME types for signature lookup.
     *
     * @var array<string, string>
     */
    private const EXTENSION_MAP = [
        'pdf' => 'application/pdf',
        'png' => 'image/png',
        'jpg' => 'image/jpeg',
        'jpeg' => 'image/jpeg',
        'gif' => 'image/gif',
    ];

    /**
     * Run the validation rule.
     *
     * Uses the client-declared MIME type (from the upload) to determine which
     * magic bytes to expect. This catches spoofed files where a malicious file
     * is renamed with a safe extension to bypass MIME type checks.
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (! $value instanceof UploadedFile) {
            return;
        }

        // Use client-declared MIME type to catch spoofing (where the attacker
        // claims a file is PDF/image but the content is actually malicious)
        $mimeType = $this->resolveExpectedMimeType($value);

        // Only validate file types we have signatures for
        if (! isset(self::SIGNATURES[$mimeType])) {
            return;
        }

        $path = $value->getRealPath();
        if (! $path || ! is_readable($path)) {
            $fail('The :attribute could not be read for content validation.');

            return;
        }

        // Read the first 8 bytes for magic byte comparison
        $handle = $this->openFile($path);
        if (! $handle) {
            $fail('The :attribute could not be read for content validation.');

            return;
        }

        $header = fread($handle, 8);
        fclose($handle);

        if ($header === false || $header === '') {
            $fail('The :attribute appears to be empty.');

            return;
        }

        $signatures = self::SIGNATURES[$mimeType];
        $matches = false;

        foreach ($signatures as $signature) {
            if (str_starts_with($header, $signature)) {
                $matches = true;
                break;
            }
        }

        if (! $matches) {
            $fail('The :attribute content does not match its file type. The file may be corrupted or spoofed.');
        }
    }

    /**
     * Resolve the expected MIME type from the client-declared type or extension.
     *
     * Prefers the client MIME type, falls back to extension mapping.
     */
    private function resolveExpectedMimeType(UploadedFile $file): ?string
    {
        $clientMime = $file->getClientMimeType();
        if ($clientMime && isset(self::SIGNATURES[$clientMime])) {
            return $clientMime;
        }

        // Fall back to extension-based lookup
        $extension = strtolower($file->getClientOriginalExtension());
        if (isset(self::EXTENSION_MAP[$extension])) {
            return self::EXTENSION_MAP[$extension];
        }

        return null;
    }

    /**
     * Open a file for reading. Extracted for testability.
     *
     * @return resource|false
     */
    protected function openFile(string $path)
    {
        return fopen($path, 'rb');
    }
}

Youez - 2016 - github.com/yon3zu
LinuXploit