# euid, ruid, suid
从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS Red Team Expert)!
* 您在**网络安全公司**工作吗? 想要看到您的**公司在HackTricks中做广告**吗? 或者想要访问**PEASS的最新版本或下载PDF格式的HackTricks**吗? 请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 探索[**PEASS Family**](https://opensea.io/collection/the-peass-family),我们独家[NFTs的收藏品**](https://opensea.io/collection/the-peass-family)
* 获取[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
* **加入** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或在**Twitter**上**关注**我 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* **通过向[hacktricks repo](https://github.com/carlospolop/hacktricks)和[hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)提交PR来分享您的黑客技巧**。
### 用户识别变量
- **`ruid`**:**真实用户ID**表示启动进程的用户。
- **`euid`**:被称为**有效用户ID**,代表系统用于确定进程特权的用户身份。通常情况下,`euid`与`ruid`相同,除了像执行SetUID二进制文件这样的情况,其中`euid`会承担文件所有者的身份,从而授予特定的操作权限。
- **`suid`**:这个**保存的用户ID**在高特权进程(通常以root身份运行)需要暂时放弃特权以执行某些任务时至关重要,然后再恢复其初始的提升状态。
#### 重要说明
一个未以root身份运行的进程只能修改其`euid`以匹配当前的`ruid`、`euid`或`suid`。
### 理解set*uid函数
- **`setuid`**:与最初的假设相反,`setuid`主要修改`euid`而不是`ruid`。特别是对于特权进程,它将`ruid`、`euid`和`suid`与指定用户(通常是root)对齐,有效地由于覆盖`suid`而巩固这些ID。详细见[setuid man页面](https://man7.org/linux/man-pages/man2/setuid.2.html)。
- **`setreuid`**和**`setresuid`**:这些函数允许对`ruid`、`euid`和`suid`进行微妙的调整。但是,它们的功能取决于进程的特权级别。对于非root进程,修改受限于`ruid`、`euid`和`suid`的当前值。相反,具有`CAP_SETUID`能力的root进程或这些进程可以将这些ID分配任意值。更多信息请参阅[setresuid man页面](https://man7.org/linux/man-pages/man2/setresuid.2.html)和[setreuid man页面](https://man7.org/linux/man-pages/man2/setreuid.2.html)。
这些功能的设计不是作为安全机制,而是为了促进预期的操作流程,例如当程序通过更改其有效用户ID采用另一个用户的身份时。
值得注意的是,虽然`setuid`可能是提升到root的特权的常见选择(因为它将所有ID都与root对齐),但区分这些函数对于理解和操纵不同情况下的用户ID行为至关重要。
### Linux中的程序执行机制
#### **`execve`系统调用**
- **功能**:`execve`启动一个由第一个参数确定的程序。它接受两个数组参数,`argv`用于参数,`envp`用于环境。
- **行为**:保留调用者的内存空间,但刷新堆栈、堆和数据段。程序的代码被新程序替换。
- **用户ID保留**:
- `ruid`、`euid`和附加组ID保持不变。
- 如果新程序设置了SetUID位,`euid`可能会有微妙的变化。
- `suid`在执行后从`euid`更新。
- **文档**:详细信息请参阅[`execve` man页面](https://man7.org/linux/man-pages/man2/execve.2.html)。
#### **`system`函数**
- **功能**:与`execve`不同,`system`使用`fork`创建一个子进程,并在该子进程中使用`execl`执行命令。
- **命令执行**:通过`execl("/bin/sh", "sh", "-c", command, (char *) NULL);`执行命令。
- **行为**:由于`execl`是`execve`的一种形式,它的操作类似,但在新的子进程的上下文中进行。
- **文档**:更多见[`system` man页面](https://man7.org/linux/man-pages/man3/system.3.html)。
#### **`bash`和`sh`在SUID下的行为**
- **`bash`**:
- 具有`-p`选项影响`euid`和`ruid`的处理方式。
- 没有`-p`,如果`bash`最初设置`euid`与`ruid`不同,则将`euid`设置为`ruid`。
- 使用`-p`,保留初始`euid`。
- 更多细节请参阅[`bash` man页面](https://linux.die.net/man/1/bash)。
- **`sh`**:
- 不具有类似于`bash`中的`-p`机制。
- 关于用户ID的行为没有明确说明,除了在`-i`选项下,强调保持`euid`和`ruid`的相等性。
- 更多信息请参阅[`sh` man页面](https://man7.org/linux/man-pages/man1/sh.1p.html)。
这些机制在操作上各有不同,为执行和在程序之间转换提供了多样的选项,特定情况下对用户ID的管理和保留方式也有特定的细微差别。
### 在执行中测试用户ID行为
示例取自https://0xdf.gitlab.io/2022/05/31/setuid-rabbithole.html#testing-on-jail,查看更多信息
#### 情况1:使用`setuid`与`system`
**目标**:了解`setuid`与`system`和`bash`作为`sh`结合的效果。
**C代码**:
```c
#define _GNU_SOURCE
#include
#include
int main(void) {
setuid(1000);
system("id");
return 0;
}
```
**编译和权限:**
```bash
oxdf@hacky$ gcc a.c -o /mnt/nfsshare/a;
oxdf@hacky$ chmod 4755 /mnt/nfsshare/a
```
```bash
bash-4.2$ $ ./a
uid=99(nobody) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0
```
**分析:**
* `ruid` 和 `euid` 起始值分别为 99 (nobody) 和 1000 (frank)。
* `setuid` 将两者都设置为 1000。
* 由于从 sh 到 bash 的符号链接,`system` 执行 `/bin/bash -c id`。
* `bash` 在没有 `-p` 的情况下,调整 `euid` 以匹配 `ruid`,导致两者都变为 99 (nobody)。
#### 情况 2: 使用 setreuid 与 system
**C 代码**:
```c
#define _GNU_SOURCE
#include
#include
int main(void) {
setreuid(1000, 1000);
system("id");
return 0;
}
```
**编译和权限:**
```bash
oxdf@hacky$ gcc b.c -o /mnt/nfsshare/b; chmod 4755 /mnt/nfsshare/b
```
**执行和结果:**
```bash
bash-4.2$ $ ./b
uid=1000(frank) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0
```
**分析:**
* `setreuid` 将 ruid 和 euid 都设置为 1000。
* `system` 调用 bash,由于它们相等,有效地作为 frank 运行。
#### 情况 3: 使用 setuid 与 execve
目标: 探索 setuid 和 execve 之间的交互。
```bash
#define _GNU_SOURCE
#include
#include
int main(void) {
setuid(1000);
execve("/usr/bin/id", NULL, NULL);
return 0;
}
```
**执行和结果:**
```bash
bash-4.2$ $ ./c
uid=99(nobody) gid=99(nobody) euid=1000(frank) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0
```
**分析:**
* `ruid` 保持为99,但 `euid` 被设置为1000,符合 `setuid` 的效果。
**C 代码示例 2 (调用 Bash):**
```bash
#define _GNU_SOURCE
#include
#include
int main(void) {
setuid(1000);
execve("/bin/bash", NULL, NULL);
return 0;
}
```
**执行和结果:**
```bash
bash-4.2$ $ ./d
bash-4.2$ $ id
uid=99(nobody) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0
```
**分析:**
* 尽管`setuid`将`euid`设置为1000,但由于缺少`-p`,`bash`会将euid重置为`ruid`(99)。
**C代码示例3(使用bash -p):**
```bash
#define _GNU_SOURCE
#include
#include
int main(void) {
char *const paramList[10] = {"/bin/bash", "-p", NULL};
setuid(1000);
execve(paramList[0], paramList, NULL);
return 0;
}
```
**执行和结果:**
```bash
bash-4.2$ $ ./e
bash-4.2$ $ id
uid=99(nobody) gid=99(nobody) euid=100
```
## 参考资料
* [https://0xdf.gitlab.io/2022/05/31/setuid-rabbithole.html#testing-on-jail](https://0xdf.gitlab.io/2022/05/31/setuid-rabbithole.html#testing-on-jail)
从零开始学习AWS黑客技术 htARTE (HackTricks AWS Red Team Expert)!
* 您在**网络安全公司**工作吗? 想要看到您的**公司在HackTricks中做广告**? 或者您想要访问**PEASS的最新版本或下载HackTricks的PDF**? 请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 发现我们的独家[NFTs收藏品**The PEASS Family**](https://opensea.io/collection/the-peass-family)
* 获取[**官方PEASS & HackTricks周边**](https://peass.creator-spring.com)
* **加入** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或在**Twitter**上关注我 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **通过向[hacktricks repo](https://github.com/carlospolop/hacktricks)和[hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)提交PR来分享您的黑客技巧**。