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?