- Harvest の Outlook Calendar OAuth 連携フローでは、コールバック URL が
state値の行き先へ再度遷移することで オープンリダイレクト が発生し、暗黙的認可フローと組み合わせるとトークンが外部 URL に露出し得た - 問題は Microsoft 側ではなく Harvest の統合側にあり、登録済みの OAuth
redirect_uriが攻撃者指定ドメインへユーザーを送る リダイレクトの踏み台 になっていた stateは URI エンコードされた JSON で、subdomainにexample.com/のようにスラッシュ付きの外部ドメインを入れるとexample.com/.harvestapp.com/...形式へ遷移する- PoC では Microsoft OAuth の authorize URL で
client_id=0dcef4db-36d8-4aed-9cc5-ab43e1814884,response_type=id_token,response_mode=fragment,scope=openidを使用し、#id_token=...フラグメントがリダイレクト先に付与される流れを示している - 脆弱性は 2020 年 8 月 23 日の報告後、2023 年 8 月 1 日に修正が確認され、2023 年 10 月 22 日に Harvest は遅延が human error だったとして謝罪した
OAuth コールバックでトークンが漏れる流れ
- Harvest はユーザーが Outlook Calendar を OAuth で接続できる時間追跡ソフトウェア
- 認可が成功すると、ユーザーは
https://outlook-integration.harvestapp.com/auth/outlook-calendar/…にリダイレクトされる - このコールバックはさらに
state内で指定された URL へユーザーを移動させ、その過程で オープンリダイレクト が発生する - 元々確認されたコールバック URL の
state値は URI エンコードされた JSON- デコードすると
{"return_to":"/","subdomain":"hackerone295"}の形になる subdomain値はhackerone295.harvestapp.comのような Harvest アプリ領域を推定するために使われる
- デコードすると
subdomainにexample.com/のようにスラッシュを付けると、コールバック URL が外部ドメインへ移動する形になる- このコールバック URL は OAuth アプリケーションに登録された redirect_uri であるため、オープンリダイレクトと暗黙的認可フローを組み合わせるとトークンがリダイレクト先に露出し得る
- PoC の authorize URL は次の値を使用
client_id=0dcef4db-36d8-4aed-9cc5-ab43e1814884response_type=id_tokenredirect_uri=https://outlook-integration.harvestapp.com/auth/outlook-calendar/…?...scope=openidresponse_mode=fragmentstate=1nonce=123456
- ユーザーは最終的に次のような形式へリダイレクトされる
https://example.com/.harvestapp.com/auth/… access token]&state=1
- Microsoft 側の脆弱性ではない
報告から修正までにかかった時間
- Harvest チームは脆弱性公開と修正の過程で応答が非常に少なく、triage で脆弱性を認めた後も修正まで長い時間がかかった
- 2020 年 8 月 23 日に脆弱性が報告され、2020 年 10 月 16 日に Harvest が初めて連絡した
- 2020 年 11 月 27 日にレポートは triaged 状態になった
- 2022 年 4 月 28 日に同社は修正中で、予定期間を 2 週間と示したが、実際の修正まではさらに約 1 年かかった
- 2023 年 8 月 1 日に脆弱性の修正が確認された
- 2023 年 10 月 21 日に公開記事としてレポートが公開された
- 同日時点でレポートは依然として triage 状態で、バグバウンティ方針には報酬の記載があったが、バウンティも HackerOne ポイントも支払われなかった
- 2023 年 10 月 22 日、記事が注目を集めた後、Harvest は遅延について human error だったと説明し謝罪した
1件のコメント
Hacker Newsのコメント
バグバウンティプログラムの担当者として、社内で何が起きていたのか説明します。すでに@0xcryptoには謝罪し、社内でも説明しましたが、ここでも整理しておくのが正しいと思います
当初からこの問題を完全には再現できず、何か見落としているのではないかと思ってクローズもできない状態でした。最後に「解決策を探す」と返答した直後には、再現不能という判断に近づいており、似たようなOAuth関連の報告が入ってきたことで社内で混乱が生じ、すでに対応して伝達済みだと勘違いしていました
通知設定のために後続メッセージを見落とし、イシューがTriage状態のまま無期限に残り、更新がありませんでした。これは言い訳ではありません。私自身、長くバグバウンティハンターとして活動してきたので、企業からの更新を待つことがどれほどもどかしいかはよく知っています。顧客のセキュリティは最優先であり、セキュリティページに書かれている内容は事実です
さらに、今となっては再現できない報告をどう扱うのかも不明です。HackerOneでさらに議論したかったのですが、謝罪メッセージの後、また無応答になったように見えます
アプリの状態がサーバーの状態と頻繁に食い違い、サーバー側の変更は強制リロード後でないと見えなかったり、クライアント側の変更が保存後に元に戻ったりします。時間追跡のユーザー体験も不便で、ボタンがスクロールしないと見えなかったり、開始/停止/再開/削除ボタンの位置が項目の状態によって常に変わったりします。以前のアプリは見た目こそ良くありませんでしたが、問題なく動作していました
かなり不安です。Harvestを使ってみたとき、サポートは本当に素晴らしく、返答も速く、顧客が製品をどう使っているかを細かく理解していて、既存機能を創造的に活用する方法も詳しく教えてくれました
実装されていない機能については「バックログには入れるが保証はできない」という回答でした。エンジニアリング要員は30人とされていますが [1]、その人員がどこに使われているのかはよく分かりません。他の機能が素早く出てくるのも見ていないからです
「Harvestユーザー」としてスパムを受け取り始め、顧客リストを売ったのではないかと疑ったのですが、会社の責任者たちがすぐにつながって強く否定し、即座に調査するほど真剣に対応しました。それは良かったです
しかし結局、これもエンジニアリング上の問題に見えます。アクティブな顧客をかなり簡単に推定できる方法を見つけましたが、これも「バックログ」に入った後、数か月たっても修正されていません。修正はごく些細なものに見えました。また、MFAはGoogleでログインするときにしか提供されません [2]。それでもアプリ自体は、任された仕事を本当によくこなします
1: https://www.getharvest.com/about/meet-the-team
2: https://support.getharvest.com/hc/en-us/articles/36005266713...
このスレッドの報告者とのコミュニケーションが食い違ったのは完全に私のミスで、上の回答で説明した通り、二度とこのようなことがないようにします
機能リクエストの一部は実際に製品に入ったこともあります。私の影響ではなかったかもしれませんが、少なくとも良い時間追跡ツールについての考えは似ていたようです
タイトルはMicrosoftにかなり不公平に見えます。最近の認証事故でMicrosoftが注目を集めたことを利用しようとしている感じで、タイトルを見た瞬間に「またMSの侵害か」と思いました
実際にはHarvestのトークンであり、Harvestコードのインジェクション脆弱性によってHarvestアプリへのアクセス権だけが誤って露出したものです。ほかのどんなアイデンティティプロバイダーの背後にあったとしても、同じように脆弱だったはずです
この脆弱性はMicrosoftアカウント連携用のOAuth実装にのみ影響するためです。元のタイトルは「Microsoft OAuth token leak via open redirect in Harvest App」で、その後「Microsoft Account's OAuth tokens leaking via open redirect in Harvest App」に変更しました。今でも変更するつもりはあり、提案を受け付けます
RFC 6749 では、認可サーバーがこのような攻撃を防ぐ方法を詳しく扱っている。
認可サーバーは、公開クライアントにはリダイレクト URI の登録を必ず要求し、機密クライアントにも要求することが望ましい。リクエストでリダイレクト URI が提供された場合、認可サーバーは登録済みの値と照合して検証しなければならない。
だとすると、Harvest アプリが悪意ある
redirect_uriを登録していたはずはないのに、どうしてこれが可能だったのか気になる。Microsoft OAuth サーバーは、OAuth クライアントの登録済みリダイレクト URI と比較するときに、redirect_uri内の URL パラメータを無視しているのだろうか?stateパラメータに入れたように見える。おそらく任意の場所へリダイレクトする目的だったのだろう。意図されたフローは、Harvest の認証 URL へ移動 → Microsoft の認証 URL へ
redirect_uri=registered_uriとstate=some_encoded_final_uriを付けてリダイレクト → ユーザーが認証情報を入力 → 登録済み URI へリダイレクト →stateを読み、その中の URI へ再度リダイレクト、という形。この攻撃でも依然として許可済み URI へリダイレクトするが、そのエンドポイントが
stateを読み、レスポンス/トークンをそのまま渡してしまう。ミスは3つある。stateの乱用、乱用するならstateを暗号化して検証していなかったこと、そしてインプリシットグラントを有効にしていたこと。必要だったなら、用途を限定した別の登録を作るべきだった。redirect_uriは Microsoft に登録されている。Microsoft OAuth サーバーが Harvest にリダイレクトした後、Harvest がstateのデータに基づいて独自のリダイレクトを実装していたということ。インプリシットグラントは、この記事で見られるように、こうした理由からかなりひどい。
ちなみに、まもなく出る OAuth 2.1 仕様では削除される予定: https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-09.htm...
脆弱性の修正に3年かかったということ? 2020年8月から2023年8月までとは、Harvest チームの規模は知らないが、それでもあり得ないレベルに見える。
OAuth の専門家に、この問題をもう少し詳しく説明してほしい。ブログを何度か読んだが、実際の脆弱性がまだ理解できない。
ごく限られた OAuth の知識では、Harvest アプリが Microsoft にユーザー検証を依頼し、Microsoft がユーザーを検証した後、成功するとコールバック URL にリダイレクトし、レスポンス本文でアクセストークンを渡す、という方式ではないのか?
この場合、ブログ筆者は戻り先 URL を実際の戻り先 URL ではなく example.com に向かわせる手製 URLを作っただけではないのか?
harvestappドメインで、攻撃者が制御する部分は OAuth サーバーから見るとほぼ不透明なstateの中にある。その URL を使うと、誰かに
login.microsoftonline.comのリンクを送り、「Harvest にログイン」するようなログインプロンプトを表示させたうえで、攻撃者が実際の Harvest アカウント関連の権限を得られる。通常は不可能。攻撃者が
example.comにリダイレクトされる新しいアプリを登録することはできるが、それでは Harvest 関連の権限が入ったアクセストークンを得られないので役に立たない。Microsoft 側の OAuth アプリには有効なリダイレクト許可リストがあるため、
login.microsoftonline.com/authorize?client_id=$harvestAppID&redirect_uri=attacker.comのような試みは Microsoft 側でエラーになる。攻撃が可能なのは、有効なoutlook-integration.harvestapp.comURL がアクセストークンを受け取った後、さらに攻撃者サイトへリダイレクトし、その際にアクセストークンも渡してしまうため。outlook-integration.harvestapp.comにあった。OAuth2 コールバックが成功した後に実行する指示を含む JSON オブジェクトをstateとして使っていた。subdomainプロパティは、ブラウザをharvestapp.comのサブドメインへリダイレクトしつつ#id-tokenを渡すために使われていた。問題は、subdomainの値が以下の URL にそのまま注入されていたこと。https://${subdomain}.harvestapp.com/...#id-token=...
JSON ペイロードの
subdomainをattacker-controlled.com/のように末尾にスラッシュの付いた値に設定すると、URL はhttps://attacker-controlled.com/.harvestapp.com/...#id-token=..となり、ブラウザが別ドメインへ移動してトークンが漏えいする。したがって OAuth 自体の暗黙的な問題ではなく、不十分な実装である。
ワークフローを設定するとき、信頼できるコールバック URL の実際のリストを作る代わりに、コールバック URL の許可リストにワイルドカードを使った可能性がある。完全に間違っているかもしれない。
なぜ3年も待ったのか分からない。公開前の猶予期間は90日で十分
ただし、そうした追加猶予は研究者、またはその弁護士/代理人が認めるべきもの。通常より大きな案件について、企業が善意で求める性質のものだ
HackerOneが企業にこういうことを3年も寝かせておくのを許すなら、自分たちの役割をきちんと果たしていないように思う
最も基本的なレベルでは、脆弱性公開プラットフォームと、研究者が法務チームに訴えられないようにするための標準的な法的文言を提供するだけ。
ほとんどの場合、企業は公開要求を拒否する。研究者が許可なく公開すれば、HackerOneおよび企業との取り決めに違反し、法的責任にさらされる。今回の場合は企業が公開に同意したようで、対応が非常に遅かったとしても、その点は評価してよいと思う。
個人的にも、4桁ドル規模の報奨金が出るバグが1年以上修正されなかったことが何度もあるが、HackerOneのせいだとは思わなかった
HackerOneは気にしていなかった。その人物が自分たちのルールを破っていると何度も知らせても、何もできないと言われた。
まともに運営できる状態まで作られた会社を最小限の運営要員だけ残して縮小し、権限のないサポート担当者が質問に答えているような感じだった。かなり前のことなので今は違うかもしれないが、当時の印象はそうだった
HackerOneが一線を越えて、企業に何をすることを「許可」するか決めていると感じれば、企業はただHackerOneを離れて社内ソリューションを作るだろう
なぜこの問題がMicrosoftに伝えられなかったのか理解できない。Microsoftなら問題が修正されるまで、このOAuthアプリケーションのアクセス権を取り消せたはずだ。
ただ、MicrosoftにはOAuthで接続された同じようにひどい実装が何千もありそうだ