OpenMeetings is a web conferencing application that can be used for video calls, presentations, and collaborative work. Its official docker image has been downloaded more than 50.000 times, and OpenMeetings can also be deployed as a plugin for applications such as Jira, Confluence, or Drupal. Its widespread adoption and the fact that it might be used for sensitive discussions, meetings, and collaborations make it an attractive target for attackers.
In this article, we will show you an interesting issue we discovered in Apache OpenMeetings, which is caused by an unexpected application state. Attackers can combine this issue with additional code vulnerabilities we found to hijack an OpenMeetings instance and execute commands on the underlying server. All they need is an account that they can create themselves in the default configuration.
OpenMeetings Vulnerabilities - Impact
We discovered the following vulnerabilities in Apache OpenMeetings:
- CVE-2023-28936: Weak Hash Comparison
- CVE-2023-29032: Unrestricted Access via Invitation Hash
- CVE-2023-29246: Null-Byte Injection
These Apache OpenMeetings vulnerabilities allow a self-registered user (enabled by default) to take over an admin account and gain remote code execution:
The account takeover is possible due to the combination of a logical flaw and a weak hash comparison. Attackers can trigger certain actions in an unexpected order to create a room invitation without a room assigned to it. This results in an unrestricted invitation to access any user account. By using a wildcard character, attackers can redeem this invitation themselves and gain admin privileges.
Due to insufficient validation of configurable items, attackers can use the acquired admin privileges to inject a null-byte in one of the binary paths. This can be leveraged to run an arbitrary binary and thus results in remote code execution.
All vulnerabilities were fixed with Apache OpenMeetings 7.1.0.
OpenMeetings Vulnerabilities - Technical Details
In this section, we explain how the room invitation of OpenMeetings works and dive into the technical details of the account takeover and the null-byte injection.
Room Invitation
OpenMeetings allows users to add events to their calendars. When a new event is added, an individual room is created, which can be used during the event:
A user within a room can send an invitation to another user:
Such an invitation is represented as an Invitation
class. When an object of this class is created, the invitee is set, and a random UUID is used as the hash:
openmeetings-web/src/main/java/org/apache/openmeetings/web/common/InvitationForm.java
Also, the Invitation
object is bound to the specific room by calling setRoom
:
openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomInvitationForm.java
Once the user submits the invitation, the invitee receives an email with an invitation link. This link points to /openmeetings/hash
and contains the generated hash in the invitation
query parameter, e.g.:
https://example.com/openmeetings/hash?invitation=52e2f294-cc34-13...
This invitation hash is then used to retrieve the corresponding Invitation
object by calling getByHash
:
openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
To summarize: an invitation is bound to a specific room and user. It can be redeemed with a randomly generated hash.
Weak Hash Comparison (CVE-2023-28936)
The first vulnerability resides within the getByHash
method. This method uses the following named query to retrieve the Invitation
object from the database identified by the user-provided hash:
openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/Invitation.java
The hash value is compared using the LIKE
operator. In contrast to a strict comparison using the equals sign (=
), the LIKE
operator allows wildcards to be used. The default database, H2, requires at least one character before a wildcard. Thus, when, e.g., passing the hash value "5%"
, all Invitation
objects with a hash value beginning with five are returned. This way, an attacker can easily enumerate valid invitation hashes and redeem them (the charset of a UUID is limited to [0-9a-f]
).
Since an invitation is bound to a specific room, this only allows an attacker to access this room on behalf of the invited user. No other interactions with the applications are possible. But let’s see how an invitation is redeemed.
Unrestricted Access via Invitation Hash (CVE-2023-29032)
After the checkHashes
method retrieved an invitation, the method continues by declaring a set called hrights
and tries to determine the room for the invitation:
openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
If the room was successfully identified, the constant Right.ROOM
is added to the hrights
set. At last, setUser
is called, passing the invitee and hrights
as parameters:
openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
Please note that if no room could be identified, the hrights
set is empty when being passed to setUser
. In this case, the rights for the newly set user are not restricted but derived from the user itself:
openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
This means that redeeming an invitation with no room attached to it results in an unrestricted session in the context of the invited user.
Although the usual sequence of actions prevents this, attackers can circumvent this by bringing the application to an unexpected state. At first, an attacker could create an event (1
) and join the associated room (2
):
Now, the attacker deletes the event (3
) while still being present in the room. Although the room is also deleted when its associated event is deleted, the presence of the attacker in the room makes this a zombie room. Next, the attacker creates an invitation for the admin user to this room (4
). This results in an invitation with no room attached to it:
At last, the attacker could leverage the weak hash comparison to redeem the invitation by using a wildcard character (5
). Although an error is raised when redeeming the hash for such an invitation, a valid web session for the invitee with full permissions of this user is created. This web session can be accessed by using the session cookie in the server’s response (6
):
The acquired admin privileges allow attackers to change the configuration of the OpenMeetings instance. This includes adding and removing users and groups, changing room settings, and terminating sessions of connected users. Although this is already quite powerful, we were looking for a way to gain code execution to control not only OpenMeetings but also the underlying server.
Null-Byte Injection (CVE-2023-29246)
OpenMeetings allows an administrator to configure the path for the executables of ImageMagick, FFMPEG, etc. For example, the path for the convert
binary is retrieved by calling getPath
with the configuration key CONFIG_PATH_IMAGEMAGIC
and the name of the binary (convert
):
openmeetings-core/src/main/java/org/apache/openmeetings/core/converter/BaseConverter.java
The getPath
method adds a file separator to the configured path if not already present and appends the name of the binary:
openmeetings-core/src/main/java/org/apache/openmeetings/core/converter/BaseConverter.java
Due to the fact that the configured path does always end with a file separator (e.g., slash) and the executable name is fixed (e.g., convert
), it seems not possible to run executables with different names. Though, when injecting a null-byte in the configured path, every character following the null-byte will be ignored. Although the ProcessBuilder
class used to execute the command carries on the null-byte in the Java realm, the implementation of the actual execution of the command is OS-specific and implemented in native C. While in Java the length of a string is stored separately allowing it to contain null-bytes, in C a single null-byte designates the end of the string effectively ignoring every character that was appended after the null-byte.
This allows an attacker with admin privileges to gain code execution by changing the ImageMagic path to "/bin/sh%00x"
(a single character after the null-byte is required to prevent it from being ignored in the first place). When now uploading a fake image containing a valid image header followed by arbitrary shell commands, the conversion spawns /bin/sh
with the first argument being the fake image, effectively executing every command in it. [Update: The possibility of injecting a null-byte in the binary path provided to ProcessBuilder
has been fixed in OpenJDK by now. The issue is tracked as CVE-2023-21938.]
In combination with the account takeover, this vulnerability allows a self-registered attacker to gain remote code execution on the underlying server.
Patch
In this section, we briefly look at the applied patches to fix the vulnerabilities. All vulnerabilities were fixed in OpenMeetings version 7.1.0.
Issue 1 - Weak Hash Comparison (CVE-2023-28936)
Interestingly, the weak hash comparison vulnerability was not fixed by changing the underlying SQL statement, but by adding an additional check whether the retrieved hash value completely matches the provided value:
openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/InvitationDao.java
This prevents an attacker from redeeming an invitation hash using a wildcard character.
Issue 2 - Unrestricted Access via Invitation Hash (CVE-2023-29032)
The second issue was mitigated by adjusting the setUser
method. The applied permissions are not derived from the given user anymore if the rights
set is empty:
openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
This prevents an invitation without a room assigned to it resulting in unrestricted access to the invited user.
Issue 3 - Null-Byte Injection (CVE-2023-29246)
At last, the null-byte injection was fixed by validating the configured path via the Path.of
method:
openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigForm.java
If the configured path contains a null-byte, Path.of
throws an InvalidPathException
and the validation fails. This prevents the possible truncation of the applied file separator and binary name.
Timeline
Date | Action |
2023-03-20 | We report all issues to maintainers. |
2023-03-20 | Initial response from maintainers; findings will be checked. |
2023-03-28 | Maintainers confirm issue 1. (Weak Hash Comparison, CVE-2023-28936) |
2023-03-30 | Maintainers confirm issue 2. (Unrestricted Access via Invitation Hash, CVE-2023-29032) |
2023-04-04 | Maintainers confirm issue 3. (Null-Byte Injection, CVE-2023-29246) |
2023-05-09 | Version 7.1.0 is released, which fixes all three issues. |
OpenMeetings Vulnerabilities - Summary
In this article, we looked at an interesting issue in the web conferencing application Apache OpenMeetings, which was caused by an unexpected application state. While developers typically anticipate and account for expected states during the design and development of an application, unexpected states can arise due to unintentional misusage or intentionally triggered attacks. As we have seen, these unexpected states can inadvertently introduce security vulnerabilities that attackers can exploit.
By following Clean Code principles, developers can reduce the risk of introducing these code vulnerabilities, ensuring that the application behaves as expected under various conditions. These principles promote security, maintainability, and reliability, enabling developers to anticipate and handle unexpected states more effectively.
We additionally pointed out the importance of this by demonstrating how attackers could combine the issue with a weak hash comparison to take over any user account. Furthermore, we looked at a null-byte injection caused by insufficient validation of user input, which results in remote code execution. At last, we looked at the applied patches and determined how the vulnerabilities were addressed.
Finally, we would like to thank the maintainers of Apache OpenMeetings for quickly responding to our report and providing a patch for all reported issues.