Skip to content

Drupal AT1 #210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 27, 2025
Merged

Drupal AT1 #210

merged 4 commits into from
Mar 27, 2025

Conversation

mcdruid
Copy link
Contributor

@mcdruid mcdruid commented Dec 4, 2024

This introduces a class of chain; AccountTakeover.

This Drupal gadget chain is sort of SQLi, but instead of free-form SQL it works with structured data which is passed to Drupal's DB API.

This PoC updates the email of the main admin user, after which an attacker could request a password reset.

Hence "account takeover".

@nollium nollium added the gadget chain This issue could yield a new gadget chain. label Feb 26, 2025
@nollium
Copy link
Collaborator

nollium commented Mar 20, 2025

Thank you for this amazing contribution. I've taken a quick look at this gadget chain. From what I understand, arbitrary operations on the database can be performed using this technique.

Currently, the exploit renames the first user to "admin" and changes its email to an attacker-controlled one so the attacker can reset their password via the mail process.

To avoid causing Denial-of-Service issues, it would be preferable to add a new account with admin privileges. This would also make it more exploitable in cases where Drupal cannot send mail to the attacker's address, which can happen for many reasons.

Is there any reason why this wouldn't be possible or desirable?

@mcdruid
Copy link
Contributor Author

mcdruid commented Mar 20, 2025

From a pentester's point of view I'm assuming that we just want to "Proof of Concept" the attack, which updating the user email achieves.

...but yes, an approach like that makes some sense; adding a new user would arguably be less disruptive.

However there are at least a couple of potential hurdles which might make this harder to achieve than we might think.

  • It's not necessarily obvious what "admin privileges" means in a Drupal application as it's a flexible framework. There is a default "administrator" role which shouldn't be too hard to grant to the implanted user, but it may or may not work as expected on a given site.
  • In order to be able to authenticate as the implanted user (without relying on the email password reset workflow) we'd need to supply a password hash in the correct format. It's not hard to include one hard-coded hash in the gadget chain, but if we wanted that to be flexible we'd either have to include a hashing implementation, or expect the user to provide their own hash.
  • Depending on how the site is set up each user entity may require several other rows in the database on top of the basic entries in the users / users_field_data tables. So injecting a functional new user entity with just SQL may be non-trivial in some cases.

So although it might not be too hard to achieve implanting a new admin user in a vanilla install of one version of Drupal, making that work reliably across different releases and the many different ways that actual Drupal sites are set up with additional contributed modules etc.. may be quite a challenge.

Just updating user number 1's email address in the db - to prove that we can - is almost certainly quite a bit simpler.

@mcdruid
Copy link
Contributor Author

mcdruid commented Mar 20, 2025

In fact, even inserting rows for a new user into just those two basic tables - users / users_field_data - could be tricky with this technique; unless I'm missing something you'd need to:

  • insert a row into users (which has an auto_increment key, uid.
  • do a matching insert into users_field_data with the correct uid foreign key from the first insert (perhaps via a subquery like SELECT MAX(uid) FROM users)

That may mean at least two exploit requests with different payloads?

On a busy site it may not be practical to derive / guess the uid you created in the first insert.

Some dbs may allow you to make up your own uid - you could go for an arbitrary high number. If we're trying to avoid making a mess of the site though, not sure that's a great idea (could harm replication etc..) Or perhaps if you make up your own uuid in the first insert, your subquery in the second insert could use that..

It's probably possible, but I don't think I'm going to try and put it together.

@nollium nollium merged commit 313b67f into ambionics:master Mar 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gadget chain This issue could yield a new gadget chain.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants