基本情報
ユーザー名前空間は、ユーザーおよびグループIDのマッピングの隔離を提供する Linuxカーネルの機能であり、各ユーザー名前空間が独自のユーザーおよびグループIDのセット を持つことを可能にします。この隔離により、異なるユーザー名前空間で実行されているプロセスは、同じユーザーおよびグループIDを数値的に共有していても、異なる特権と所有権を持つことができます 。
ユーザー名前空間は、各コンテナが独自の独立したユーザーおよびグループIDのセットを持つべきコンテナ化に特に便利であり、コンテナとホストシステム間のセキュリティと隔離を向上させます。
仕組み:
新しいユーザー名前空間が作成されると、ユーザーおよびグループIDのマッピングの空のセット から始まります。これは、新しいユーザー名前空間で実行されるプロセスが名前空間の外で特権を持たない ことを意味します。
新しい名前空間のユーザーおよびグループIDと親(またはホスト)名前空間のIDとの間にIDマッピングを確立できます。これにより、新しい名前空間のプロセスが親名前空間のユーザーおよびグループIDに対応する特権と所有権を持つことができます 。ただし、IDマッピングは特定の範囲やIDのサブセットに制限でき、名前空間内のプロセスに付与される特権を細かく制御できます。
ユーザー名前空間内では、プロセスは名前空間内の操作に対して完全なルート特権(UID 0)を持つことができます が、名前空間の外では制限された特権を持ちます。これにより、コンテナはホストシステム上で完全なルート特権を持たずに、自身の名前空間内でルートのような機能を持って実行できます 。
プロセスはsetns()
システムコールを使用して名前空間間を移動したり、unshare()
またはclone()
システムコールをCLONE_NEWUSER
フラグと共に使用して新しい名前空間を作成したりできます。プロセスが新しい名前空間に移動するか、新しい名前空間を作成すると、その名前空間に関連付けられたユーザーおよびグループIDのマッピングを使用し始めます。
ラボ:
異なる名前空間を作成する
CLI
Copy sudo unshare -U [--mount-proc] /bin/bash
新しいインスタンスの /proc
ファイルシステムを --mount-proc
パラメータを使用してマウントすることで、新しいマウント名前空間がその名前空間に特有のプロセス情報の正確で隔離されたビュー を持つことを保証します。
エラー: bash: fork: メモリを割り当てることができませんunshare
が -f
オプションなしで実行されると、Linux が新しい PID (プロセス ID) 名前空間を処理する方法のためにエラーが発生します。重要な詳細と解決策は以下の通りです:
Linux カーネルはプロセスが unshare
システムコールを使用して新しい名前空間を作成することを許可します。しかし、新しい PID 名前空間の作成を開始するプロセス(「unshare」プロセスと呼ばれる)は新しい名前空間に入らず、その子プロセスのみが入ります。
%unshare -p /bin/bash%
を実行すると、unshare
と同じプロセスで /bin/bash
が開始されます。その結果、/bin/bash
とその子プロセスは元の PID 名前空間に存在します。
新しい名前空間内の /bin/bash
の最初の子プロセスは PID 1 になります。このプロセスが終了すると、他にプロセスがない場合、名前空間のクリーンアップがトリガーされます。PID 1 は孤児プロセスを引き取る特別な役割を持っているためです。Linux カーネルはその名前空間での PID 割り当てを無効にします。
新しい名前空間内での PID 1 の終了は PIDNS_HASH_ADDING
フラグのクリーンアップを引き起こします。これにより、新しいプロセスを作成する際に alloc_pid
関数が新しい PID を割り当てることに失敗し、「メモリを割り当てることができません」というエラーが発生します。
この問題は、unshare
に -f
オプションを使用することで解決できます。このオプションは、unshare
が新しい PID 名前空間を作成した後に新しいプロセスをフォークします。
%unshare -fp /bin/bash%
を実行すると、unshare
コマンド自体が新しい名前空間内で PID 1 になります。これにより、/bin/bash
とその子プロセスはこの新しい名前空間内に安全に収容され、PID 1 の早期終了を防ぎ、通常の PID 割り当てを可能にします。
unshare
が -f
フラグで実行されることを保証することで、新しい PID 名前空間が正しく維持され、/bin/bash
とそのサブプロセスがメモリ割り当てエラーに遭遇することなく動作できるようになります。
Docker
Copy docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash
ユーザー名前空間を使用するには、Dockerデーモンを**--userns-remap=default
**で起動する必要があります(Ubuntu 14.04では、/etc/default/docker
を修正し、その後sudo service docker restart
を実行することで行えます)
プロセスがどの名前空間にあるかを確認する
Copy ls -l /proc/self/ns/user
lrwxrwxrwx 1 root root 0 Apr 4 20:57 /proc/self/ns/user - > 'user:[4026531837]'
dockerコンテナからユーザーマップを確認することができます:
Copy cat /proc/self/uid_map
0 0 4294967295 -- > Root is root in host
0 231072 65536 -- > Root is 231072 userid in host
ホストからは:
Copy cat /proc/ < pi d > /uid_map
すべてのユーザー名前空間を見つける
Copy sudo find /proc -maxdepth 3 -type l -name user -exec readlink {} \; 2> /dev/null | sort -u
# Find the processes with an specific namespace
sudo find /proc -maxdepth 3 -type l -name user -exec ls -l {} \; 2> /dev/null | grep < ns-numbe r >
ユーザー名前空間に入る
Copy nsenter -U TARGET_PID --pid /bin/bash
また、ルートでない限り他のプロセス名前空間に入ることはできません 。そして、ディスクリプタ がそれを指していない限り、他の名前空間に入ることはできません (例えば /proc/self/ns/user
のように)。
新しいユーザー名前空間を作成する(マッピング付き)
Copy unshare -U [--map-user=<uid> |< name > ] [--map-group =< gid >|< name > ] [--map-root-user] [--map-current-user]
Copy # Container
sudo unshare -U /bin/bash
nobody@ip-172-31-28-169:/home/ubuntu$ #Check how the user is nobody
# From the host
ps -ef | grep bash # The user inside the host is still root, not nobody
root 27756 27755 0 21:11 pts/10 00:00:00 /bin/bash
Recovering Capabilities
ユーザー名前空間の場合、新しいユーザー名前空間が作成されると、その名前空間に入るプロセスには完全な権限のセットが付与されます 。これらの権限により、プロセスはファイルシステムのマウント 、デバイスの作成、ファイルの所有権の変更などの特権操作を実行できますが、そのユーザー名前空間のコンテキスト内でのみ 実行できます。
例えば、ユーザー名前空間内でCAP_SYS_ADMIN
権限を持っている場合、ファイルシステムのマウントなど、この権限を通常必要とする操作を実行できますが、あなたのユーザー名前空間のコンテキスト内でのみです。この権限を使用して実行する操作は、ホストシステムや他の名前空間には影響しません。
したがって、新しいユーザー名前空間内に新しいプロセスを取得することがすべての権限を取り戻すことになります (CapEff: 000001ffffffffff)が、実際には名前空間に関連するもののみを使用できます (例えばマウント)が、すべてではありません。したがって、これだけではDockerコンテナから脱出するには不十分です。
Copy # There are the syscalls that are filtered after changing User namespace with:
unshare -UmCpf bash
Probando: 0x067 . . . Error
Probando: 0x070 . . . Error
Probando: 0x074 . . . Error
Probando: 0x09b . . . Error
Probando: 0x0a3 . . . Error
Probando: 0x0a4 . . . Error
Probando: 0x0a7 . . . Error
Probando: 0x0a8 . . . Error
Probando: 0x0aa . . . Error
Probando: 0x0ab . . . Error
Probando: 0x0af . . . Error
Probando: 0x0b0 . . . Error
Probando: 0x0f6 . . . Error
Probando: 0x12c . . . Error
Probando: 0x130 . . . Error
Probando: 0x139 . . . Error
Probando: 0x140 . . . Error
Probando: 0x141 . . . Error
hacking tricks by submitting PRs to the** HackTricks and HackTricks Cloud github repos.