CVE-2020-25637
*** 説明 ***
実行中の QEMU ドメインのネットワークインターフェース情報を要求する libvirt API(バージョン 6.8.0 より前)に、二重解放 (double free) の問題が発生しました。この脆弱性は、ポリシー制御ドライバー (polkit) に影響を与えます。具体的には、読み書きソケットに接続し、ACL 権限が制限されたクライアントが、この脆弱性を利用して libvirt デーモンをクラッシュさせ、サービス拒否 (DoS) を引き起こしたり、システム上で権限を昇格させる可能性があります。この脆弱性の最大の脅威は、データの機密性、完全性、およびシステムの可用性に関するものです。
この脆弱性の最大の脅威は以下の通りです:
脆弱性スコア:
RedHat による中程度の脆弱性、平均スコア 6.4
NVD による中程度の脆弱性、平均スコア 6.7
*** この脆弱性を悪用するために必要な異なるツールと重要な前提条件 ***
まず、オペレーティングシステムの互換性を確認する必要があります。以下のコマンドを実行します。
grep -E -c "vmx|svm" /proc/cpuinfo
コマンドが OK を返したら、インストールを続行できます。
sudo apt-get -y install qemu-kvm libvirt-bin virt-top outils-libguestfs virtinst bridge-utils
2) vagrant のインストール:
vagrant をインストールするには、以下のコマンドを実行します。
sudo apt -y install vagrant
Vagrant と KVM をインストールしたら、Vagrant を使用して KVM 仮想マシンを管理できるようにするための libvirt プラグインをインストールする準備が整います。
vagrant plugin install vagrant-libvirt
プラグインがインストールされたことを確認できます。
vagrant plugin list
3) vagrant ボックス:
Vagrant で既製のテンプレートを直接使用することが可能です。ここでは Ubuntu 20.04 イメージを使用します。
イメージを vagrant ボックスに追加するには、以下のコマンドを実行します。
vagrant box add generic / ubuntu1804 --provider = libvirt
ローカルに存在するボックスのリストを表示するには:
vagrant box list
4) デバッグ
デバッグには2つの方法があります。
GDB:オペレーティングシステムにツールがインストールされていない場合は、以下のコマンドを実行します。
sudo apt-get install gdb
Valgrind:オペレーティングシステムにツールがインストールされていない場合は、以下のコマンドを実行します。
sudo apt-get install valgrind
*** コードの実行 ***
Vagrant 経由で VM を起動します。
vagrant up
まず、ライブラリをインストールします。
sudo apt-get install -y libvirt-dev
コンパイル:
gcc -g -Wall info1.c -o info1 -lvirt
コードの実行:
./info1 qemu:///system vagrant-vms_ubuntu-01
デバッグ付きでの実行:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt ./info1 qemu:///system vagrant-vms_ubuntu-01
*** 脆弱性の有効化 ***
脆弱性を有効にする前に、libvirt で問題を引き起こす関数の動作を理解することが不可欠です。
攻撃者は、libvirt の qemuAgentGetInterfaces() 関数を介して、解放済みメモリ領域の使用 (use-after-free) を引き起こす可能性があると仮定します。具体的には、ifname 変数のメモリ領域で、サービス拒否 (DoS) を引き起こし、場合によってはコードを実行する可能性があります。
待望の瞬間がやってきました。
Vagrant ファイルが起動したら、Qemu/KVM で起動した仮想マシン内で info1.c コードを実行する必要があります。つまり、Vagrant が作成した VM 内でコードを実行する、VM の中に VM を作成するということです。
*** この脆弱性の修正 ***
libvirt の qemuAgentGetInterfaces() 関数内で ifname 変数を NULL に設定するだけです。つまり、ifname 変数は各インターフェースごとに解放される必要があります。
*** デモンストレーション ***
PowerPoint ファイルに、問題 (double free) の簡単なデモンストレーションがあります。
*** 重要 ***
このプロジェクトは、脆弱性の複雑さ、ハードウェアの問題、および時間不足の理由により、完了には至っていません。