OSSの脆弱性を発見して、CVEを2件取得するまで 脆弱性の発見・報告のポイント紹介
Amazon Translateでも利用されている機械翻訳フレームワークSockeyeとPythonのマイクロサービスフレームワークnamekoの任意のコード実行に繋がる脆弱性を発見し、報告を行い、CVEを2件(CVE-2021-43811, CVE-2021-41078)取得しました。
オープンソースソフトウェア(OSS)の脆弱性を発見、報告、CVEを取得までどのような過程を経たのか、OSSの脆弱性を見つける場合にはどのようにすると良いのか、報告方法はどうすればいいのか、今回の経験をもとにポイントを紹介します。
脆弱性報告の経緯
そもそもOSSの脆弱性を発見した経緯としては、前回の「TensorFlowだけじゃない!安全でないデシリアライゼーション in Python」の記事を書く中で、GitHubでyaml.unsafe_loadやyaml.UnsafeLoaderで検索すると脆弱な実装の可能性が高いものが見つけられる、ということを書いていたことがきっかけでした。
unsafeと書いてあることから推測できるように、悪意のあるコードを含むものをunsafe_loadを使って読み込むと任意のコード実行に繋がるという脆弱性が、有名な機械学習のためのライブラリであるTensorFlowに報告されていることから、同様の脆弱性がまだ他のOSSでもあるのでは、と思ったことから調査を開始しました。
実際に探してみると、該当するリポジトリ数は多いものの、ほとんどのリポジトリはスター数が一桁台の世の中で広く使われているものではないと思われました。
しかし、詳しく調査してみると聞いたことがある企業名が入ったものや、スター数が多いものもいくつか見つけることができたので、それらに関して実際に悪用可能かどうか、脆弱性の再現可能かどうかの調査を行いました。
その結果、今回の2件の脆弱性の発見、CVEの取得に繋げることができました。
脆弱性 発見のポイント
今回の脆弱性の発見のポイントを以下の3つに分けて紹介します。
既存の脆弱性の横展開
今回、発見した脆弱性は2つともにTensorFlowで発見されたPyYAMLのunsafe_loadを利用していたことによる安全でないデシリアライゼーションの脆弱性と同様のものです。
TensorFlowという有名なOSSにも脆弱性が残っていたことからも、他のOSSにも同様の脆弱性が残ったままかもしれない、と推測することで新たな脆弱性を発見することができます。
脆弱性が公開されてからあまり時間が経ってなく、多くの開発者が認知していない、リスクをあまり理解されていないような脆弱性の場合は特に既知の脆弱性の横展開するだけで見つけることができます。
そのため、セキュリティの研究者の中には、新たなタイプの脆弱性を見つけた時に、同様の脆弱性を簡単に見つけることができるツールを開発し、大量の脆弱性を報告することもあります。
ReDoS と呼ばれる正規表現の処理部分の不備による脆弱性に関して、最近は増えている印象ですが、 Regexploit と呼ばれるReDoSの脆弱性を特定するツールを開発し、11件ものCVEを取得したケースもあります。
このように、一つの脆弱性から横展開して、他の脆弱性の発見に活かす、ということがひとつめのポイントになります。
理解して変化させる
次のポイントは、既存の脆弱性を理解して、少し変化を入れる、違った要素を加えることです。
今回発見した脆弱性に関しても、元々の脆弱性では、PyYAMLのunsafe_loadを利用したことが原因でした。
しかし、安全でないデシリアライゼーションの脆弱性は、unsafe_load以外にもLoaderとしてUnsafeLoaderを設定した状態で、loadした場合にも影響を受けます。
このように、unsafe_loadが危険だからunsafe_loadだけ探すのではなく、安全でないデシリアライゼーションの脆弱性はどんな場合に起こるものなのか、そもそもどんな脆弱性なのかを理解して、既存のケースと違った場合でも起こることはないか、といった視点を少し加える工夫が大切です。
以前、以下の記事でnode-tarのパストラバーサルの脆弱性に関して紹介しました。
npmにも影響があるnode-tarのパストラバーサルの脆弱性 CVE-2021-32804
この脆弱性は、Linux環境を想定したパストラバーサルの脆弱性で、脆弱性への対応として修正されました。
しかし、その後Windows環境でのパストラバーサルの脆弱性が指摘され、再度修正を行っています。
LinuxとWindowsでパスの扱い方が違うことに気がつき、変化させることで修正をバイパスした脆弱性を発見することができます。
このような考え方は脆弱性を見つけるセキュリティエンジニアだけでなく、セキュアな開発を行う場合や脆弱性を修正する場合にも役立てることができます。
Try Harder!
最後のポイントは、Try Harder!(もっと頑張る)です。
Try Harderという言葉は、OSCPというペネトレーションテストの資格のキャッチコピーとして使われているため、セキュリティ業界では聞いたことがあるワードかもしれませんが、脆弱性を見つける時には一筋縄ではなかなかいかないことも多いため重要な要素だと思います。
私の場合もGitHubでunsafe_loadを検索し、多くのリポジトリに影響がある、で諦めずにひとつひとつ確認してみる、少し工夫して探してみる、と調査を続けました。
また、影響のありそうなプロジェクトを見つけた場合も既に脆弱性を認識していると思われるもの(コード上のコメントでリスクが書かれているものなど)は報告対象から外し、リスクがありそうな場合には実際に脆弱性が再現できるかどうか検証し、確認できたものを報告しました。
しかし、ただ闇雲にTry Harderするのではなく、上記のようなポイントを使ったり、自分の得意な範囲に絞るなどの工夫を重ねた上で、諦めずに取り組み続けてみることが大切だと感じました。
脆弱性 報告のポイント
脆弱性を見つけて、実際に報告する時の注意点やポイントを紹介します。
報告窓口を確認
脆弱性情報は誰でも確認できてしまうIssueとしてあげること基本的に避けるべきです。
リポジトリにSECURITY.mdのファイルがあれば、そこにどのように脆弱性を報告すれば良いのか書かれていますので、その方法に従って行いましょう。
SECURITY.mdがない場合もREADMEなどに報告窓口が書かれている場合がありますのでその方法に従って報告しましょう。
今回の報告では、namekoの場合は、READMEに書かれていたTideliftというOSSのメンテナをサポートするサービス経由で報告、その後のコミュニケーションを行いました。
わかりやすく情報を伝える
連絡先が見つかった場合には、発見した脆弱性に関して、詳細な情報をセキュリティに詳しくない人でもわかるような形で伝えましょう。
できれば、脆弱性を再現することができるPoCコードとその影響も含めて連絡することでメンテナも脆弱性を正しく把握することができるようになります。
今回、私が報告した際にはPoCコードとその再現による影響、TensorFlowでも同様の脆弱性が報告されていたことも伝えました。
気長に待つ、リマインドする
報告後、どちらも比較的迅速にメールでの応答があり、脆弱性の対応を行うプルリクが作成されるのが確認できました。
その後は修正が完了するまでは気長に待ちしょう。
報告者としては、早く修正して欲しい、早くCVEを取得したい、脆弱性を見つけたことを公開したい、という気持ちになりがちですが、メンテナとしてはOSSであれば修正する義務があるわけではありませんし、プロジェクトとしてしっかり管理されているものであればスケジュール外での対応となります。
メンテナをリスペクトしつつ、反応がない、動きが見えない期間を続いた場合には、現状のステータスを確認するリマインドをしてみましょう、進展があるかもしれません。
CVE-IDを発行して欲しい、Creditを載せて欲しいなどの要望を伝える
脆弱性を報告し、修正された場合でも常にCVEが付与される訳ではありません。
要望があれば、メンテナとのやりとりの中でCVEの発行をお願いしたり、Creditに載せてもらえるようにお願いしてみましょう。
私の場合は、CVEが発行され、Security Advisoryも公開された後にCreditを追加で明記してもらえるようにお願いしたところ、快く対応して頂きました。
そのため、事前にCVEの発行とCreditの明記を一緒にお願いすればよかったと思いました。
また、気をつけるべきポイントは、バグバウンティのように脆弱性報告に対する報酬を要求することはしてはいけません。
バグバウンティを行っているプロジェクトの場合には、対象のバグバウンティの報告窓口経由で行いましょう。
私が今回経験した中では上記が脆弱性報告時のポイントですが、それ以外にも報告窓口が見つからない場合や、報告しても対応してもらえないこともあると思います。
そのような場合も含めた、詳細な脆弱性報告のガイダンスとしてOWASP Cheat Sheet Series Vulnerability Disclosure Cheat Sheetがありますので、もし脆弱性を報告する時には参考にしてみると良いと思います。
タイムライン
Sockeye (CVE-2021-43811) 報告からCVE発行されるまでのタイムライン
- 2021/09/09 : sockeye 開発チームへ脆弱性報告
- 2021/09/16 : 反応がなかったため、再度連絡
- 2021/09/18 : 返信があり、既にこのプルリクで修正に着手しているとの返答
- 2021/10/22 : masterブランチへ修正がマージされる (コミット)
- 2021/11/05 : バージョン2.3.24としてリリース
- 2021/12/09 : CVE-2021-43811 として脆弱性が公開
nameko (CVE-2021-41078) 報告からCVE発行されるまでのタイムライン
- 2021/09/13 : nameko の脆弱性報告窓口(Tidelift)へ脆弱性報告
- 2021/09/14 : Tideliftより一次返答あり
- 2021/09/29 : masterブランチへ修正がマージされる (コミット)
- 2021/10/19 : バージョン2.14.0としてリリース、 CVE-2021-41078 として脆弱性が公開
さいごに
yamoryというサービスを提供しているため、日頃から多くのOSSの脆弱性を目にする機会が多く、自分も少しでもOSSに貢献できたら、と思っていました。
そのため、偶然ではありますがこのような形でOSSに貢献し、CVEの取得まで行うことができてよかったと思うと同時に、こういった情報をあまり見かけないので自分自身の備忘録や振り返りを兼ねて記事として書きました。
新たな脆弱性を見つけて報告する、バグバウンティをすることは世の中にとって良いことですが、報告を行うセキュリティエンジニアは報告される開発側のことも考えて行動する必要がありますし、報告を受ける側も報告した人へのリスペクトを持つことが必要です。
また、この記事は脆弱性を見つけるセキュリティエンジニア視点で書きましたが、もしかすると攻撃者も同様の視点を持っているかもしれません。
攻撃者に近い視点で見ることは、どのようなリスクがあるのか、そこからよりセキュアなものを作るためにはどうすれば良いのか、という視点としても利用できると思います。
セキュリティに関するイベントを開催しております。
1/26(水) 14:00 ~ 15:00に「【実演】Log4jの脆弱性へのハッキングデモと効果的な脆弱性対策の方法」を開催します。
ご興味のある方はぜひご参加ください。
yamoryでは、脆弱性管理サービスの無料トライアルを提供しています。
エンジニア・セキュリティエンジニアの募集もしております。こちらより応募お待ちしております。