CVE-2022-31168 (published 2022-07-22T13:15Z)

Zulip is an open source team chat tool. 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. The vulnerability is fixed in Zulip Server 5.5. Members who don’t own any bots, and lack permission to create them, can’t exploit the vulnerability. As a workaround for the vulnerability, an organization administrator can restrict the `Who can create bots` permission to administrators only, and change the ownership of existing bots.

CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-285
cwe_name: Improper Authorization
description: The product does not perform or incorrectly performs an authorization check when an actor attempts to access a resource or perform an action.
extended_description: 
            Assuming a user with a given identity, authorization is the process of determining whether that user can access a given resource, based on the user's privileges and any permissions or other access-control specifications that apply to the resource.
            When access control checks are not applied consistently - or not at all - users are able to access data or perform actions that they should not be allowed to perform. This can lead to a wide range of problems, including information exposures, denial of service, and arbitrary code execution.
         
         
cwe_id: CWE-863
cwe_name: Incorrect Authorization
description: The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
extended_description: 
            Assuming a user with a given identity, authorization is the process of determining whether that user can access a given resource, based on the user's privileges and any permissions or other access-control specifications that apply to the resource.
            When access control checks are incorrectly applied, users are able to access data or perform actions that they should not be allowed to perform. This can lead to a wide range of problems, including information exposures, denial of service, and arbitrary code execution.
         
         

Fix information:
repo_url: https://github.com/zulip/zulip
commit_details: repo_url: https://github.com/zulip/zulip
author: Anders Kaseorg
author_date: 2022-07-18 19:00:51-07:00
msg: 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>
repository: repo_url: https://github.com/zulip/zulip
repo_name: zulip/zulip
description: Zulip server and web application. Open-source team chat that helps teams stay productive and focused.
repo_language: Python
owner: zulip
file_changes: filename: test_bots.py
change_type: ModificationType.MODIFY
diff: @@ -8,6 +8,7 @@ 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_change_user_role, do_deactivate_user
@@ -1190,9 +1191,26 @@ class BotTest(ZulipTestCase, UploadSerializeMixin):
 
         req = dict(role=UserProfile.ROLE_REALM_OWNER)
 
-        result = self.client_patch(f"/json/bots/{self.get_bot_user(email).id}", req)
+        result = self.client_patch(f"/json/users/{user_profile.id}", req)
+        self.assert_json_error(result, "Must be an organization owner")
+
+        result = self.client_patch(f"/json/bots/{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")
+
+        result = self.client_patch(f"/json/bots/{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")

programming_language: Python
filename: users.py
change_type: ModificationType.MODIFY
diff: @@ -40,6 +40,7 @@ from zerver.lib.exceptions import (
     CannotDeactivateLastUserError,
     JsonableError,
     MissingAuthenticationError,
+    OrganizationAdministratorRequired,
     OrganizationOwnerRequired,
     RateLimited,
 )
@@ -191,13 +192,13 @@ 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.
         #
         # Logic replicated in patch_bot_backend.
         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(target):
             raise JsonableError(
@@ -331,6 +332,8 @@ def patch_bot_backend(
         # Logic duplicated from update_user_backend.
         if UserProfile.ROLE_REALM_OWNER in [role, bot.role] and not user_profile.is_realm_owner:
             raise OrganizationOwnerRequired()
+        elif not user_profile.is_realm_admin:
+            raise OrganizationAdministratorRequired()
 
         do_change_user_role(bot, role, acting_user=user_profile)
 

programming_language: Python