随心情笔记,不定期更新
__free_hook
上方几乎是"\x00",无可用size,但是我们可以先用 unsorted attack 攻击__free_hook
上方,在其上方踩出 size,再去劫持 __free_hook。tcache stashing attack
或unsorted_bin_attack
,将_IO_2_1_stdin_->_IO_buf_end
改成main_arena+x
(我这里是+352),从而可以在scanf的时候输入数据到realloc_hook
和malloc_hook
,改成one_gadget,调节下偏移即可。__printf_function_table
表为heap地址(让其不为空),覆写__printf_arginfo_table
表为heap地址且heap['s']被覆写为了one_gadget,在调用格式化字符带有%s
printf()函数时,即可get shell。_rtld_global._dl_rtld_lock_rescursive
为one_gadget_IO_list_all
,调用 _IO_2_1_stdout_
下的vatable中_setbuf
函数.malloc_consolidate()
函数用于将 fast bins 中的 chunk 合并,并加入 unsorted bin 中。 ptmalloc中会有以下几种情况会调用malloc_consolidate()
_int_malloc
的while循环之前,分配的 chunk 属于 small bin,如果 small bin 还没有初始化为双向循环链表,则调用malloc_consolidate()
函数将 fast bins中的 chunk 合并._int_malloc
的while循环之前,分配的 chunk 属于 large bin,判断当前分配区的 fast bins 中是否包含 chunk,如果存在,调用 malloc_consolidate()
函数合并 fast bins 中的 chunkmalloc_consolidate
的 trickmalloc_consolidate
合并__GI___call_tls_dtors
函数__GI___call_tls_dtors+18
也就是rbx不为零时,程序会执行到下面的call rax
,且参数是由rbx控制,再看__GI___call_tls_dtors+13
,rbx是fs:[-0x40],也就是当前线程栈的TLS结构体的上方0x40处,若能覆盖到此处,就能控制程序执行流程。在最终call rax
之前,还有一次ror rax,0x11
和xor rax, fs:[0x30]
,需要leak出TLS的pointer_guard成员._IO_2_1_stdin_
结构的fileno
,最终汇到底层系统调用read(_IO_2_1_stdin_.fileno,buf,nbytes)
。所以有些时候如果我们能够控制IO_stdin
结构的fileno为其它fd,再去调用scanf函数时就可以实现从其它fd读数据。_int_free
中在检查了size合法后(小于0x400),放入fastbin之前,它先尝试将其放入tcache_int_malloc
中,若fastbins中取出块则将对应bin中其余chunk填入tcache对应项直到填满(smallbins中也是如此)__libc_malloc
,_int_malloc
之前,如果tcache中存在满足申请需求大小的块,就从对应的tcache中返回chunktcache_unsorted_limit
限制且之前已经存入过chunk则在此时取出(默认无限制):tcache->counts[tc_idx]
的大小是否大于0,会造成下溢。且没有检测entries处chunk的合法性,我们若能伪造tcache->entries[tc_idx]
的tcache_entry
指针,那我们就能实现从tcache任意地址分配chunk。tcache_double_free
的检测,2.29将每个放入tcache中的chunk->bk(也是tcache entries结构的key位)设置为tcache。_int_malloc
中,使用unsortedbin_attack
时,增加了对unsortedbin双向链表的完整性检测,导致unsortedbin_attack
不可用.unsortedbin_attack
无非就是往一个地址写一个值,如果只是为了改例如global_max_fast
,那largebin_attack
完全可以替代,只不过写入的是堆地址,只是和largebin_attack
配套的house of strom
来实现任意地址分配不能用了。target
,fd不变( 不修改small bin尾部chunk是为了绕过分配时的smallbin double linked list corrupted
检测 ),且target->bk
( target+3*size_t
)必须是一个可写地址,记作target->bk = attack_addr
_int_malloc
中,当从small bin中申请出chunk时,small bin尾部chunk在经过双向链表检测后会被分配出去,启用tcache会遍历small bin中剩余的chunk放入到对应tcache中,但此时的small bin链表已经被破坏,(tc_victim = last (bin)) != bin
这个条件恒成立直到abort,为了beak那个while循环,我们才在tcache中预留2个chunk位,直到tcache被填满tcache->counts[tc_idx] = mp_.tcache_count
以此来跳出循环。attack_addr -> fd
写入一个main_arena
的地址,实现任意地址写。(当然这个洞在引入tcache时的glibc版本就已经存在)。target_chunk
largebin attack
。largebin
中放一个堆块,并在 unsorted bin
中放一个比 large bin
中小但是在同一个 index的堆块,利用 uaf
修改 large bin
的 bk_nextsize = 目标地址
,申请一个比 unsorted bin
中小的 chunk
触发攻击,此时 largebin->bk_nextsize->fd_nextsize
写入堆地址。target
,fd不变( 不修改small bin尾部chunk是为了绕过分配时的smallbin double linked list corrupted
检测 ),且target->bk
( target+3*size_t
)必须是一个可写地址,记作target->bk = attack_addr
_int_malloc
中,当从small bin中申请出chunk时,small bin尾部chunk在经过双向链表检测后会被分配出去,启用tcache会遍历small bin中剩余的chunk放入到对应tcache中,但此时的small bin链表已经被破坏,(tc_victim = last (bin)) != bin
这个条件恒成立直到abort,为了beak那个while循环,我们才在tcache中预留2个chunk位,直到tcache被填满tcache->counts[tc_idx] = mp_.tcache_count
以此来跳出循环。attack_addr -> fd
写入一个main_arena
的地址,实现任意地址写。target_chunk
target_chunk
。如果再次调用malloc申请chunk,得益于从tcache分配时未仔细检查chunk_head
,这时便会从tcache中将这个target_chunk
分配出来,实现任意地址分配内存。fastbin_chunk
的完整性。target_addr
,当这个target_chunk
最后被滑入tcache中时,target_chunk
做为tcache的头部,若tcache中存在其他chunk,则target_chunk -> fd
就被写入一个堆地址,实现任意地址写。chunk_head
,这时便会从tcache中将这个target_chunk
分配出来,实现任意地址分配内存。(任意地址分配内存在这种情况下是个鸡肋,因为我们完全可以不清空tcache,利用UAF+calloc也就是fastbin_attck
来实现任意地址分配)_IO_strfile
没有了像libc-2.24下的fp->_s._allocate_buffer()
这类函数操作,都被修改为了标准函数(malloc...),所以没办法直接直接像libc-2.24那样直接劫持程序流。因此不能使用以前的io_file
攻击手法来劫持流程,但是我们看到在_IO_str_overflow
函数中有很多函数,并且参数我们都可以控制,因此我们可以利用这一点来完成新版的io_file攻击_IO_str_overflow
对应的汇编代码:IO_list_all
指向我们伪造的io_file
malloc_hook
为setcontext+61io_str_overflow
里面会调用malloc,调用malloc之前rdx=rdi+0x28
rdi=&fake_IO_FILE
,此时rdi可控,执行sropmalloc_hook
项。(参见TCTF2020 duet)chunk A-> ptr
构造好三个IO_FILE: X.chain -> Y.chain -> Z.chain
_IO_flush_all_lockp
时三次进入_IO_str_overflow
;第一次控制malloc参数将chunk A分配出来;第二次的时候调用malloc就会分配到ptr,而后memcpy(参见_IO_str_overflow
C源码),即可进行任意地址写(通常将_malloc_hook
写成setcontext+61,用于第三次刷新IO用);第三次调用malloc,即可setcontext实现orw。_free_hook
控制程序流程IO_wfile_sync
函数可以利用rdi控制rdx,函数setcontext+0x35处可以用rdx控rsp,两个搭配使用就可以进行迁栈。在IO_wfile_sync+0x6d
处有call [r12+0x20],这里的r12也是可以用rdi控制的,所以可以利用这条指令调用setcontext+0x35,实现free_hook -> IO_wfile_sync -> setcontext+0x35