v8-archive icon indicating copy to clipboard operation
v8-archive copied to clipboard

Users are able to elevate their own roles

Open kosicielPL opened this issue 4 years ago • 7 comments

Accidentally it turned out, that as a low-privileged user I am able to elevate my own role to admin.

  • Directus 8.8.0 Installed with one-click installation on DigitalOcean droplet along with:
  • Ubuntu 18.04
  • Apache 2.4
  • MySQL 5.7
  • PHP 7.2

Steps to reproduce:

1. As an admin user, I create a new role (called "Test") with default permissions (as below)

directus_step_01

2. I want active users of "Test" role to be able to modify their own user profiles in regards to first_name and last_name only:

directus_step_02

directus_step_03

Of course, "Test" users permissions in regards to updating user profiles are set to "mine".

However, I also don't want "Test" users to be able to modify any of given roles and permissions, so I'm disabling their access to related collections:

directus_step_03 1

3. As permissions for the new role are set, I'm creating new "Test User" with role set to "Test"

directus_step_04

4. Now I'm signing myself in as a newly created user and I'm trying to edit my own user profile:

directus_step_05

For now everything looks like expected. I don't have permissions to edit my own role. I only have access to First Name and Last Name Fields (and, for some reason, for Timezone as well):

directus_step_05

5. BUT, besides GUI, there is also a RESTful API, that I can use. So let's try to sign in through it (as a test user of course).

I'm now sending a POST request for //auth/authenticate with payload of email and password. In response get my token and user data:

{ "data": { "token": "<token>", "user": { "id": "4", "status": "active", "role": "4", "first_name": "Test", "last_name": "User", "email": "[email protected]", "timezone": "Europe/Warsaw", "locale": "en-US", "locale_options": null, "avatar": null, "company": null, "title": null, "external_id": "<externalId>", "theme": "auto", "2fa_secret": null, "password_reset_token": null } }, "public": true }

Note that my role is set to 4 which is and id for my "Test" role.

6. Now let's take my token and try to elevate my role through API.

I'm now sending a PATCH request for [host]/[project]/users/4 along with the following payload:

{ "role": 1 }

Where 1 corresponds to built-in "Admin" role.

I'm attaching my token in querystring, so the complete request URL looks like this:

[host]/[project]/users/4?access_token=[access token taken from previous request]

Let's send this request to the server... * puff * and now let's take a look at the response:

{ "data": { "id": 4, "status": "active", "role": 1, "first_name": "Test", "last_name": "User", "email": "[email protected]", "token": "<token>", "timezone": "Europe/Warsaw", "locale": "en-US", "locale_options": null, "avatar": null, "company": null, "title": null, "email_notifications": true, "last_access_on": "2020-07-30 09:38:44", "last_page": "/zpruszkowa/users/4", "external_id": "<externalId>", "theme": "auto", "2fa_secret": null, "password_reset_token": null } }

As we can see, my new role is 1 which means, that I just elevated my permissions to Admin.

7. Now let's go back to the Directus GUI and...

directus_step_06

Tadamm!

My test user is now an admin.

I'm pretty sure that this isn't supposed to work this way. I want my users to be able to change their own personal data (like e-mail address) but I am not sure if I want to grant them a privilige to change their own role to admin.

kosicielPL avatar Jul 30 '20 10:07 kosicielPL

If you have acknowledged this bug, please, take into consideration also following related issue: -> as a an authenticated user with defaults permissions, I have access to all revisions and activities through API. After lowering level of permissions for Revisions and Activities application's GUI throws errors and eventually breaks. Granting access to all revisions means basically allowing access to all the data in the app.

kosicielPL avatar Jul 30 '20 13:07 kosicielPL

It seems the API request may be bypassing the validation of the user-role interface if you set all the required permissions. Did you try clicking on the all button next to the status to turn on or off the fields?

By default when you grant permission, all fields are readable and writable for the status you select.

In the meantime, if that does not work, I would suggest a hook to look for the incoming data object and adjust using the following hooks: item.create:before and item.update:before.

It would be cool to have roles non-writable by default in future releases.

For revisions and activity, what were the permission settings? You don't want the API user to see revisions or just the delta and data fields?

philleepflorence avatar Jul 30 '20 20:07 philleepflorence

We found the same revision bug as @kosicielPL. If a user has permission to read revisions, he will be able to inspect data from not only restricted collections, but also any system tables, such as users. You can then get access tokens and passwords set by administrators when creating new users.

Steps to reproduce from a clean installation:

  • Create a new role
  • Create a new user ("attacker"), assign him the previously created role

For the default admin user :

  • Change any field of the admin user
  • As the attacker user, access the revision history of the admin user http://localhost:8080/_/users/1/revisions

For any other user :

  • Create the user, set a default password
  • As the attacker user, access the revision history of the user http://localhost:8080/_/users/the_user_id/revisions
  • The default password is accessible in the revision history
  • Change any field of the user
  • The user token is now available in the revision history

(For some reason, the token only appears in the revision history if a modification has been made to the user, even though the token is already generated)

Jeremy-Gaillard avatar Jul 31 '20 15:07 Jeremy-Gaillard

@Jeremy-Gaillard in the meantime, you can prevent a non-trusted user from reading certain fields in the activity collection.

They can see the activity not just all of it. See image for permissions:

directus-api-roles-activity

By setting the data and delta fields off, that user will see this:

    "data": [
        {
            "id": 226,
            "activity": 238,
            "collection": "app_collections_configuration",
            "item": "11",
            "parent_collection": null,
            "parent_item": null,
            "parent_changed": false
        },
        {
            "id": 227,
            "activity": 239,
            "collection": "app_collections_configuration",
            "item": "12",
            "parent_collection": null,
            "parent_item": null,
            "parent_changed": false
        }
    ]
}

The permissions of Directus are very granular and will only improve in the next version(s).

philleepflorence avatar Jul 31 '20 18:07 philleepflorence

@kosicielPL I was able to get the role blocked from updates by any user in a non-admin role.

You can accomplish that by setting granular permissions on the user collection as follows:

directus-user-permissions-role

Then if you run this PATCH and try to update the role:

{{api}}/app/users/2?access_token={{access_token}}

You should get this response:

{
    "error": {
        "code": 305,
        "message": "Write access to \"role\" field in \"directus_users\" collection was denied",
        "class": "Directus\\Permissions\\Exception\\ForbiddenFieldWriteException",
        "file": "/Users/philleepflorence/Sites/Directus/suite/src/core/Directus/Permissions/Acl.php",
        "line": 1232
    }
}

philleepflorence avatar Jul 31 '20 18:07 philleepflorence

@Jeremy-Gaillard in the meantime, you can prevent a non-trusted user from reading certain fields in the activity collection.

They can see the activity not just all of it. See image for permissions:

directus-api-roles-activity

By setting the data and delta fields off, that user will see this:

    "data": [
        {
            "id": 226,
            "activity": 238,
            "collection": "app_collections_configuration",
            "item": "11",
            "parent_collection": null,
            "parent_item": null,
            "parent_changed": false
        },
        {
            "id": 227,
            "activity": 239,
            "collection": "app_collections_configuration",
            "item": "12",
            "parent_collection": null,
            "parent_item": null,
            "parent_changed": false
        }
    ]
}

The permissions of Directus are very granular and will only improve in the next version(s).

@philleepflorence - this works for REST API, but then, when you try to sign in to GUI as an user with limited permissions, the app throws errors and eventually prevents you from signing in.

kosicielPL avatar Aug 02 '20 16:08 kosicielPL

its been 2 years. Does anyone have solved this?

officialgithub avatar Jun 16 '22 14:06 officialgithub