Last active
January 9, 2023 04:23
-
-
Save brant-ruan/779f824939606ba7a6db5e4af6f92af2 to your computer and use it in GitHub Desktop.
Pawnyable LK04
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE | |
#include <assert.h> | |
#include <fcntl.h> | |
#include <linux/userfaultfd.h> | |
#include <poll.h> | |
#include <pthread.h> | |
#include <signal.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/ioctl.h> | |
#include <sys/mman.h> | |
#include <sys/syscall.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
void fatal(const char *msg) { | |
perror(msg); | |
exit(1); | |
} | |
static void *fault_handler_thread(void *arg) { | |
char *dummy_page; | |
static struct uffd_msg msg; | |
struct uffdio_copy copy; | |
struct pollfd pollfd; | |
long uffd; | |
static int fault_cnt = 0; | |
uffd = (long)arg; | |
puts("[t][*] mmaping one dummy page"); | |
dummy_page = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, | |
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
if (dummy_page == MAP_FAILED) | |
fatal("mmap(dummy)"); | |
puts("[t][*] waiting for page fault"); | |
pollfd.fd = uffd; | |
pollfd.events = POLLIN; | |
while (poll(&pollfd, 1, -1) > 0) { | |
if (pollfd.revents & POLLERR || pollfd.revents & POLLHUP) | |
fatal("poll"); | |
// block until triggered | |
if (read(uffd, &msg, sizeof(msg)) <= 0) | |
fatal("read(uffd)"); | |
assert(msg.event == UFFD_EVENT_PAGEFAULT); | |
puts("[t][+] caught page fault"); | |
printf("[t][+] uffd: flag=0x%llx, addr=0x%llx\n", msg.arg.pagefault.flags, msg.arg.pagefault.address); | |
// craft data and copy | |
puts("[t][*] writing hello world into dummy page"); | |
if (fault_cnt++ == 0) | |
strcpy(dummy_page, "Hello, world! (1)"); | |
else | |
strcpy(dummy_page, "Hello, world! (2)"); | |
puts("[t][*] copying data from dummy page to faulted page"); | |
copy.src = (unsigned long)dummy_page; | |
copy.dst = (unsigned long)msg.arg.pagefault.address & ~0xfff; | |
copy.len = 0x1000; | |
copy.mode = 0; | |
copy.copy = 0; | |
if (ioctl(uffd, UFFDIO_COPY, ©) == -1) | |
fatal("ioctl(UFFDIO_COPY)"); | |
} | |
return NULL; | |
} | |
int register_uffd(void *addr, size_t len) { | |
struct uffdio_api uffdio_api; | |
struct uffdio_register uffdio_register; | |
long uffd; | |
pthread_t th; | |
puts("[*] registering userfaultfd"); | |
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); | |
if (uffd == -1) | |
fatal("userfaultfd"); | |
uffdio_api.api = UFFD_API; | |
uffdio_api.features = 0; | |
if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1) | |
fatal("ioctl(UFFDIO_API)"); | |
uffdio_register.range.start = (unsigned long)addr; | |
uffdio_register.range.len = len; | |
uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; | |
if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1) | |
fatal("UFFDIO_REGISTER"); | |
puts("[*] spawning a fault handler thread"); | |
if (pthread_create(&th, NULL, fault_handler_thread, (void *)uffd)) | |
fatal("pthread_create"); | |
return 0; | |
} | |
int main() { | |
void *page; | |
page = mmap(NULL, 0x2000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
if (page == MAP_FAILED) | |
fatal("mmap"); | |
printf("[+] mmap two pages at 0x%llx\n", (long long unsigned int)page); | |
register_uffd(page, 0x2000); | |
char buf[0x100]; | |
puts("[*] reading from page#1"); | |
strcpy(buf, (char *)(page)); | |
printf("[+] 0x0000: %s\n", buf); | |
puts("[*] reading from page#2"); | |
strcpy(buf, (char *)(page + 0x1000)); | |
printf("[+] 0x1000: %s\n", buf); | |
puts("[*] reading from page#1"); | |
strcpy(buf, (char *)(page)); | |
printf("[+] 0x0000: %s\n", buf); | |
puts("[*] reading from page#2"); | |
strcpy(buf, (char *)(page + 0x1000)); | |
printf("[+] 0x1000: %s\n", buf); | |
getchar(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment