栈
stack pivoting
把ret指针修改为jmp esp的地址,其后加上asm(sub esp,20,;jmp esp),来跳转到shellcode处(ps:20表示偏移量20,需修改)
frame faking
利用leave劫持ebp,从而使得ret到ebp+8
基于堆类型
unsorted bin
FIFO:先进先出
free后,fd和bk为main_arena加上一定偏移的地址,可用于泄漏libc地址。
fastbin
FILO:先进后出
连续两次free相同大小后,最后一个free的fd指向前一个free的地址,可通过修改该值后用于申请任意地址。
Tcache
FILO:先进后出
free时每类大小的bin中可存放7个tcache,其fd指向下一个tcache。
malloc时如果从fastbin中申请一个块,则剩下的块存入tcache中至满。
连续两次free相同大小后,最后一个free的fd指向前一个free的地址,可通过修改该值后用于申请任意地址。
large bin
为双向链表,构造时需要同时修改fd与bk
基于堆的攻击方法
Overflow directly
直接溢出,最容易利用,需要构造好块
UAF
free后未把指针置NULL,可重复使用该指针
Double Free
通常与UAF一起出现
常见套路:
1 | free(1) |
这时申请到的块依次为1->2->1,fastbin可通过此任意申请地址
fastbin attack
原理:修改fd指针伪造fastbin链。
1 | new(0,0x60) |
此时3的地址为ptr+0x10,注意,ptr+8处的值应对应申请的fastbin大小。
global_max_fast
2.23版本位于0x3c67f8处
修改后可将fastbin范围扩大,更容易使用fastbin相关攻击。
fastbin dup consolidate
通过申请largebin触发malloc_consolidate,即可将原本free的fastbin放入unsortbin中,然后再次free。
利用方式:
1 | new(0,0x40) |
此时fastbin和unsortbin中都有0对应的地址。
large bin attack
与fastbin类似,但需要bk。(双向链表)
unsorted bin attack
free后控制bk指针填入一个地址,再申请同样大小的块,即可向(指定地址+2*size)处填入类似[main_arena+88]的地址。
利用套路:
1 | ptr = 0x602180 |
此时0处地址为[main_arena+88]的地址。
注:堆的申请应该在unsortbin之前完成,否则会报错
unsorted bin into stac
代码:
1 |
|
此时victim1的地址与stack_buffer相同
overlap
利用条件:off by one或off by null
chunk extend
通过把p位置置0来伪造前面块为freed状态,并且prev_size为前面的伪造free的大小,从而重复申请得到两个指向同一地址的指针
常见利用方式:
1 | malloc(0,0xf8) |
此时4的地址与1相同
chunk shrink
原理:申请时分割用了size位,free时向前合并时只检查了prev_size
利用方式:
1 | new(0,0x218) |
free(3)后2变为top chunk,通过构造后可以再申请回4处的地址
Unlink
new(small bin unlink)
在free中若p位为0,则会进行合并,并且将P->bk->fd赋值为P->fd。
利用方式:
1 | ptr = 0x602180+0x8#ptr为指向伪造的堆块的地址 |
此时ptr处的地址会被更改为ptr-0x18相应地址的值(即伪造堆的fd)
old
旧版的libc(picoctf2019有出现,但就是不知道怎么编译的),一般是32位的程序
将当前堆的prev_size和size位置为0xfffffffc,则会认为上一块的位置为p-(-0x4)。(size位可随意填写)
设fd覆盖为p,bk覆盖为q。
则free相邻的前一个块后,*(q+8)=p, *(p+0xc)=q。
(好像还有其他的利用方法。。。不是很懂,没有具体的程序可以分析,不过picoctf那道倒是这么做的)
Tcache
tcache poisoning
覆盖 tcache entry 结构体中的 next 域,不经过任何伪造(不需要检查size位) chunk 即可分配到另外地址,类似于fastbin attack。
利用方式:
1 | ptr = 0x602180 |
此时4的地址为ptr。
tcache dup
类似于 fastbin 的double free,就是多次释放同一个tcache,形成环状链表
tcache perthread corruption
控制tcache_perthread_struct
结构体
修改其中相应大小bins的数量及地址,即可任意申请
tcache house of spirit
free 内存后,使得栈上的一块地址进入 tcache 链表,这样再次分配的时候就能把这块地址分配出来
smallbin unlink
在 smallbin 中包含有空闲块的时候,会同时将同大小的其他空闲块,放入 tcache 中,此时也会出现解链操作,但相比于 unlink 宏,缺少了链完整性校验。因此,原本 unlink 操作在该条件下也可以使用。
house of 系列
house of spirit
- 伪造堆块
- 覆盖堆指针指向上面伪造堆
- 释放堆块
- 申请堆块
例题:l-ctf2016–pwn200
House Of Einherjar
2.23
- 申请a、b块
- 并且伪造堆块(prev_size、size位任意,fd、bk都设置为堆块本身)
- 将b的prev_inuse置0,并把b的prev_size位设置为b->fd的地址减去伪造堆的地址
- 伪造堆的size位同样设置为b->fd的地址减去伪造堆的地址
- 释放掉堆块b,此时再申请即从伪造堆处开始
2.27
- 申请a、b块
- 并且伪造堆块(prev_size、size位任意,fd、bk都设置为堆块本身)
- 将b的prev_inuse置0,并把b的prev_size位设置为b->fd的地址减去伪造堆的地址
- 伪造堆的size位同样设置为b->fd的地址减去伪造堆的地址,并且将相邻的下一堆块的prev_size设置为同样的b->fd的地址减去伪造堆的地址
- 释放掉堆块b,此时再申请即从伪造堆处开始
House of Force
利用条件:
- 能够控制top chunk的size位
- 能自用控制malloc的分配大小
- 分配的次数不能受限制
利用方法:
- 申请堆块a
- 将topchunk的size改为-1
- 申请(addr-0x28)-topchunk_addr的块
- 再申请块,即可获得指向addr的块
House of Lore
- 申请堆块a,b
- 伪造堆块f1,f2:其中f1的prev_size和size位为0,fd指向堆块a,bk指向堆块f2;f2的fd指向f1
- 释放堆块a
- 申请堆块c
- 设置堆块a的bk为f1的地址
- 申请堆块d、e,则堆块e指向f1
House of Orange
House of Rabbit
POC1
通过修改chunk1的size位实现overlap。
1 | chunk1 = malloc(0x40); |
此时chunk1对应bin的大小为0xa0;chunk2对应bin的大小为0x50,再申请对应大小堆块即可overlap。
POC2
通过修改chunk1的fd位指向伪造堆块实现overlap。
1 | chunk1 = malloc(0x40);//0x602000 |
此时bin中存在0x50(0x602000)以及0x30(0x602060),申请即可实现overlap。
House of Roman
思路:
- 首先分配
3
个chunk (A , B, C)
,大小分别为0x20, 0xd0, 0x70
- 在
B + 0x78
处设置p64(0x61)
, 作用是fake size
,用于后面 的fastbin attack
- 释放掉
B
,B
进入unsorted bin
, 此时B+0x10
和B+0x18
中有main_arean
的地址 - 再次分配
0xd0
, 会分配到B
, 此时B+0x10
和B+0x18
中main_arean
的地址依然存在 - 然后分配
3
个0x70
的chunk (D , E, F)
, 为后续做准备 - 在
A
触发 单字节溢出,修改B->size = 0x71
. 然后释放C , D
, 此时C , D
进入fastbin
, 同时D->fd = C
. 由于chunk
之间的相对偏移固定,于是利用uaf
修改D->fd
的低 字节 ,使得D->fd=B
- 此时
B->size = 0x71
,同时B + 0x78
为p64(0x61)
(第2步设置), 这就成功伪造了一个0x70
大小的fastbin
。 此时B->fd
为main_arean
的地址,于是通过 修改 低2
个字节,可以修改到malloc_hook - 0x23
处 (malloc_hook - 0x23 + 0x8
处的值为p64(0x7f)
) - 然后分配
3
次0x70
的chunk
, 就可以拿到包含malloc_hook
的chunk
, 此时malloc_hook
内容为0
- 然后利用
unsorted bin
修改malloc_hook
内容为main_arean
的地址 - 利用部分写修改
malloc_hook
为one_gadget
- 多次释放一个指针,触发
double free
异常,进而触发malloc_printerr
,getshell
House-of-Corrosion
House of banana
1.修改largebin(ptr0)的bksize(0x20)位置为写入地址(即_rtld_global)
2.将另一同大小size(ptr1)放入largebin中,即可向对应地址写入这一新堆块地址
3.将该堆块内容修改如下:
1 | //fake_rtld_global point to (ptr1-0x10) |
4.最后调用exit或者退出即可
House of pig
- 修改largebin(ptr0)的bksize(0x20)位置为
__free_hook
-0x28的地址,将另一同大小size(ptr1)放入largebin中,即可向__free_hook
-0x8写入ptr1的地址。 - 恢复堆块,再修改(ptr0)的bksize(0x20)位置为
_IO_list_all
-0x20的地址,再申请其他大小的堆块将ptr1的地址写入到_IO_list_all
-0x20中。 - 恢复堆块,并将ptr0的fd修改为main_arena+240,bk设置为__free_hook-0x20,利用tcache stashing unlink attack,将其解链后放入tcache中。(程序退出或者libc abort时会调用malloc函数申请[IO_buf_len*2+0x64]大小的堆块,并将buf中内容拷贝进去,最后调用free函数释放)
- 在ptr1中伪造IO结构,并修改
_IO_write_ptr
为1,_IO_write_ptr
为0xffffffffffff,_IO_buf_base
为拷贝数据,_IO_buf_end
为拷贝数据结尾,并还原好IO_str_vtable。 - 最后调用exit或者退出即可
IO
相关结构
_IO_FILE_plus
1 | struct _IO_FILE_plus |
注:_IO_FILE是整个嵌入, _IO_jump_t为指针
FILE
1 | struct _IO_FILE { |
vtable IO_jump_t
1 | struct _IO_jump_t |
vtable _IO_str_jumps
1 | const struct _IO_jump_t _IO_str_jumps libio_vtable = |