可以发现 flag 是写在一个文件中, 且存在一个 baby.ko 驱动模块, 那么漏洞应该存在在 baby.ko 中
checksec baby.ko
➜ 0ctf-final-baby checksec baby.ko [*] '/mnt/d/Users/Lantern/Desktop/note/pwn_note/kernal/linux_kernel_pwn-master/0ctf2018-final-baby/0ctf-final-baby/baby.ko' Arch: amd64-64-little RELRO: No RELRO Stack: No canary found NX: NX enabled PIE: No PIE(0x0)
用 IDA 打开驱动文件进行分析, flag 是硬编码在驱动文件中的
.data:0000000000000480 flag dq offset aFlagThisWillBe .data:0000000000000480 ; DATA XREF: baby_ioctl+2A↑r .data:0000000000000480 ; baby_ioctl+DB↑r ... .data:0000000000000480 ; "flag{THIS_WILL_BE_YOUR_FLAG_1234}" .data:0000000000000488 align 20h
驱动主要注册了一个 baby_ioctl 函数,其中包含两个功能。当 ioctl 中 cmd 参数为 0x6666 时,驱动将输出 flag 的加载地址。当 ioctl 中 cmd 参数为 0x1337 时,首先进行三个校验,接着对用户输入的内容与硬编码的 flag 进行逐字节比较,当一致时通过 printk 将 flag 输出出来。
其中 attr 结构体如下
signed __int64 __fastcall baby_ioctl(__int64 a1, __int64 a2) { attr *v2; // rdx signed __int64 result; // rax int i; // [rsp-5Ch] [rbp-5Ch] attr *v5; // [rsp-58h] [rbp-58h]
_fentry__(a1, a2); v5 = v2; if ( (_DWORD)a2 == 0x6666 ) { printk("Your flag is at %px! But I don't think you know it's content\n", flag); result = 0LL; } elseif ( (_DWORD)a2 == 0x1337 && !_chk_range_not_ok((char *)v2, 16LL, *(_QWORD *)(__readgsqword((unsigned __int64)¤t_task) + 4952)) && !_chk_range_not_ok( v5->flag_str, v5->flag_len, *(_QWORD *)(__readgsqword((unsigned __int64)¤t_task) + 4952)) && v5->flag_len == strlen(flag) ) { for ( i = 0; i < strlen(flag); ++i ) { if ( v5->flag_str[i] != flag[i] ) return0x16LL; } printk("Looks like the flag is not a secret anymore. So here is it %s\n", flag); result = 0LL; } else { result = 0xELL; } return result; }