CVE-2022-31168: Fix authorization check for changing bot roles.

Due to an incorrect authorization check in Zulip Server 5.4 and
earlier, a member of an organization could craft an API call that
grants organization administrator privileges to one of their bots.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2022-07-18 19:00:51 -07:00
committed by Matt Keller
parent 93d2c77225
commit c9f6830ba6
2 changed files with 42 additions and 4 deletions

View File

@@ -8,9 +8,10 @@ from django.core import mail
from django.test import override_settings
from zulip_bots.custom_exceptions import ConfigValidationError
from zerver.actions.bots import do_change_bot_owner
from zerver.actions.realm_settings import do_set_realm_property
from zerver.actions.streams import do_change_stream_permission
from zerver.actions.users import do_change_can_create_users, do_deactivate_user
from zerver.actions.users import do_change_can_create_users, do_change_user_role, do_deactivate_user
from zerver.lib.bot_config import ConfigError, get_bot_config
from zerver.lib.bot_lib import get_bot_handler
from zerver.lib.integrations import EMBEDDED_BOTS, WebhookIntegration
@@ -1169,6 +1170,42 @@ class BotTest(ZulipTestCase, UploadSerializeMixin):
bot = self.get_bot()
self.assertEqual(None, bot["default_sending_stream"])
def test_patch_bot_role(self) -> None:
self.login("desdemona")
email = "default-bot@zulip.com"
user_profile = self.get_bot_user(email)
do_change_user_role(user_profile, UserProfile.ROLE_MEMBER, acting_user=user_profile)
req = dict(role=UserProfile.ROLE_GUEST)
result = self.client_patch(f"/json/users/{self.get_bot_user(email).id}", req)
self.assert_json_success(result)
user_profile = self.get_bot_user(email)
self.assertEqual(user_profile.role, UserProfile.ROLE_GUEST)
# Test for not allowing a non-owner user to make assign a bot an owner role
desdemona = self.example_user("desdemona")
do_change_user_role(desdemona, UserProfile.ROLE_REALM_ADMINISTRATOR, acting_user=None)
req = dict(role=UserProfile.ROLE_REALM_OWNER)
result = self.client_patch(f"/json/users/{user_profile.id}", req)
self.assert_json_error(result, "Must be an organization owner")
# Test for not allowing a non-administrator user to assign a bot an administrator role
shiva = self.example_user("shiva")
self.assertEqual(shiva.role, UserProfile.ROLE_MODERATOR)
self.login_user(shiva)
do_change_bot_owner(user_profile, shiva, acting_user=None)
req = dict(role=UserProfile.ROLE_REALM_ADMINISTRATOR)
result = self.client_patch(f"/json/users/{user_profile.id}", req)
self.assert_json_error(result, "Must be an organization administrator")
def test_patch_bot_to_stream_private_allowed(self) -> None:
self.login("hamlet")
user_profile = self.example_user("hamlet")

View File

@@ -39,6 +39,7 @@ from zerver.lib.exceptions import (
CannotDeactivateLastUserError,
JsonableError,
MissingAuthenticationError,
OrganizationAdministratorRequired,
OrganizationOwnerRequired,
)
from zerver.lib.integrations import EMBEDDED_BOTS
@@ -188,11 +189,11 @@ def update_user_backend(
if role is not None and target.role != role:
# Require that the current user has permissions to
# grant/remove the role in question. access_user_by_id has
# already verified we're an administrator; here we enforce
# that only owners can toggle the is_realm_owner flag.
# grant/remove the role in question.
if UserProfile.ROLE_REALM_OWNER in [role, target.role] and not user_profile.is_realm_owner:
raise OrganizationOwnerRequired()
elif not user_profile.is_realm_admin:
raise OrganizationAdministratorRequired()
if target.role == UserProfile.ROLE_REALM_OWNER and check_last_owner(user_profile):
raise JsonableError(