Take Your Media Anywhere With Emby
After the last two articles, I’ve said to myself: Why always go after Jellyfin
? Why not go back to where it all began, the fork from Emby
. I wanted to know just how much DNA both projects share these days and was curious if my knowledge of the former proved to be useful.
Ultimately, it was useful, because I’ve found three vulnerabilities in version 4.7.14.0
:
- An unauthenticated endpoint for retrieving meta data of potentially every item in the library (full paths, identifiers etc).
- An unauthenticated endpoint for retrieving every image of the library.
- A
Cross-site sripting
(XSS
) vulnerability in the admin dashboard that leads to remote code execution (RCE
). Can be triggered by a low-privileged user.
The issues themselves don’t merit a full-blown article, which is why I’m simply including my initial short report to the vendor almost verbatim. It contains a fully commented exploit for the XSS
issue.
Update April 21, 2024: Apparently the problem with the ImageService
has been known for four years!
I Want to Write Exploits, Not Emails
Speaking about the vendor:
Unfortunately, they were (and still are) very unresponsive. I’ve first contacted them privately on the 12th of December 2023 with the full details. After following up two times, I’ve received a one-liner that didn’t answer any of my questions.
Look, I’m not suddenly part of the team because I’ve informed them of those vulnerabilities. I’m not asking for briefings about every internal detail. I simply wanted a rough timeline for coordinating the release of this article so that no information is available before any of those 23.500 reachable instances 1 had a chance to get patched.
My last attempt at getting any kind of feedback was opening an issue in their support GitHub repository.
Something to keep in mind with all of this: Emby
is not an open source project run by volunteers! They offer paid subscriptions, which incidentally is one of the reasons why the Jellyfin
team decided to fork.
All in all, not a good look. Especially after last year’s incident. 2
Now for the interesting parts: My initial report followed by some testing I did with the newest available version.
Report
SuggestionsService
The SuggestionsService
endpoint can be used without authentication. Only a user id is needed. Because those start at 1, it’s trivial to guess a correct one.
https://<hostname:port>/emby/Users/1/Suggestions
Without any additional filters via query parameters, it seems that meta data of every item in the library gets returned. This data contains sensitive information like paths and names. An attacker could use the ids to further leak data from other endpoints.
ImageService
Most of the ImageService
endpoints don’t require authentication. An interesting one is
https://<hostname:port>/emby/Items/<itemId>/Images/Primary
which lets an attacker download any image from the Emby
instance. In combination with the SuggestionsService
, the image id doesn’t even have to be guessed. But because ids in Emby
are sequential anyway, they could be.
Remote Code Execution through XSS in Admin Dashboard
A malicious user can send an authentication request with a manipulated X-Emby-Client
value, which gets added to the devices section of the admin dashboard without sanitization.
Here’s a small payload to verify the XSS
:
|
|
Because the JavaScript
gets executed in the context of an administrator, every service endpoint is usable for an attacker.
Here’s an exploit that executes an attacker controlled executable downloaded from the Internet:
|
|
This is the POST request after minimizing and encoding. We use String.fromCharCode()
so that we don’t need to mess with quotation marks:
|
|
The fake encoder executable could drop a plugin DLL
in order to gain persistent access to the Emby
instance.
An almost identical vulnerability was present in Jellyfin
. I’ve written about it here.
Summary
Unauthenticated attackers can retrieve a lot of valuable information from the outside through the SuggestionsService
. They can then retrieve every image of an instance. There are probably other attacks for which this information proves to be essential.
It doesn’t really matter, though, because Emby's
id system makes use of insecure direct object references. An attacker could simply enumerate lots of ids until they find images.
Furthermore, malicious users can trigger JavaScript
execution in an admin context in order to gain remote code execution on the Emby
instance.
All research was done on version 4.7.14.0
.
(End of report)
What is Fixed in 4.8.3.0?
Because the vendor isn’t responding, I wanted to do at least some light testing with the newest available version before releasing the full details. But please: Don’t just take my word for it!
Firstly, the SuggestionsService
endpoint requires authentication now. I haven’t tested if it’s scoped to the user making the request, though.
Secondly, the initial XSS
vulnerability in the admin dashboard seems to be fixed, too. I doubt that the underlying technique of switching the encoder binary in order to gain remote code execution was fixed.3
Here’s the relevant part of the Document Object Model (DOM) before the fix:
And here is one after the fix:
And lastly, the ImageService
endpoint still does not require authentication! Removing the ability to simply retrieve the image ids via the SuggestionsController
does make the process a bit more cumbersome, but it’s still trivial:
Ids are sequential, so we simply need a loop that requests emby/Items/<i++>/Images/Primary
. Emby
is kind enough to provide clear error messages. Either an item is not an image, or the requested id has not been assigned yet. A nice exit condition for the loop.
Conclusion
Looking at two projects with a common history but enough divergence today was a lot of fun. Jellyfin's
decision of using UUIDs instead of ascending integers for identifiers might have the most impact. If we could somehow combine last year’s argument injection in Jellyfin
with the id system or SuggestionsService
of Emby
, we’d be in unauthenticated RCE
heaven!
The vulnerabilities highlighted in this article yet again show just how important a proper setup for self-hosted services is. Ideally, the login pages of the individual services should never be exposed. I realize that a lot of those media servers are shared with people not well-versed in technical details. Nevertheless, there are countless guides out there dealing with this exact scenario.
Proper isolation is key, because there will always be bugs. The lesser surface exposed, the better.
As always, thank you so much for reading!