PHP contains an interesting but rarely used feature called Phar, which stands for PHp ARchive, that allows developers to package entire applications as a single executable file. It also boasts some additional security benefits by signing archives with a digital signature, disallowing the modification of the archives on production machines.
According to the official PHP documentation:
Phar can compress individual files or an entire archive using gzip compression or bzip2 compression and can verify archive integrity automatically through the use of MD5, SHA-1, SHA-256 or SHA-512 signatures….
… The Phar extension takes security into account, and disables write access to executable phar archives by default, requiring system-level disabling of the phar.readonly php.ini setting in order to create or modify phar archives. Normal tar and zip archives without an executable stub can always be created or modified using the PharData class.
While the above is technically true, we at Sucuri have found that these restrictions are easily bypassed by a determined attacker and cannot be relied on to protect the integrity of an archive. As such, it is advised that additional measures be taken to confirm the validity of any Phar archives before using in a production setting.
How Phar Disables Writes
The documentation states that archives can only be written if explicitly allowed in php.ini – but this protection is only enforced in code. What this means is that the Phar classes included with PHP will not allow the writing of new files or the modification of existing ones when attempted via the Phar class methods provided for this purpose. Any modification via external resources is not – and cannot – be enforced in this manner, leaving these files open to alteration by any user with write access to the file.
Having write access will most certainly allow the file to be changed, but that would inevitably alter the file’s signature. This should cause any attempted execution to fail, right?
How Phar Checks Signatures
To give more background on how Phar archives are constructed, they are PHP files that contain a mixture of code and other binary data.
First, comes the stub – a section of code that handles the extraction of resources. A binary manifest comes next, which allows the interpreter to understand the file structure of the embedded contents that follow. The signature makes up the last section of the file.
The signature format used by Phar archives is quite simple. On creation, a signature is generated. The file contains only the stub, manifest, and contents. This signature, along with a 4-byte signature flag, tells PHP what signature type was used. Last, a magic 4-byte constant marks a file as having a signature. All are then appended to the final file.
When PHP later reads the archive, it can determine the signature and type by reading the end of the archive. This type of formatting is ultimately where the problem arises.
Injecting Code in the Signature
To test this, we started out with a simple “Hello World” Phar file and signed it using OpenSSL. Executing the resulting .phar through the command line displayed our simple message as long as the archive existed alongside its public key file. Without the public key file, the interpreter failed with the PharException.
Likewise, any attempt to alter the stub section of the archive would also cause the signature to fail, but code injected before the stub would execute before this failure occurred. This is not a good thing, but the question then arose if it was possible to not only inject code – but to do so silently.
It turned out to be quite simple.
Since the signature is hard-coded into the file, we just removed the old signature section completely. After adding our payload (a simple “Hello Evil World”), we calculated a new MD5 signature, appended it to the malicious copy, and replaced our once benign “Hello World” with our infected version.
The resulting file executed our “Hello Evil World” payload then happily said “Hello World” as if nothing was wrong, and PHP was none the wiser. The public key file was ignored completely.
What This Means for Developers
Developers should be aware that the security mechanisms built into the Phar format are not a complete solution, and cannot prevent the modification of the code within.
The premise of Phar is to allow multiple PHP files to be stored within a single container, and that is exactly how it should be treated – as a collection of files.
What the Phar file format won’t do is prevent others from:
- reading your code
- modifying your code
- including your code elsewhere
This doesn’t mean that you shouldn’t ever use Phar for anything ever, but developers and system administrators need to be aware of the limitations of the format.