前言

如果你想知道如何在继续使用第三方服务的情况下,避免和减少 Token 盗用产生的影响,那么下面这篇文章可能会对你有所帮助

https://hicane.com/archives/geek-embyserver-token-an-quan-wei-hu-zhi-nan

背景

昨天,朋友突然找到我,说他的 EmbyServer 被人入侵了,内容库被胡乱删改,留下了一堆挑衅信息。

emby-index.png

简单的问了下,了解到他的 EmbyServer 设置的管理员密码是个弱口令,而他最近在后台经常看到一些恶意的登录行为,不过频率并不高。我以为是简单的弱密码被碰撞到了,并没有放在心上,只是让他删除所有配置和数据,重装一遍,并设置更加复杂的密码。

emby_wechat_scan.png

朋友很听劝,第一时间按照建议重装了系统,可是不到三小时,联系我说 EmbyServer 又沦陷了。这次入侵者不但删改了内容库标题,还主动在 TG 上联系到了他,勒索 100U,嚣张程度可见一斑。

emby-tg.png

这时我开始意识到这次攻击是有备而来,短短三个小时,不太可能是碰撞撞出来的,肯定是哪里有了漏洞导致的。于是和朋友要了服务器帐号密码,开始溯源。

安全应急响应的一般流程

很多人没有遇到过类似的情况,不知道遇到这种事该怎么处理。这里简单的讲解下我所了解的安全应急响应的一般流程,因为我并不是搞网络安全出身的,内容难免有错误、遗漏之处,还望各位指出。

  1. 遏制

    第一时间要做的,永远是遏制,防止攻击者利用漏洞进一步提权或破坏,针对此次情况,首先要做的就是网络隔离

    因为朋友的 EmbyServer 运行在 Docker,如果可以确定影响没有溢出到宿主机的情况下,可以考虑其他业务不停机,先断开 EmbyServer 的网络连接

  2. 保护现场

    其次要做的,是尽可能关停一些对关键日志有更改/删减操作的服务

  3. 分析

    溯源和分析,找到发生问题的原因

最后是清除、恢复和总结。

溯源过程

1. 确定影响范围

首先,第一时间登入服务器,在做好了网络隔离的情况下,开始分析系统痕迹。经过分析,基本可以排除服务器层面的侵入可能,结合 EmbyServer 的 Docker 配置,基本也可以排除从容器提权到宿主机的可能,最终锁定侵入范围仅在 EmbyServer 服务本身。

2. 调查服务背景

经过确认,服务器所用 EmbySever 为官方最新版本镜像。EmbyServer 使用了数个第三方插件以及围绕 EmbyServer 搭建了数个配套服务系统,均运行在单独的 Docker 中,服务之间互相隔离,并没有使用 Docker compose 统一编排。

首先,我倾向于认为不太可能是 EmbyServer 本身的问题,假如是一个已经公开过的基于最新版本的高危安全漏洞,现在肯定到处都是风声,不会像现在这么安静。如果是个未公开发表的 0day,我相信发现者也不会拿这种高级别漏洞做这么 low 的事儿,而且整个勒索的过程也显得太不专业了点,怎么看都像个脚本小子。

不过本着宁可信其有,不可信其无的心态,还是简单的检索了下,确定 EmbyServer 近期没有高危漏洞公开发布的信息。至此进一步缩小调查范围,集中锁定在插件和其配套的周边服务。

3. 溯源

前两步其实在登入服务器之前心里就已经估摸个大概了,所以执行起来并没有花费多少时间,更多的是对想法的验证。接下来主要集中在对日志的分析上,整个 EmbyServer 日志打包下来有 80 多MB,一条一条看是不可能的,只能聚焦在敏感操作上,先简单搜了下跟认证/用户服务/Token 相关的日志,有大几千条,即使过滤了 succeed/success 相关的,也剩个几百条。

emby-log.png
emby-auth.png

全看是不可能全看的,尝试定位下事件发生的时间段。比较麻烦的是,朋友并不知道确切的事件发生时间点,只是其他用户告诉他, EmbyServer 的内容库被再次更改,并且他尝试登录自己的管理员账户,发现登录不上去。

因为已经做好了网络隔离,不必担心启用 EmbyServer 后被侵入者被进一步搞破坏,所以直接后台重置密码,以管理员用户登录后台查看信息。

这一查,确实发现了一些有用的信息,这个帐号在 15:49 分的更改用户策略和创建用户的行为并不是朋友自己操作的。

emby_user.png

定位到该段时间对应的详细日志,果然有所收货

2025-10-20 15:49:00.043 Info UserService-0HNGFIA83NGCV:00000001: http/1.1 POST http://‌‍‍xx.xx.xx.xx/Users/xxxxxxxxxxxxx/Password. Source Ip: ‌‍‍144.xx.xx.xx, UserAgent: python-requests/2.32.5

UserAgeng: python-requests/2.32.5 ,这并不是一个来自浏览器的正常请求,而是 Python requests 库的默认 UA。在日志中,搜索脚本使用者的IP(144.xx.xx.xx)的所有操作,基本可以还原整个过程。

15:47:54 - 用 Python 脚本,利用 EmbyServer Token 修改管理员密码
15:49:00 - 创建新的账户 pxxxx
15:49:00 - 为 pxxxxx 设置密码修改权限
15:49:24 - 删除原始管理原账户

4. 定位漏洞

知道了对方的攻击手法,下一步就是找到 Token 泄漏的原因。第一次出问题后,朋友重装官方的 EmbyServer 容器后新设了三条 Token,分别给了三个相关服务使用,同时 EmbyServer 本身又再次装了第三方插件。

第一时间的想法是确定哪个 Token 遭到了泄漏

继续研究了下 EmbyServer 日志,发现其并没有更进一步的详细请求说明,无法得知一个请求具体使用的请求参数。

又问了下朋友在搭建反向代理服务过程中的细节,没有获取到有用信息,也没有相关日志可以读取。

无法确定是哪个 Token 遭到了泄漏,只能对插件和服务一一进行排查

首先看了下第三方插件,功能主要是利用 ffmpeg 来读取媒体数据,达到加速刮削的作用。插件用的人不少,作者多少也是听说过的,个人不太相信其会埋雷,另外我虽然没有用过这个插件,但是基于这个插件的功能分析,不太可能有需要用到 Token 的地方,其他人找到这个插件的漏洞然后获取 Token ,应该也是不太可能的。

剩下三个服务,一个是用来下载媒体的,一个是用来同步和生成 Strm 的,一个是用来管理 EmbyServer 用户的,每个都有获取 Token。

第一个是个比较知名的开源项目,使用人数非常多,基本不太可能会出现这种问题(因为如果有 0day 的话,影响范围会大很多,应该能听到风声)先放在后面。

后两个都是小范围内使用的收费项目,且朋友都使用了很长一段时间,两个都有可能。不过我听到其描述后的第一反应就是管理 EmbyServer 用户的更可能像是泄漏的原因,毕竟跟用户操作相关的服务总是比较让人敏感的,决定首先排查这个。

5. 代码审计

进去EmbyServer 用户管理服务的容器,看了下源码,Python 写的,有一定的加密,但不多。代码风格写的也比较像 AI 生成的(此时心里已隐约感觉问题大概率出现在这里)。

开始审计,首先说明下进行审计时候的排查思路(因为这个服务的功能和代码还是比较多的)

  1. 首先需要重点关注的是跟配置相关的路由,这里是最有可能导致 Token 泄漏的地方

  2. 其次是关于权限验证部分的代码

  3. 再次是关于可能存在注入点和任意代码执行部分的路由

  4. 其他接口

关于1, 他这个项目写的还是比较特殊的,前端没有手动写入 EmbyServer Token 的地方,而是在安装的时候通过配置文件写入的。Token 并没有写入环境变量,且所有获取配置信息的接口,都没有暴露 Token 的可能。

关于2, 权限验证部分的路由也没有太多问题,而且就算是管理员登录,也没有在前台能获取到的 Token 的地方。

关于3, 不存在这样的问题

只能去检查,使用 Token 和调用 Emby 相关服务的路由,在一个 emby-proxy 的路由下,发现了问题

@app.route('/emby-proxy/<path:subpath>')
def emby_proxy(subpath):
    """代理Emby图片请求,解决Docker中的跨域问题"""
    try:
        # 构建完整的Emby URL
        url = f"{EMBY_SERVER}/emby/{subpath}"
        headers = {
            'X-Emby-Token': ADMIN_TOKEN,
            'User-Agent': 'EmbyUserHub/3.1.0'
        }
        
        # 转发请求到Emby服务器
        response = requests.get(
            url, 
            headers=headers, 
            params=request.args,
            stream=True,
            timeout=10
        )
        
        # 如果请求失败,记录错误并返回错误响应
        if response.status_code != 200:
            app.logger.error(f"Emby代理请求失败: {url}, 状态码: {response.status_code}")
            return f"图片加载失败: {response.status_code}", response.status_code
        
        # 创建Flask响应对象
        from flask import Response
        proxy_response = Response(
            response.iter_content(chunk_size=10*1024),
            status=response.status_code,
            content_type=response.headers.get('content-type', 'image/jpeg')
        )
        
        # 复制响应头
        for key, value in response.headers.items():
            if key.lower() not in ('content-length', 'transfer-encoding', 'content-encoding'):
                proxy_response.headers[key] = value
                
        return proxy_response
        
    except Exception as e:
        app.logger.error(f"Emby代理异常: {str(e)}")
        return "图片加载失败", 500

作者本身是想要转发一些 Emby 响应方便用户能在前台或许一些有关 EmbyServer 媒体服务器的数据。问题是,他转发响应的处理逻辑,是直接拿从原始响应中拿取数据,并没有针对响应头和响应体中的敏感信息进行过滤,这就导致了 Token 泄漏的可能。

为了验证,拿普通用户帐号登入该服务前台。发现在普通用户查看最新入库媒体海报和获取最新媒体信息的界面,发起的请求中,响应体里直接暴露了 EmbyServer Token,就此基本可以确定漏洞所在。

总结

整个漏洞利用的过程是:

  1. 朋友搭建了一个收费的「EmbyServer用户管理」项目,可以方便快捷的进行用户管理

  2. 「EmbyServer用户管理」项目新建的普通用户既可以登录 EmbyServer,也可以在「EmbyServer用户管理」项目的用户端查看最新入库的媒体资源,但是这一过程中可以查看到 EmbyServer 的 Token

  3. 不法用户使用 Token 创建 EmbyServer 管理员账户,恶意窜改媒体库信息

  4. 因全部服务互相隔离,且 EmbyServer 用 Docker 容器搭建,不法用户无法进一步扩大伤害(又因为使用 Strm 的缘故,不法用户连删除原始资源也无法做到)

处理,已告知朋友漏洞原因和修复方案,截止目前,服务器并没有再次受到入侵。

后记

脚本小子在敲诈我朋友的时候并没有做好自己的匿踪防护,使用的 ‌‍‍144.xx.xx.xx 的跳板竟然是他自己的常用服务器。这下好了,可以友好的反向调查一下了,目前已经查到了域名,以及服务器上面跑得服务列表。

更新: 已经定位到QQ了,后续就不展开讲了。

10.22 再更新:

本来以为已经完结了的,朋友说服务器又被黑了,依然是 Token 改密码、删用户、改 EmbyServer 标题三件套。

比较纳闷,又向朋友详细询问了下细节。朋友说之前设置的三个 Token 并不只提供给了三个服务,有一些不在上次排查范围内的服务也在使用 - -#。再次溯源了下,手法跟上次一次,甚至连使用的 IP 都没变,漏 Token 的地方看来不止一处。不过破坏力依然感人,除了改改 EmbyServer 和媒体库标题也没有做进一步的伤害。

另外,又了解到一个细节,朋友说这次重装后,虽停用了「EmbyUser管理」服务。但其他使用 Token 的周边服务并没有修改密码,不排除周边服务存在弱口令的可能性。

考虑到破坏力实在有限(连删 Strm 副本都做不到,只能改网站和媒体库标题)。且了解完朋友使用的整个 EmbyServer 周边生态,发现还是比较复杂的(现在都有弹幕相关的了吗?),一个个服务去审查,时间成本上有点划不来。简单粗暴点,直接禁用 Token,后续想办法直接从根源上解决这个问题,如果禁用 Token 后还有侵入事件,便再做进一步分析。

另外朋友这台服务器,整个服务器上面的容器编排、网络隔离、日志记录、备份容灾还有不少可以优化和改善的地方。

有意思的是,这个入侵者使用的 144.xx 的服务器,也没做好,犯了很多的错误

后续打算结合本次案例出一篇关于服务搭建、容器编排、日常维护的文章。当然,在运维方面,我也只是个不入流的菜鸟,如果有说的不对或者有纰漏的地方,欢迎各为大佬指正,一起学习交流。

10.23 更新

没有再次发生入侵事件

10.29

没有再次发生入侵事件,但是发现了另一个 EmbyServer 自身的高危漏洞

https://hicane.com/archives/geek-embyserver-gao-wei-an-quan-lou-dong