Shogo's Blog

Jun 18, 2023 - 3 minute read - github

GitHub経由で脆弱性報告してみた

lestrrat-go/jwxに脆弱性を発見したので報告しました。

「メールでやり取りするの面倒だなー」と思っていたら、いつのまにかGitHub経由で脆弱性報告できるようになってるじゃないですか。

というわけで試してみたお話です。

背景

脆弱性報告の難しさ

脆弱性に関する情報は悪い人に悪用される可能性があるので、GitHubのIssueで報告するのは厳禁です。 公開レポジトリのIssueは広く公開されているので、悪い人に見つかってしまいます。

そのため、基本的に脆弱性の報告者はメンテナーと直接やり取りをする必要があります。 しかし、やり取りの方法に決まったルールはありません。 GitHubではセキュリティーポリシーをSECURITY.mdに記載するルールになっているので、運が良ければSECURITY.mdに連絡先が書いてあります。

運が悪ければ連絡先を頑張って探すところからはじめなければなりません。

まあ、たいていは連絡先としてメールアドレスが見つかるので、そこにメールを送ることになります。 ただし、メールというものは脆弱性の報告に特化したものではないので、どうやって情報をやり取りするかお互いに工夫が必要です。 僕はやったことないですが、修正のパッチをメーリングリストに送るんですかね。 大変そうです。


脆弱性と聞けば、CVEのような脆弱性情報データベースや、IPAの脆弱性関連情報の届出受付を思い浮かべるひとも多いでしょう。

しかしこういった制度も、メンテナーの連絡先を管理しているわけではありません。 メンテナーの連絡先を探す手間も、メンテナーとのやり取りをする手間もかわりません。 (まあやったことないけど)

実際に報告した人のレポートにもありますが、「虎の威を借る」効果は多少期待できるでしょう。 CVEやIPAの名前だけ知っているというひとは多いでので、優先度を上げてくれるメンテナーも多いと思います。

逆に言えば、脆弱性レポートの段階では、その程度の効果しかありません。

脆弱性の概要

lestrrat-go/jwxのJWEのデコード機能を利用する場合に、本脆弱性の影響を受ける可能性があります。

AES-CBCで暗号化されたデーターを復号するにはパディングを取り除く必要があります。 このとき不正なパディングを見つけた場合に “failed to generate plaintext from decrypted blocks: invalid padding” というエラーを返す実装になっていました。

// https://github.com/lestrrat-go/jwx/blob/8840ffd4afc5839f591ff0e9ba9034af52b1643e/jwe/internal/aescbc/aescbc.go#L210-L213
	plaintext, err := unpad(buf, c.blockCipher.BlockSize())
	if err != nil {
		return nil, fmt.Errorf(`failed to generate plaintext from decrypted blocks: %w`, err)
	}

パディングの検証結果をエラーとして返してしまうと、パディングオラクル攻撃を受ける可能性があります。

ライブラリの利用者としては、エラーの内容について詳しいレポートがあるのはうれしいです。 しかし、セキュリティーに関わる文脈では、エラーの内容も攻撃材料に使われてしまうので、慎重にエラー報告しなければなりません。

RFC 7516 JSON Web Encryption (JWE)にも実装時の考慮事項として、 このようなエラーは報告「してはなりません(MUST NOT)」と書いてあります。 (僕もこの脆弱性報告を書いていてはじめてRFCに記載があることを知った・・・)

11.5. Timing Attacks To mitigate the attacks described in RFC 3218 [RFC3218], the recipient MUST NOT distinguish between format, padding, and length errors of encrypted keys. It is strongly recommended, in the event of receiving an improperly formatted key, that the recipient substitute a randomly generated CEK and proceed to the next step, to mitigate timing attacks.

報告の流れ

今までの脆弱性報告では、まず「連絡先を探す」というハードルがありました。 GitHubの脆弱性レポート機能を使えばGitHubが代わりにメンテナーへ連絡してくれるので、連絡先を探す手間はありません。

レポートにはGitHubの便利な機能もそのまま使えます。 だいたいドキュメントに書いてあるとおりですが、見ていきましょう。

Security Advisoryを作成する

GitHubレポジトリのSecurityタブから「Report a vulnerability」というボタンを押すと、Security Advisoryを作成できます。 レポジトリごとの設定で無効化できてしまうので、万が一このボタンが表示されない場合は、諦めてメンテナーの連絡先を探しましょう。

脆弱性の概要・詳細・PoCなどを入力します。

Advisory Details

僕の場合は以下の内容で報告しました。

### Summary

Decrypting AES-CBC encrypted JWE has Potential Padding Oracle Attack Vulnerability.

### Details

On [v2.0.10](https://github.com/lestrrat-go/jwx/releases/tag/v2.0.10), decrypting AES-CBC encrypted JWE may return an error "failed to generate plaintext from decrypted blocks: invalid padding":

https://github.com/lestrrat-go/jwx/blob/8840ffd4afc5839f591ff0e9ba9034af52b1643e/jwe/internal/aescbc/aescbc.go#L210-L213

Reporting padding error causes [Padding Oracle Attack](https://en.wikipedia.org/wiki/Padding_oracle_attack) Vulnerability.
RFC 7516 JSON Web Encryption (JWE) says that we **MUST NOT** do this.

> 11.5.  Timing Attacks
> To mitigate the attacks described in RFC 3218 [RFC3218], the
> recipient MUST NOT distinguish between format, padding, and length
> errors of encrypted keys.  It is strongly recommended, in the event
> of receiving an improperly formatted key, that the recipient
> substitute a randomly generated CEK and proceed to the next step, to
> mitigate timing attacks.

In addition, the time to remove padding depends on the length of the padding.
It may leak the length of the padding by Timing Attacks.

https://github.com/lestrrat-go/jwx/blob/796b2a9101cf7e7cb66455e4d97f3c158ee10904/jwe/internal/aescbc/aescbc.go#L33-L66

To mitigate Timing Attacks, it MUST be done in constant time.

### Impact

The authentication tag is verified, so it is not an immediate attack.

報告すると、報告者とメンテナーのみ閲覧可能な状態になります。

一時的なプライベートレポジトリを作成する

「Start a temporary private fork」をクリックすると、非公開のレポジトリをフォークしてくれます。 通常のレポジトリと同じようにgit cloneして、修正をコミットしましょう。

Start a temporary private fork

プルリクエストも送ることができます。 upstreamに対してプルリクエストを送ると普通はフォーク元でプルリクエストが公開されますが、 プライベートレポジトリから送ったプルリクエストは非公開のままです。 以下の画像はお試しでgo-sfvのレポジトリでプルリクエストを作成してみた様子です。

Comparing changes

メンテナーからのリアクションを待つ

メンテナーが脆弱性に対応してくれるのを待ちます。 僕の場合はその日のうちに@lestrratが反応して、修正をマージしてくれました。 いつ返信が返ってくるかはメンテナーの気分次第なので、気長に待ちましょう。

送った脆弱性レポートは、メンテナーが内容をチェックして修正したのち公開されます。 公開時に報告者宛に「Reporterとして公開していいか?」とGitHubからメッセージが来るので、名前を公開していい人は許諾します。

まとめ

GitHubの脆弱性レポート機能を体験してみました。 いつも通りプルリクエストを送る感覚で報告できて便利でした。

今回僕は報告者という立場でしたが、 ソフトウェアをメンテナーをやっているひとは、settings/security_analysisからレポート受付を有効化しておくと良いでしょう。

Setting: Private vulnerability reporting

あれ、GAのブログ記事が公開されたけど、Betaのまま・・・?

参考