Problem/Motivation
There's a viable Gadget Chain in \GuzzleHttp\Cookie\FileCookieJar
which can be abused to achieve an arbitrary File Write if there's a PHP Object Injection vulnerability in a Drupal application. It cannot be exploited by itself.
(https://portswigger.net/web-security/deserialization#what-is-insecure-de... for general context).
Details of this Gadget Chain have been public for a long time - it looks like it was originally added to PHPGGC around 8 years ago:
https://github.com/ambionics/phpggc/tree/master/gadgetchains/Guzzle/FW/1
I filed an issue to make sure that the Guzzle maintainers are aware but there has been no activity:
https://github.com/guzzle/guzzle/issues/3271
Steps to reproduce
To emphasise again, in order for this to be exploitable within Drupal there first needs to be a PHP Object Injection vulnerability.
https://www.drupal.org/project/gadget_chain_poc/ →
is a development / security research tool to simulate such a vulnerability.
With that module installed, the guzzle/fw1 gadget chain can be used to write a file to the server (somewhere the PHP user has write permission) which could be used as part of an attack.
I'll leave the full details as an exercise for the reader initially.
Proposed resolution
It doesn't look like the FileCookieJar class is ever used in Drupal core, and a quick search suggests it only appears in contrib as part of the vendored library where that's been committed to projects.
We could remove this class from Drupal's autoloader, and that would render it inert in terms of being exploitable in a PHP Object Injection scenario.
I asked about approaches to doing this in drupal slack and received several interesting suggestions. I'll try to summarise them briefly:
joachim: Have a look at the patch for the composer cache ID thingy - @alexpott worked out how to do it in that with a composer plugin:
https://www.drupal.org/project/drupal/issues/3509069
📌
Use a better container cache key
Active
catch: you could add class_alias() very early in a middleware or similar, to point to either your own version, or an empty class.
longwave: look at
https://www.drupal.org/node/3509577 →
as well which messes with the autoloader a bit.. but to block something you might need ... [to throw an exception. Or] you could maybe use reflection to alter Composer's ClassLoader::$missingClasses property to fake that the class doesn't exist, but iirc getting hold of the object to do that is tricky.. or maybe i'm thinking of something else actually
berdir: instead of preventing loading, why don't you ensure the file doesn't exist? similar to core had (has?) workarounds in place to delete certain dev files if they are in the docroot folder with a composer plugin during composer install? ... hooking directly into composer install, you can set that up in composer.json or with a registered plugin ... which is also used to add the scaffold files like robots.txt
chx: a very simple way to do this.. [referring to \Composer\Autoload\ClassLoader::findFile] create an empty file and set apcu to it. it will load it instead of the real class and unlike with class_alias it will not exist after loading it
catch: If we wanted this in core, we could add the file to core-vendor-hardening specifically.
Remaining tasks
* MR
* Tests
* Review / commit etc..
* Release note snippet
User interface changes
n/a
Introduced terminology
n/a
API changes
The class would no longer be available via the autoloader.
Any contrib / custom code that needs to use it would need to load the class explicitly.
Data model changes
n/a
Release notes snippet
This would warrant a CR - that's a todo.