NervesHubでAPIトークンが奪われる脆弱性、修正版あり
NervesHubのCLIログインに、アカウントを持たない第三者が利用者のAPIトークンを入手できる脆弱性があり、2.5.0から2.5.2を運用する組織が対象です。修正版2.5.3へ更新し、見覚えのないAPIトークンがないかも確認してください。
急ぎ度: 早めに
CVSS v4は9.4の重大な脆弱性ですが、公開と同日に修正版2.5.3が出ているため、様子見せずに早めに更新する段階です。
関係があるか
NervesHubを自分たちで運用している組織が対象です。CLIログインが加わった2.5.0以降の版を使っていれば、Webにサインインできる利用者全員のAPIトークンが狙われえます。
| 製品 | 影響を受ける版 | 修正版 |
|---|---|---|
| nerves_hub(otp) | 2.5.0以上、2.5.3未満(2.5.0から2.5.2) | 2.5.3(コミット3131f1701) |
| ghcr.io/nerves-hub/nerves-hub(oci) | 2.5.0以上、2.5.3未満(2.5.0から2.5.2) | 2.5.3 |
確かめ方
- 1自社でNervesHubを動かしているか、動かしているなら配備中の版(リリースまたはコンテナイメージのタグ)が2.5.0から2.5.2に当たるかを見ます。2.5.0より前の版は、CLIログインがまだ無いため対象外です。
- 2他社が運用するNervesHubを使っている場合は、運営元に2.5.3以降へ更新済みかを問い合わせます。
- 3リバースプロキシのログで、POST /api/auth/cli_sessionに身に覚えのない時刻や送信元からのアクセスがないかを見ます。
- 4アカウントページのAPIトークン一覧に、作った覚えのないものがないかを見ます。
何が起きたか
NervesHubのCLIログインの仕組みに脆弱性があり、アカウントを持たない第三者が、NervesHubの別の利用者名義のAPIトークンを手に入れられます。
CLIログインは、認証なしで開始できます。開始すると、ポーリング用のトークン、そのトークンを含む確認用URL、確認コードが返ります。サインイン中の利用者がこのURLを開いてConfirm loginを押すと、その利用者のAPIトークンが作られ、ログインの開始者がポーリングしたときに渡されます。
確認コードは画面に表示されるだけで、サーバー側では何とも照合されていません。確認した人がログインを始めた本人かどうかを、コードでは示せない設計でした。分類はCWE-384(セッション固定)です。
修正版2.5.3では、確認用のURLをすべてのログインで共通の /auth/cliに変え、利用者がCLIに表示された8桁のコードを入力してログインを探す方式になりました。ポーリング用のトークンはブラウザーに渡りません。確認の前に、ログインを始めた時刻、送信元アドレス、CLIが送った説明文が表示されます。コードは暗号論的な乱数から作られ、入力の試行にも回数の制限が付きました。
攻撃の流れ
-
1
ログイン開始
攻撃者が認証なしでCLIログインを始め、確認用URLと確認コードを受け取ります。
-
2
リンクを送る
NervesHubの利用者に、URLとコードを添えて確認を促す連絡を送ります。
-
3
利用者が確認
サインイン中の利用者がURLを開き、Confirm loginを押します。
-
4
トークン入手
利用者名義のAPIトークンが作られ、攻撃者のポーリングに対して返ります。
-
5
APIを悪用
攻撃者がそのトークンで、利用者の権限のままAPIを操作します。
どう悪用されるか
攻撃者はNervesHubのアカウントを持っている必要がありません。ネットワーク越しにログインを始められるので、サーバーがインターネットに公開されていれば誰でも起点を作れます。
一方で、被害者側にも条件があります。NervesHubにサインインしている利用者が、送られたリンクを開き、自分で確認ボタンを押さなければなりません。確認フォームにはCSRFトークンが付き、ページはフレームに埋め込めないため、利用者に気づかれずに押させることはできません。ただし、画面に出る確認コードは攻撃者も知っているので、連絡文に添えて送れます。コードを見比べるだけでは見破れません。
成功すると、攻撃者は被害者のAPIトークンを得ます。トークンは、被害者が所属するすべての組織で、被害者の役割のままAPIを操作できます。デバイスやファームウェアの閲覧、ファームウェアのアップロードと配信、デバイスコンソールを開く操作が含まれ、被害者が管理者なら組織の管理にも及びます。Webからサインアウトしても止まらず、アカウントページで削除するまで使えます。
今すぐやること
-
1
2.5.3へ更新する
2.5.0から2.5.2を動かしているなら、2.5.3へ更新します。クライアント側の変更は要りません。コンテナで運用している場合は、配備しているイメージのタグも確認します。
docker image ls ghcr.io/nerves-hub/nerves-hub -
2
発行済みのAPIトークンを見直す
更新しても、すでに発行されたトークンは失効しません。CLIログインで作られたトークンは普通のAPIトークンと同じ扱いで、説明文もCLI側が決めるため、攻撃者のものも見分けにくくなっています。各利用者にアカウントページで一覧を見てもらい、心当たりのないトークンを削除してもらいます。
-
3
不審なトークンがあれば操作の跡を調べる
身に覚えのないトークンが見つかったら、そのトークンで行われた操作がないかを調べます。ファームウェアのアップロードや配信、デバイスコンソールの利用を重点的に見ます。リバースプロキシのログにある、CLIログインの開始要求の送信元も手がかりになります。
-
4
コードを送られても入力しないよう周知する
修正版でワンクリックのリンクは無くなりましたが、他人から送られたコードを /auth/cliに入力させる手口までは防げません。デバイスコード方式のログインに共通する限界です(RFC 8628の5.4節)。利用者には、自分でnhを実行したときに表示されたコードだけを入力するよう伝えます。
すぐ更新できないとき
すぐに更新できないときは、リバースプロキシでPOST /api/auth/cli_sessionを遮断します。これでCLIログインの開始自体ができなくなります。CLIは、メールアドレスとパスワードによる認証(nh user auth、POST /api/users/auth)か、アカウントページで作ったAPIトークンで使い続けられます。
背景
NervesHubは、Elixirで組み込み機器を作るNervesの開発者が、機器へのファームウェア配信や管理に使うサーバーです。nhというCLIから操作でき、APIトークンがあれば、ファームウェアの配信やデバイスコンソールを開く操作がAPI経由でできます。今回のトークンが狙われると被害が大きくなるのは、この権限の広さによります。
CLIで始めた操作を別の端末のブラウザーで承認する方式は、デバイスコード方式と呼ばれます。承認する人が開始者本人かを確かめにくいという弱点が、仕様(RFC 8628)の中でも指摘されている方式です。今回の脆弱性は、確認コードを表示するだけで照合せず、トークン入りのリンクを開いて押すだけで承認できた点にありました。攻撃者が先に用意した識別子に、あとから被害者の認証結果が結びつく形で、CWE-384のセッション固定に当たります。
よくある質問
Q.更新すると、CLIを使う人の操作は変わりますか。
まだ分かっていないこと
- 実際の攻撃で悪用された事例の有無は、勧告では触れられていません。
この記事は、取得元の公開情報をもとに、人が監修しながらAIを活用して執筆しています。執筆と監修は佐々木 航が担い、公開したあとも人が内容を確認しています。誤りに気づいたときは直し、記事の末尾に訂正の行を残します。対応を決める前に、下の原文と参照先も確認してください。
影響パッケージ
| パッケージ | 影響を受ける版 → 修正版 | |
|---|---|---|
| nerves-hubnerves_hub_web |
e6bf11a812d7aa8b69d854ba8ef02d65516f5564 以上 3131f1701194b581ab4b3e5e9d81194fc9c83508 未満→ 3131f1701194b581ab4b3e5e9d81194fc9c83508 |
3131f1701194b581ab4b3e5e9d81194fc9c83508 |
原文の説明 取得元が公開している説明をそのまま載せています (多くは英語)。
Summary
Session Fixation vulnerability in the CLI login flow in nerves-hub nerves_hub_web allows an unauthenticated attacker to obtain an API token for another user's account via a crafted login link. Starting a CLI login with POST /api/auth/cli_session needs no authentication and returns a polling token, a confirmation URL that carries that token, and a confirmation code. When a signed-in user opens that URL and clicks Confirm, NervesHub.Accounts.verify_cli_session_token/2 creates an API token for the user's account and stores it on the login, and the next poll of GET /api/auth/cli_session/ returns it to whoever started the login.
The confirmation code is only displayed and is never compared with anything, so it cannot show that the person confirming is the one who started the login. The confirm form carries a CSRF token and the page cannot be framed, so the attacker has to persuade the user to open the link and click the button themselves.
This issue affects nerves_hub: from 2.5.0 before 2.5.3.
Details
1. Starting a login. nh user login, like any client of this flow, calls POST /api/auth/cli_session, which needs no authentication. NervesHubWeb.API.UserController.cli_session/2 calls NervesHub.Accounts.generate_cli_session_token/1, which stores a waiting login in the CLI session cache under a random UUID token with a six-digit confirmation code, and responds with the token, the code, and the URL /auth/cli/.
2. Approving a login. `GET /auth/…
出典: CVE.org (CVE Program・cvelistV5) NVD GitHub Advisory
参照URL
- web github.com
- web cna.erlef.org
- web osv.dev
- web github.com
- web github.com