5.5.5 では判定できない — TrueConf CVE-2026-72530 のビルド番号

セマンティックバージョニングに慣れていると、バージョン比較は3つの数字を左から見ればよい、という感覚になる。5.5.4 < 5.5.5 であり、5.5.55.5.5 と等しい。台帳の比較処理もたいていそう書かれている。

その感覚のまま扱うと確実に誤判定する脆弱性がある。TrueConf Server の CVE-2026-72530 がそれだ。CISA が 2026年8月20日に KEV へ収載し、是正期限を 2026年9月3日とした。

理由は単純で、修正が4桁目のビルド番号で入っており、しかもその番号が OS ごとに違うからである。「5.5.5 だから修正済み」は成立しない。

この記事では判定を間違える構造を示し、最後にビルド番号まで見て判定するスクリプトを置く。

何が起きるのか

NVD の記述によると、4307/TCP を通じてネットワーク到達できる未認証の攻撃者が、細工したスクリプトを用いて隔離された実行環境を脱し、ホストシステム上で任意コードを実行できる。

CWE は CWE-94(コード生成の不適切な制御)。採番元(CNA)は Kaspersky Labs で、CVSS 4.0 で 9.5 Critical、CVSS 3.1 で 9.0 Critical を付けている。NIST 独自の評価は本稿執筆時点(2026年8月22日)では付いていない。

「隔離環境からの脱出」という表現が要点である。スクリプトを走らせる仕組み自体は想定された機能で、その実行はサンドボックス内に閉じているはずだった。壊れているのは機能ではなく閉じ込めのほうだ。したがって「スクリプト機能を使っていないから関係ない」とは言えない。使うかどうかを決めるのは攻撃者の側である。

そして悪用は理論上の話ではない。Kaspersky の Securelist は、Head Mare と呼ばれる攻撃者グループが TrueConf Server を標的に PhantomCore を展開した事例を公表しており、NVD はこの記事を Exploit の参照として登録している。

修正版の一覧

影響を受けるのは 5.3.X〜5.3.9、5.4.X〜5.4.9、5.5.X〜5.5.5 とそれ以前である。修正版は次のとおり分かれる。

系列 Windows Linux
5.3 5.3.9.10013 以降 5.3.9.10015 以降
5.4 5.4.9.10072 以降 5.4.9.10019 以降
5.5 5.5.5.10010 以降 5.5.5.10009 以降

表を眺めると、判定に必要な情報が3つあることが分かる。系列(5.3 / 5.4 / 5.5)、OS(Windows / Linux)、そしてビルド番号である。どれか1つでも欠けると判定できない。

いくつか具体で確かめる。

  • 5.5.5.10009(Windows)… 修正版は 10010 以降。該当する
  • 5.5.5.10009(Linux)… 修正版は 10009 以降。該当しない
  • 5.4.9.10019(Windows)… 修正版は 10072 以降。該当する
  • 5.4.9.10019(Linux)… 修正版は 10019 以降。該当しない

同じ文字列 5.5.5.10009 が、OS によって該当と非該当に分かれる。バージョン文字列だけでは答えが決まらないということだ。

さらに 5.4 系のビルド番号 10072 は、他の系列の 10013〜10019 と桁の並びが違う。「番号が大きいほう=新しい」という素朴な比較は系列をまたぐと通用しない。比較は同じ系列の中でだけ意味を持つ。

資産台帳が壊れる形

ここで起きがちな誤判定を整理しておく。

1. 3桁で切り捨てている。 収集スクリプトが 5.5.5.10009 を正規表現 [0-9]+\.[0-9]+\.[0-9]+ で拾うと 5.5.5 になる。この時点で判定に必要な情報が消える。しかも消えたことに気づけない。台帳には妥当な文字列が入っているからだ。

2. OS を持っていない。 バージョンだけの台帳では、同じ 5.5.5.10009 が該当か非該当か決められない。

3. 系列をまたいで数値比較している。 「ビルド番号 10072 以上なら修正済み」という単一の閾値を書くと、5.3 系と 5.5 系のホストが軒並み「未修正」になる。逆に「10009 以上」と書けば 5.4 系が取りこぼされる。

3つとも、間違った答えが自信を持って返ってくるのが厄介なところである。エラーにならないので、レビューでも見つかりにくい。

実際に試す

系列と OS を踏まえて判定する Python スクリプトを置く。依存パッケージは無い。

前提: Python 3.8 以上。バージョン文字列と OS を渡すと該当可否を返す。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/usr/bin/env python3
"""CVE-2026-72530 (TrueConf Server) の該当判定。

修正版は「系列 x OS」ごとにビルド番号が違う。
3桁までの比較では判定できないため、4桁目まで見る。
"""
import sys

# (系列): {OS: 修正が入った最小ビルド番号}
FIXED = {
(5, 3, 9): {"windows": 10013, "linux": 10015},
(5, 4, 9): {"windows": 10072, "linux": 10019},
(5, 5, 5): {"windows": 10010, "linux": 10009},
}


def parse(version):
"""'5.5.5.10009' -> ((5,5,5), 10009)。4桁目が無ければ build=None。"""
parts = version.strip().split(".")
if len(parts) < 3:
raise ValueError(f"バージョンの形式が不正です: {version!r}")
try:
major, minor, patch = (int(p) for p in parts[:3])
except ValueError:
raise ValueError(f"バージョンの形式が不正です: {version!r}")
build = int(parts[3]) if len(parts) >= 4 and parts[3].isdigit() else None
return (major, minor, patch), build


def verdict(version, os_name):
os_name = os_name.strip().lower()
if os_name not in ("windows", "linux"):
return "unknown", f"OS が不明です(windows / linux のいずれか): {os_name!r}"

series, build = parse(version)

# 修正が入った patch 番号より小さい系列は、ビルド番号を見るまでもなく該当。
for fixed_series in FIXED:
if series[:2] == fixed_series[:2] and series[2] < fixed_series[2]:
return "affected", (
f"{'.'.join(map(str, series))} は "
f"{'.'.join(map(str, fixed_series))} より前です"
)

if series not in FIXED:
# 5.6 以降など、表に無い系列。安全側に倒して「不明」を返す。
return "unknown", (
f"系列 {'.'.join(map(str, series))} は修正版一覧にありません。"
"ベンダーのアドバイザリを直接確認してください"
)

need = FIXED[series][os_name]
if build is None:
# ここが本題。ビルド番号が無ければ判定できない。安全側に倒す。
return "unknown", (
f"ビルド番号がありません。{os_name} では {need} 以上が必要です。"
"資産台帳が3桁で切り捨てていないか確認してください"
)
if build < need:
return "affected", f"{os_name} の修正版は build {need} 以上(現在 {build})"
return "not-affected", f"{os_name} の修正版 build {need} 以上を満たします({build})"


def main(argv):
if len(argv) != 3:
print("使い方: trueconf_check.py <version> <windows|linux>", file=sys.stderr)
return 64
state, reason = verdict(argv[1], argv[2])
print(f"{argv[1]} ({argv[2]}): {state}{reason}")
# 該当=2 / 判定不能=1 / 非該当=0。判定不能を 0 に倒さない。
return {"affected": 2, "unknown": 1, "not-affected": 0}[state]


if __name__ == "__main__":
sys.exit(main(sys.argv))

同じバージョン文字列が OS で分かれることを確かめる。

1
2
3
4
python3 trueconf_check.py 5.5.5.10009 windows;  echo "exit=$?"
python3 trueconf_check.py 5.5.5.10009 linux; echo "exit=$?"
python3 trueconf_check.py 5.5.5 linux; echo "exit=$?"
python3 trueconf_check.py 5.4.9.10019 windows; echo "exit=$?"

出力は次のとおりになる。

1
2
3
4
5
6
7
8
5.5.5.10009 (windows): affected — windows の修正版は build 10010 以上(現在 10009
exit=2
5.5.5.10009 (linux): not-affected — linux の修正版 build 10009 以上を満たします(10009
exit=0
5.5.5 (linux): unknown — ビルド番号がありません。linux では 10009 以上が必要です。資産台帳が3桁で切り捨てていないか確認してください
exit=1
5.4.9.10019 (windows): affected — windows の修正版は build 10072 以上(現在 10019
exit=2

3行目が、この記事で言いたかったことである。**5.5.5 を渡すと「非該当」ではなく「判定不能」が返る。** 3桁しか持っていない台帳は、安全だと答えてはいけない。答えられないと答えるのが正しい。

更新のほかにやること

対応は更新だけで終わらない。3点を挙げておく。

4307/TCP の到達範囲を見る。 この番号はクライアントの接続に使うものではないので、インターネットから到達させる必要がある構成は多くない。管理セグメントからのみ到達可能にする措置は、更新までの時間稼ぎとして現実的である。ただしベンダーが公式の workaround として提示したものではなく、成立条件から導かれる措置である点は区別しておく。

痕跡を確認する。 KEV 収載と Head Mare の事例公表がある以上、更新前の期間に既に侵入されている可能性を検討する必要がある。TrueConf Server のプロセスから起動された想定外の子プロセス、4307/TCP への外部からの接続記録、サーバ上の新規の実行ファイルを確認する。

台帳の粒度を上げる。 今回の教訓はここに残す。ビルド番号と OS を記録していない台帳は、この種の脆弱性が来るたびに実機調査からやり直しになる。

各クラウド・ディストリでの対応状況は CVE Watch の該当ページにまとめている。TrueConf Server はベンダー配布パッケージで導入するため、ディストリのセキュリティトラッカーにはエントリが立たない点も Zimbra と同じである。


5.5.5 では判定できない — TrueConf CVE-2026-72530 のビルド番号
https://blog.hashito.biz/2026/08/22/trueconf-cve-2026-72530-build-number-comparison/
著者
hashito
作成日
2026年8月22日
著作権