Plan 9とGo言語のブログ

主にPlan 9やGo言語の日々気づいたことを書きます。

Git credentialプロトコルの脆弱性(CVE-2020-5260)を眺めた

Gitは認証の必要なリポジトリへアクセスするとき、ユーザ名とパスワード入力を必要としますが、アクセスするたび入力するのは煩わしいので、資格情報を記憶するために、git-credential-から始まる名前のカスタムヘルパーコマンドが存在します。これらカスタムヘルパーはGitから標準入出力を扱う普通のコマンドで、標準入力経由でGitから渡されたパラメータに従って、対応するパスワードを標準出力を介してGitへ返します。ヘルパーコマンドが呼ばれるルールはgitcredentials(7)に書かれています。

これらのヘルパーコマンドとGitの間で使われるプロトコルがGit credentialプロトコルです。プロトコルは1行に1つのキーバリューが書かれるテキストプロトコルで、リクエストは空行で終わります。ヘルパーコマンドは空行までを読み取って、不足しているパラメータ(通常はパスワードだけ)を返します。これらのパラメータはリポジトリのURLから生成されます。以下はGit credentialプロトコルでパスワードを取得するときの例です。

protocol=https
host=github.com
username=lufia

password=xxx

macOSを使っている場合は、以下のようにするとKeychainからパスワードを取り出せます。最後の空行を忘れないようにしましょう。

% `git --exec-path`/git-credential-osxkeychain get
protocol=https
host=github.com
username=lufia

CVE-2020-5260

日本時間だと4/15 3:00頃にGit 2.26.1がリリースされました。このリリースでCVE-2020-5260というGit credentialプロトコル脆弱性が修正されました。

上記でみたように、Git credentialプロトコルは改行文字でパラメータを区切ります。ところでURLはパーセントエンコーディングされた値を一部の場所で使うことができるため、https://host?%0aのように改行文字も与えることができてしまいます。そしてややこしいことに、Gitはcredentialプロトコルで扱うURLのパースを厳密には行っていません。そのため、外部からプロトコルへ介入することができてしまいます。例えば以下の場合、

https://evil.example.com?%0agithub.com/xxx

Git 2.26.0までは、Gitは%0aをデコードしてヘルパーコマンドへ渡すため、

protocol=https
host=evil.example.com
host=github.com

のようにhost=パラメータが2回現れます。同じパラメータが届いた場合は後勝ちなのでhost=github.comのパスワードがGitへ戻されますが、しかしGitが実際に通信するリポジトリのホストはevil.example.comなので、パスワードが漏れてしまって非常にまずいですね、という脆弱性です。

影響

ヘルパーコマンドは、git-remote-httpリポジトリへアクセスするとき、またはgit imap-sendでパッチを送るときに使われるようでした。そのため、影響を受けるプロトコルは現代ではhttpsがほとんどでしょう。ssh経由でアクセスしている場合はgit-remote-httpを使わないので、おそらく影響しないと思われます(間違っていたら指摘ください)。ただし、SourceTreeなどGitクライアントや、場合によってはHomebrewやGoコンパイラなど、裏でGitコマンドを使っている場合も対象となるので注意が必要です。

やるべきこと

脆弱性が修正されたバージョンにGitをアップデートしましょう。Git credentialのヘルパーコマンドを全て無効化する方法もあるようですが、絶対にアップデートする方が簡単です。

パスワードは変更した方が良いのか

信用できるリポジトリしか扱わない前提があれば、パスワードの変更は不要だとは思いますが、少しでも不安なら変更した方が安全だと思います。