131 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 用户命名空间
{{#include ../../../../banners/hacktricks-training.md}}
## 基本信息
用户命名空间是一个 Linux 内核特性,**提供用户和组 ID 映射的隔离**,允许每个用户命名空间拥有**自己的一组用户和组 ID**。这种隔离使得在不同用户命名空间中运行的进程**可以拥有不同的权限和所有权**,即使它们在数值上共享相同的用户和组 ID。
用户命名空间在容器化中特别有用,每个容器应该拥有自己独立的用户和组 ID 集,从而在容器与主机系统之间提供更好的安全性和隔离。
### 工作原理:
1. 当创建一个新的用户命名空间时,它**以一个空的用户和组 ID 映射集开始**。这意味着在新的用户命名空间中运行的任何进程**最初在命名空间外没有权限**。
2. 可以在新命名空间中的用户和组 ID 与父(或主机)命名空间中的 ID 之间建立 ID 映射。这**允许新命名空间中的进程拥有与父命名空间中的用户和组 ID 对应的权限和所有权**。然而ID 映射可以限制在特定范围和 ID 子集上,从而对新命名空间中进程授予的权限进行细粒度控制。
3. 在用户命名空间内,**进程可以在命名空间内拥有完全的 root 权限UID 0**,同时在命名空间外仍然拥有有限的权限。这允许**容器在其自己的命名空间内以类似 root 的能力运行,而不在主机系统上拥有完全的 root 权限**。
4. 进程可以使用 `setns()` 系统调用在命名空间之间移动,或使用带有 `CLONE_NEWUSER` 标志的 `unshare()``clone()` 系统调用创建新的命名空间。当进程移动到新命名空间或创建一个新命名空间时,它将开始使用与该命名空间关联的用户和组 ID 映射。
## 实验:
### 创建不同的命名空间
#### CLI
```bash
sudo unshare -U [--mount-proc] /bin/bash
```
通过挂载新的 `/proc` 文件系统实例,如果使用参数 `--mount-proc`,您可以确保新的挂载命名空间具有 **特定于该命名空间的进程信息的准确和隔离的视图**
<details>
<summary>错误bash: fork: 无法分配内存</summary>
`unshare` 在没有 `-f` 选项的情况下执行时,由于 Linux 处理新的 PID进程 ID命名空间的方式会遇到错误。关键细节和解决方案如下
1. **问题解释**
- Linux 内核允许进程使用 `unshare` 系统调用创建新的命名空间。然而,启动新 PID 命名空间创建的进程(称为 "unshare" 进程)并不会进入新的命名空间;只有它的子进程会进入。
- 运行 `%unshare -p /bin/bash%` 会在与 `unshare` 相同的进程中启动 `/bin/bash`。因此,`/bin/bash` 及其子进程位于原始 PID 命名空间中。
- 新命名空间中 `/bin/bash` 的第一个子进程成为 PID 1。当该进程退出时如果没有其他进程它会触发命名空间的清理因为 PID 1 具有收养孤儿进程的特殊角色。然后Linux 内核将禁用该命名空间中的 PID 分配。
2. **后果**
- 新命名空间中 PID 1 的退出导致 `PIDNS_HASH_ADDING` 标志的清理。这导致 `alloc_pid` 函数在创建新进程时无法分配新的 PID从而产生 "无法分配内存" 的错误。
3. **解决方案**
- 通过在 `unshare` 中使用 `-f` 选项可以解决此问题。此选项使 `unshare` 在创建新的 PID 命名空间后分叉一个新进程。
- 执行 `%unshare -fp /bin/bash%` 确保 `unshare` 命令本身在新命名空间中成为 PID 1。然后`/bin/bash` 及其子进程安全地包含在这个新命名空间中,防止 PID 1 的过早退出,并允许正常的 PID 分配。
通过确保 `unshare``-f` 标志运行,新的 PID 命名空间得以正确维护,使得 `/bin/bash` 及其子进程能够正常运行,而不会遇到内存分配错误。
</details>
#### Docker
```bash
docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash
```
要使用用户命名空间Docker 守护进程需要使用 **`--userns-remap=default`** 启动(在 Ubuntu 14.04 中,可以通过修改 `/etc/default/docker` 然后执行 `sudo service docker restart` 来完成)
### 检查您的进程在哪个命名空间中
```bash
ls -l /proc/self/ns/user
lrwxrwxrwx 1 root root 0 Apr 4 20:57 /proc/self/ns/user -> 'user:[4026531837]'
```
可以通过以下命令检查 Docker 容器中的用户映射:
```bash
cat /proc/self/uid_map
0 0 4294967295 --> Root is root in host
0 231072 65536 --> Root is 231072 userid in host
```
或从主机使用:
```bash
cat /proc/<pid>/uid_map
```
### 查找所有用户命名空间
```bash
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-number>
```
### 进入用户命名空间
```bash
nsenter -U TARGET_PID --pid /bin/bash
```
此外,您只能**以 root 身份进入另一个进程命名空间**。并且您**不能**在没有指向它的描述符的情况下**进入**其他命名空间(例如 `/proc/self/ns/user`)。
### 创建新的用户命名空间(带映射)
```bash
unshare -U [--map-user=<uid>|<name>] [--map-group=<gid>|<name>] [--map-root-user] [--map-current-user]
```
```bash
# 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
```
### 恢复能力
在用户命名空间的情况下,**当创建一个新的用户命名空间时,进入该命名空间的进程会被授予该命名空间内的完整能力集**。这些能力允许进程执行特权操作,例如**挂载** **文件系统**、创建设备或更改文件的所有权,但**仅在其用户命名空间的上下文中**。
例如,当您在用户命名空间内拥有 `CAP_SYS_ADMIN` 能力时,您可以执行通常需要此能力的操作,如挂载文件系统,但仅在您的用户命名空间的上下文中。您使用此能力执行的任何操作都不会影响主机系统或其他命名空间。
> [!WARNING]
> 因此,即使在新的用户命名空间内获取一个新进程**会让您恢复所有能力**CapEff: 000001ffffffffff您实际上**只能使用与命名空间相关的能力**(例如挂载),而不是所有能力。因此,仅凭这一点不足以逃离 Docker 容器。
```bash
# 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
```
{{#include ../../../../banners/hacktricks-training.md}}