从 posix_spawn() 函数窥探漏洞逃逸

posix_spawn() 函数是用来在Linux上创建子进程的,头文件是 #include <spawn.h></spawn.h> ,语法如下:

#include
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[]);

我们可以看到一共要传入六个参数,语法参数说明如下:

  • 子进程 pid(pid 参数指向一个缓冲区,该缓冲区用于返回新的子进程的进程ID)
  • 可执行文件的路径 path(其实就是可以调用某些系统命令,只不过要指定其完整路径)
  • file_actions 参数指向生成文件操作对象,该对象指定要在子对象之间执行的与文件相关的操作
  • attrp 参数指向一个属性对象,该对象指定创建的子进程的各种属性。
  • argv 和 envp 参数指定在子进程中执行的程序的参数列表和环境

详细文档可以通过 man posix_spawn 查看相关文档:

从 posix_spawn() 函数窥探漏洞逃逸

既然我们知道了这些参数,我们该如何利用这个呢?

我们先给一个 Demo 看看:

/*
* @Author: python
* @Date:   2020-01-12 17:28:31
* @Last Modified by:   python
* @Last Modified time: 2020-01-12 17:32:28
*/
#include
#include
#include
#include
#include
#include
/*
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;
}

运行结果如下图所示:

从 posix_spawn() 函数窥探漏洞逃逸

我们从结果可以看到, /bin/sh 的效果就类似于 sh 脚本中开头的 #!/bin/sh,指定了系统命令 sh 的路径, argv 就类似于 shell 脚本中要执行的代码,比如这里执行 sh -c cmd,而 cmd 参数由用户输入。

我们以 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 连接之后,会发现无论输入什么命令,你会发现输入的所有字母都被替换成了大写字母,没法进行任何操作。

在这里,我们不得不提到一个有意思的东西, $0

这个 $0 是什么东西呢,我们可以尝试打印一下:

从 posix_spawn() 函数窥探漏洞逃逸

我们可以看出, $0 事实上就是调用当前的 shell 了,是不是都是这样呢?

我们尝试自己写个例子看看:

从 posix_spawn() 函数窥探漏洞逃逸

我们可以看到,执行并且测试以后,发现输出的结果正好是当前脚本的名字,当前的 $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 函数来实现其功能的:

从 posix_spawn() 函数窥探漏洞逃逸

详细文档可以参考:https://docs.python.org/3/library/os.html

于是我们就可以进行如下更加简便的操作:

  1. 先调用 os.system 调用 C 语言中的 system 函数

从 posix_spawn() 函数窥探漏洞逃逸
  1. 然后执行 system 模块中的 posix_spawn 函数

从 posix_spawn() 函数窥探漏洞逃逸
  1. 最后调用当前的 shell

从 posix_spawn() 函数窥探漏洞逃逸

这道题目如果没有屏蔽掉黑名单的话,还是有其他解题思路的,可以直接通过通配符来解决问题,payload 如下:

/???/???/?38?

Original: https://www.cnblogs.com/ECJTUACM-873284962/p/12183348.html
Author: Angel_Kitty
Title: 从 posix_spawn() 函数窥探漏洞逃逸

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/551704/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Aviator 内置函数

    系统函数 函数名称 sysdate() 返回当前日期对象 java.util.Date rand() 返回一个介于 [0, 1) 的随机数,结果为 double 类型 rand(n…

    技术杂谈 2023年5月31日
    084
  • jetBrain IDE Plugins

    jetBrain IDE Plugins jetBrain IDE Plugins:Import CostIndent RainbowPrettierIDE Eval Reset …

    技术杂谈 2023年5月30日
    0101
  • 前后端分离,SpringBoot如何实现验证码操作

    验证码的功能是防止非法用户恶意去访问登录接口而设置的一个功能,今天我们就来看看在前后端分离的项目中,SpringBoot是如何提供服务的。 SpringBoot版本 本文基于的Sp…

    技术杂谈 2023年6月21日
    0113
  • 基本用法

    规则引擎的工作方式有点像if-else,它允许你设置一些条件和动作,然后在程序运行时判断某些动作该不该执行。easy-rules是一款轻量级的java规则引擎,目前它的长期支持版本…

    技术杂谈 2023年7月11日
    0125
  • day2

    螺旋矩阵|| 根本没有想到是用二分法的精髓来做!!!但是他是有序数组,其实可以考虑到循环不变量。要注意到奇数的情况今天时间没有留够,但是理解透彻了二分法的两种写法,以及它的注意事项…

    技术杂谈 2023年7月10日
    073
  • 【软考】易错选择题

    1.第01题:2018下半年系统集成项目管理工程师 工业和信息化部会同国务院有关部门编制的《信息化发展规划》提出了我国未来信息化发展指导思想和基本原则。其中,不包括( )原则。A:…

    技术杂谈 2023年5月31日
    093
  • Java线程的两种实现方式,以及它们之间的联系和区别

    Java线程的两种实现方式,以及它们之间的联系和区别 本文将从继承Thread类和实现Runnable接口讲起,并阐述它们的联系和区别。 实现方式1:继承Thread类,并重写ru…

    技术杂谈 2023年7月24日
    059
  • Python中的异常(Exception)

    以下 Python 版本为 Python 3.8.10 . 初探异常 错误: 语法错误 . 逻辑错误 . 异常:程序运行过程中,出现的意料之外的错误(大概类似 corner cas…

    技术杂谈 2023年7月24日
    073
  • 企业级开发平台的演进

    过去几年中,现代软件开发的整体环境发生了巨大的变化。回想在 2000 年代初期,产业的发展并没有那么快,技术和框架只是在稳步前进。而现在,技术发展的复杂度和多样性已经可以用超音速来…

    技术杂谈 2023年6月21日
    0115
  • Spark学习(3)SparkSQL

    什么事sparkSQL Spark SQL是Spark用来处理结构化数据的一个模块,它提供了一个编程抽象叫做DataFrame并且作为分布式SQL查询引擎的作用, 它是将Spark…

    技术杂谈 2023年7月24日
    081
  • Modern Cpp记录

    cpp;gutter:true;</p> <h1>include</h1> <p>include</p> <h1&…

    技术杂谈 2023年5月31日
    084
  • 如何在Oracle中复制表结构和表数据

    复制表结构及其数据: 只复制表结构: 或者: 只复制表数据: 如果两个表结构一样: 如果两个表结构不一样: Original: https://www.cnblogs.com/lc…

    技术杂谈 2023年5月31日
    077
  • DB2 8.2 9.1 9.5 9.7 下载地址(用迅雷防止官方下线文件)

    下列都是完全版包含补丁的地址 ,包含必备和并存补丁(稍后可取消选择不需要的补丁) DB2 8.2 Windows 32位: DB2 9.1 DB2 9.5 DB2 9.7 Orig…

    技术杂谈 2023年5月30日
    0126
  • 【JavaWeb-Ajax】笔记汇总 – 全局刷新和局部刷新;ajax 中使用 XMLHttpRequest 对象(四步);json 的使用

    1、全局刷新和局部刷新: 1)全局刷新:整个浏览器被新的数据覆盖,在网络中传输大量的数据(浏览器需要加载,渲染页面)。 2)局部刷新:在浏览器的内部,发起请求,获取数据,改变页面中…

    技术杂谈 2023年7月10日
    069
  • Mysql-强制改密

    MySQL V8.0.22 [mysqld] 跳过登录验证 skip-grant-tables use mysql; update user set authentication_…

    技术杂谈 2023年6月21日
    095
  • ds 校验某一个必填项字段

    场景: 通过 Step 组件,两个步骤中 Form,共用同一个 ds,希望步骤一中的指定字段没有填写时,禁止跳转下一步 思路: 通过 ds.checkValidity(record…

    技术杂谈 2023年5月30日
    084
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球