posix_spawn() 函数是用来在Linux上建立子进程的,头文件是 #include <spawn.h>
,语法以下:html
#include <spawn.h> int posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]);
咱们能够看到一共要传入六个参数,语法参数说明以下:python
详细文档能够经过 man posix_spawn
查看相关文档:shell
既然咱们知道了这些参数,咱们该如何利用这个呢?ubuntu
咱们先给一个 Demo 看看:函数
/* * @Author: python * @Date: 2020-01-12 17:28:31 * @Last Modified by: python * @Last Modified time: 2020-01-12 17:32:28 */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <spawn.h> #include <sys/wait.h> /* int posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]); */ extern char **environ; void run_cmd(char *cmd) { pid_t pid; char *argv[] = {"sh", "-c", cmd, NULL}; int status; printf("Run command: %s\n", cmd); status = posix_spawn(&pid, "/bin/sh", NULL, NULL, argv, environ); if (status == 0) { printf("Child pid: %i\n", pid); if (waitpid(pid, &status, 0) != -1) { printf("Child exited with status %i\n", status); } else { perror("waitpid"); } } else { printf("posix_spawn: %s\n", strerror(status)); } } int main(int argc, char* argv[]) { run_cmd(argv[1]); return 0; }
运行结果以下图所示:测试
咱们从结果能够看到,/bin/sh
的效果就相似于 sh 脚本中开头的 #!/bin/sh
,指定了系统命令 sh 的路径,argv
就相似于 shell 脚本中要执行的代码,好比这里执行 sh -c cmd
,而 cmd 参数由用户输入。spa
咱们以 xman 第三界冬令营选拔赛 shellmaster 为例,因为环境已经宕机了,因此我找出题人拿到了源码,有兴趣的能够尝试用源码从新复现一下环境。线程
import os import sys import time blacklist = [ "$", "-", "_", "{", "}", "*", "2", "4" ] def handler(): print "Oops, are you a master?" os._exit(0) print "Welcome to shell master!" print "Start to wake up the shell ..." time.sleep(3) sys.stdout.flush() while True: sys.stdout.write("master@ubuntu:~$ ") sys.stdout.flush() cmd = raw_input().upper() ''' for i in blacklist: if i in cmd: print "blacklist: "+i handler() if len(cmd) > 16: print "len:"+len(cmd) handler() ''' cmd += " 2>&1" print os.system(cmd)
咱们从源码能够看到,输入的命令中全部字母都被替换成了大写字母,因此你若是经过 nc 链接以后,会发现不管输入什么命令,你会发现输入的全部字母都被替换成了大写字母,无法进行任何操做。code
在这里,咱们不得不提到一个有意思的东西,$0
。htm
这个 $0
是什么东西呢,咱们能够尝试打印一下:
咱们能够看出,$0
事实上就是调用当前的 shell 了,是否是都是这样呢?
咱们尝试本身写个例子看看:
咱们能够看到,执行而且测试之后,发现输出的结果正好是当前脚本的名字,当前的 $0
就是 ./test.sh
。
咱们从以上这个例子能够看出,在 shell 脚本中,经过使用 $0
就能够获取到脚本的名字或者说脚本自己。
既然这玩意能直接调用当前的 shell,利用方式就有不少种了。
咱们能够经过 posix_spawn
这个函数,建立一个子进程,这个子进程能够是系统的默认的命令(进程实质上就是一个程序嘛),这个子进程若是调用的是当前的 shell,咱们就能够直接利用这个 shell 来获取相关权限的信息,从而实现逃逸这一过程。
咱们能够尝试经过系统的一些方法传入 $0
来实现逃逸这一过程。
那咱们既然已经知道了这一点,咱们就能够尝试去
那么何时会调用
posix_spawn
函数?因为
posix_spawn
函数是C
语言中system.c
建立线程默认调用的功能模块。
C 源码官方下载:http://ftp.gnu.org/gnu/libc/,定义 system 的 c 文件在 glibc/sysdeps/posix/system.c
,固然咱们也能够在 https://code.woboq.org/userspace/glibc/sysdeps/posix/system.c.html 在线查看。
到这里为止,咱们基本思路已经很清楚了,咱们能够经过使用 system 模块来调用 posix_spawn 函数来建立子进程,让这个子进程调用当前的 shell,也就是使用 $0
,而后获取到相关的权限信息,实现逃逸这一过程。咱们能够直接写相关的 C 程序来解决。
而在 python 中,os.system 是经过调用 C 语言中的 system 函数来实现其功能的:
详细文档能够参考:https://docs.python.org/3/library/os.html
因而咱们就能够进行以下更加简便的操做:
这道题目若是没有屏蔽掉黑名单的话,仍是有其余解题思路的,能够直接经过通配符来解决问题,payload 以下:
/???/???/?38?