Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Date: Fri, 25 Feb 2022 12:32:37 +0100
From: Carlos López <clopez@...e.de>
To: oss-security@...ts.openwall.com
Subject: CVE-2022-24986: KCron: Insecure temporary file handling

Hello list,

Find below our report for CVE-2022-24986: Insecure temporary file 
handling in KDE KCron <= 21.12.2.

# 0. Overview

KCron [0] is a graphical frontend to the classical cron utility for the 
KDE desktop environment. In order to perform elevated tasks, such as 
modifying the system-wide crontab at `/etc/crontab`, a privileged helper 
program is used. Communication (via dbus) and authorization against the 
helper (via Polkit) is abstracted away with the KDE Kauth framework.

# 1. Analysis

The client (unprivileged) code is mainly contained in 
`src/crontablib/ctcron.cpp:CTCron::save()` and 
`src/crontablib/ctSystemCron:CTSystemCron::CTSystemCron()`. The client 
side has two different modes of operation:

- Saving content of the user-specific crontab. This is done via the 
`/usr/bin/crontab` setuid-root binary.
- Saving content of the system-wide crontab. This is done via invocation 
of the privileged privileged helper program on D-Bus 
(`src/helper/kcronhelper.cpp`).

In both cases a temporary file is created with the new contents and it 
is passed on to the respective mechanism. These temporary files are 
created under /tmp using unpredictable file names of the format 
`systemsettings.XXXXXX` with mode `0644`, and are thus world-readable

The first mode of operation is affected by an information leak, and the 
second one by a potential privilege escalation.

## 1.1. Information leak due to improper file permissions

When temporary files are created, the mode passed to the open call is 
`0666`, which causes the file to be world-readable.

```
openat(AT_FDCWD, "/tmp/systemsettings.jhcCtT", 
O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 15
```

Since created temporary files are world-readable, other users in the 
system might gain knowledge about other users' crontabs. The severity of 
this leak depends on the actual contents of the user specific crontab. 
The system wide crontab is usually installed as world-readable, so the 
leak does not apply there by default (but could still be an issue if 
`/etc/crontab` is hardened, and thus not meant to be read). Users could 
place passwords in their crontabs via environment variables, or the 
contents could be hints for further attack vectors.

## 1.2. Privilege escalation due to filename reuse

The name for the temporary file holding user changes is obtained once 
and reused each time the user saves crontab content. This means that, 
after the first time the temporary file is written, other local users in 
the system have knowledge of the used filename, and can stage attacks if 
the user should reuse the same instance of the tool.

```
CTCron::CTCron(...)
{
     ...
     QTemporaryFile tmp;
     tmp.open();
     d->tmpFileName = tmp.fileName(); // [A]
     ...
}

CTSaveStatus CTCron::save()
{
     bool saveStatus = saveToFile(d->tmpFileName); // [B]
     ...
     QFile::remove(d->tmpFileName); // [C]
     ...
}

bool CTCron::saveToFile(const QString &fileName)
{
     QFile file(fileName);
     if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
         ...
     ...
}
```

The file name is obtained once in [A], when the CTCron object is 
instantiated, and reused in [B] every time the user saves their changes. 
The file is then removed explicitly in [C].

Temporary files are opened without passing the `O_EXCL` or `O_NOFOLLOW` 
flags, which can be exploited in two ways.

First, if `/proc/sys/fs/protected_symlinks` is disabled (see the manual 
page for proc(5)), the absence of `O_NOFOLLOW` means that the 
application will happily follow any symlink. Note that this protection 
is disabled by default for the vanilla kernel, but it is enabled by most 
distributions.

This can be exploited as follows:

- An attacker creates a world-writable directory under its own control 
and prepares a symlink attack into this directory:
   1. `mkdir -m 777 /tmp/evil-directory`
   2. `ln -s /tmp/evil-directory/evil-file /tmp/systemsettings.abcdef`
- When KCron re-creates the temporary file, the call will succeed, 
because the target file does not yet exist.
- After the file has been created in `/tmp/evil-directory`, the attacker 
can remove the `/tmp/evil-directory/evil-file`, as they have write 
permissions in the directory. After that, a new file under the 
attacker's control is created in its stead that contains malicous data. 
This is the race condition that needs to be won.
- Once either the KAuth helper or the crontab binary is invoked, the 
malicious data is placed as the new crontab content, allowing arbitrary 
code execution as the victim user (or as an arbitrary user in the case 
of the system crontab).

Second, if `/proc/sys/fs/protected_regular` is disabled, the absence of 
`O_EXCL` means that the call to `openat()` will not fail if the file 
already exists and is owned by a different user. In this case, the 
attacker does not even need to set up a symlink, as they can simply 
create a file with the appropiate name and world-writeable permissions. 
Once KCron is done writing to the temporary file, but before it is 
copied to its destination, the attacker can modify its contents, as the 
file is still under their control.

This all stems from a misuse of the `QTemporaryFile` object of the Qt 
framework. The abstractions this class provides make its use fairly 
non-obvious, as we already noted in the past [1].

# 2. Other minor issues

During our analysis we noticed other minor issues that do not pose an 
immediate security threat, but that we communicated to the maintainer 
nonetheless. These have since been addressed through upstream patches.

  - The helper's error handling is incomplete, only warnings will be 
logged, but neither is the operation aborted on errors nor are errors 
propagated back to the caller. No proper polkit authentication dialog 
with the active source/target arguments is displayed.
  - The helper's functionality is not limited to saving a crontab file, 
as it accepts source and destination arguments (i.e. an arbitrary file 
move scheme). If the helper were improperly parametrized, it could be 
used for arbitrary local root exploits. In the past we already 
identified issues with overly generic D-Bus file system APIs which can 
lead to security bugs [2].
  - There is an additional DoS vector due to file name reuse, as other 
users might place files at the expected temporary locations. This breaks 
the application, as it will not be able to create said temporary files. 
Of course, this is not an issue for a privileged user, which can remove 
the malicious files, and the option to update the crontab manually via 
CLI is still available, but it would defeat the purpose of the GUI program.

The referenced upstream patch to fix the issues [3] still contains a 
problem. With the patch the source (temporary) file under user control 
is `chmod()`ed by the helper program [4] to give it the right 
permissions for moving it to `/etc/crontab`. Our suggestion is to to 
overwrite the destination file instead. An upstream merge request is 
currently in the works to address this [5].

# 3. Timeline

2022-01-26 - Issues reported to upstream
2022-01-31 - Upstream starts working on fixes
2022-02-02 - Embargo date set to 2022-02-16
2022-02-04 - Patch proposal from maintainer
2022-02-15 - Patch pushed to upstream repository
2022-02-16 - KDE report goes public [6]

# 4. References

[0] https://invent.kde.org/system/kcron
[1] https://www.openwall.com/lists/oss-security/2018/04/24/1
[2] https://www.openwall.com/lists/oss-security/2019/07/09/3
[3] 
https://invent.kde.org/system/kcron/-/commit/ef4266e3d5ea741c4d4f442a2cb12a317d7502a1
[4] 
https://invent.kde.org/system/kcron/-/commit/ef4266e3d5ea741c4d4f442a2cb12a317d7502a1#87f74e7efe41bc6f7cbe1f834b88b2e31889c804_47_47
[5] https://invent.kde.org/system/kcron/-/merge_requests/14
[6] https://kde.org/info/security/advisory-20220216-1.txt

Best regards,

Carlos

-- 
Carlos López
Jr. Security Engineer
SUSE Software Solutions

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.