teamspeak6 客户端服务端授权攻击分析
服务端
授权类型
目前ts6的服务端还在开发状态,所以teamspeak6每个版本内置了一套证书链,内容写死,有效期也是固定的,大概两三个月,到期了就得继续去拉新版服务端继续使用
除开内置授权,授权类型有以下几种
SDK是定制版本所以普通服务端会拒绝OFFLINE / SDK_OFFLINE授权版本
除了SDK_OFFLINE与OFFLINE授权不向 accounting2.teamspeak.com:443 汇报。其它类型会按 doc/server/accounting.txt 做开机汇报和每小时汇报;过期、被封、超槽、超虚机或汇报失败会停服。
授权文件使用
同目录下licensekey.dat,或 --license-path / TSSERVER_LICENSE_PATH。
授权文件格式
Signed_License_Info
├── 1 license_info (嵌套消息 License_Info) ← 被签名的内容
├── 2 sign_certificate (bytes,签名证书链)
└── 3 signature (bytes,必须正好 64 字节)
License_Info
├── 1 certificate (bytes,服务器证书链)
├── 2 private_key (bytes,必须正好 32 字节)
├── 3 max_slots (uint32) ← 文件路径真正生效的槽数
├── 4 max_virtual_servers (uint32) ← 文件路径真正生效的虚机数
├── 5 description (string)
└── 6 server_version_major(int32)
验证方式为签名而不是加密
根公钥
cd0de2aed46345509a7e3cfd8f68b3dc7555b29dccec73cd18750f993812408a
只有能对累积公钥做 Ed25519 签名的人,才能让服务端接受这份 protobuf
h_i = SHA-512( P_i || cert_i[33:] ) # 跳过开头那个 0x00
h_i[0] &= 0xF8 # 与 Ed25519 私钥相同的 clamp
h_i[31] &= 0x3F
h_i[31] |= 0x40
h_i = int_le(h_i[:32]) mod L
acc_0 = ROOT
acc_{i+1} = acc_i + h_i · P_i # Edwards 点加cert[33:] 就是 type + 日期 + payload,所以改日期、改类型、改位图、改发行者都会改 h_i,累积点跟着变。
对应私钥
sk_acc = sk_root + Σ h_i · a_i (mod L)
A_acc = sk_acc · B = acc官方 sk_root 未知,所以未改根的服务端无法验证自制授权文件。
此外内置的DEFAULT授权不会走授权类型和Ed25519验证,加载成功后会POST https://reporting.teamspeak.com/report
licensekey.dat
key2 + Base64 + key2 ← 可打印封装,可逆
│
▼
Signed_License_Info (protobuf 明文)
┌───────────────────┐
│ License_Info │ ← 签名消息 M
│ certificate = 服务器链 │
│ private_key = 32B 标量 │ ← licensesignmessage
│ slots / vs / desc / major │
│ sign_certificate = 签名链 │ ← 用来累加出 A
│ signature = 64B Ed25519 │
└───────────────────┘
│
▼
acc = ROOT + Σ clamp(SHA512(P||rest)) · P
Ed25519_Verify(acc, M, signature)
│
▼
类型白名单 + 日期 + 叶子类型 2/8
│
▼
授权生效(或失败回落 DEFAULT)
官方签发流程
官方签发时拥有 sk_root,流程是:
选授权类型、槽数、虚机、有效期、持有人名称。
生成中间证、服务器叶子、LICENSE_SIGN 三把 Ed25519 钥。
组服务器链(INTERMEDIATE + 类型 8 或类型 2)。
组签名链(INTERMEDIATE + LICENSE_SIGN)。
填 License_Info,按字段号 1..6 做 protobuf 序列化。
对签名链算 sk_acc,对序列化字节做 Ed25519 签名。
包成 Signed_License_Info,Base64,两边加 key2。
小结
由于生成授权的私钥未知,所以即使知道授权文件的生成机制也无法在不修改服务端的情况下让其接受自生成的授权文件
客户端
对服务端进行修改,成功使用OFFLINE类型的授权

注意到TS6客户端无法正常连接,但是TS6的客户端则出现了无法连接的情况,原因invalid serverID

使用TS3客户端,可以正常连接

怀疑可能是TS6客户端还加了中间验证,继续进行分析
最终发现会有三层验证
第一层验证-本地验证
官方客户端硬编码与 TS3 accounting 相同的根公钥(TeamSpeak.dll 内嵌 32 字节):
步骤:
验
proof
把omega当 P-256(prime256v1)公钥,对l的原始字节做 ECDSA-SHA256 验签。通过只说明“持有 omega 私钥的那一端发出了这条链”,不说明这条链挂在官方根下。打补丁的服务端也能签出合法proof,因为它自己有License_Info.private_key。解析链
version 必须为 1;2–8 张证书;日期嵌套合法;倒数第二张为 Server(类型 2 或 8);最后一张为 ephemeral(32)。license_type要落在客户端/服务端白名单(服务端sub_140941E10:{1,4,5,6,7,8,9,10,11,12})。结构不对 →illegal_server_license。从官方根做曲线累积,得到会话公钥
与服务端sub_14094AE60同一公式(Ed25519 / Curve25519 点,clamp 与私钥相同):h_i = clamp(SHA-512(P_i || cert_i[33:])[:32]) acc = ROOT + Σ h_i * P_i # ROOT = cd0de2ae…,含 ephemeral官方客户端的
ROOT写死为上面那 32 字节。服务端导出链、加 ephemeral 之后用自己加载许可证时的根做同一累积。两边ROOT一致,acc才一致。ECDH → SharedIV / SharedMac
客户端再生成临时 Curve25519 密钥对,令sharedData = acc * client_ek_sk SharedIV = SHA-512(sharedData) SharedIV[0..10) ^= alpha SharedIV[10..64) ^= beta SharedMac = SHA-1(SharedIV)[0..8]之后所有 Command 包按协议纸 §1.6 用 AES-128-EAX。
acc对不上,MAC 全错,表现为握手失败。clientekek= 临时公钥;proof= 用客户端身份(另一把 P-256)对ek[0..32) ‖ beta[0..54)签名。这是绑身份,不是验服务器许可证。
“官方性”完全取决于第 3 步的 ROOT。proof 只防中间人改 l 而不持有 omega 私钥。
第二层验证-官方的黑灰名单验证
客户端里关于黑灰名单检查的请求接口如下
https://blacklist2.teamspeak.com/check
Content-Type: application/x-ts3blacklistprotobuf com.teamspeak.blacklist.BlacklistInfoRequest / BlacklistInfoResponse:
请求里带出去的标识(都来自本机已有信息,不是官方回传授权):
响应按对象分别给出 status_ip / status_domain / status_virtual_server_id / status_public_license_id,枚举:
INVALID | BLACKLISTED | GREYLISTED | NOT_LISTED映射到 UI:
第三层验证-服务端拒绝
ClientInitRequest / ClientProperties 里服务端会看到:昵称、client_version + client_version_sign、平台、密码(base64(sha1(...)))、client_key_offset(身份安全等级)、client_myteamspeak_id、徽章、hardware_id、默认频道等。
常见拒绝(UDP 已通、第一层验证过了):
版本过旧 / 签名不是官方客户端三元组
安全等级低于虚机设置
服务器密码错误
封禁、克隆数、槽位满
myTSID:证书链、过期、吊销列表、签名失败(服务端字符串
rejecting myteamspeakid: ...)
myTSID 吊销列表由服务端去拉;失败日志为 failed to download mytsid revocation list,相关特性关掉,不带 myTSID 的普通身份仍可进。
总结
目前在不对客户端或服务端进行修改的情况下,无法实现对授权的伪装,但如果只修改服务端的根公钥,可以实现不上报官方服务器的情况下的扩容,但是只能TS3进行连接,TS6客户端由于会对服务器的授权的根公钥进行验证则会被拒绝连接。如果也修改TS6客户端内置的公钥则会导致客户端只能连接同样修改过的服务端,除非进行更多修改。
笔者水平有限,绝大多数分析工作都是由AI完成的,我主要是根据AI的分析结果了解他们产品背后的工作逻辑,授权逻辑,受益匪浅。
