【WP】roarctf_2019_easy_pwn
off_by_one
单字节溢出
题目描述
calloc
1 | __int64 sub_C46() |
一个结构体,内容分别为in_use位,size位和指向堆空间的指针
edit
1 | __int64 sub_E82() |
index需要在0到15之间
获取in_use位并判断
输入size
注意到这里进入了一个函数sub_E26(*(&size + 4 * v3), v2)1
2
3
4
5
6
7
8
9
10
11
12__int64 __fastcall sub_E26(signed int a1, unsigned int a2)
{
__int64 result; // rax
if ( a1 > a2 )
return a2;
if ( a2 - a1 == 10 )
LODWORD(result) = a1 + 1;
else
LODWORD(result) = a1;
return result;
}
即当输入的size-真实的size等于10时,在读入内容时将多读入一个字节,发生单字节溢出
delete
1 | __int64 free_0() |
free操作,指针置0了,感觉没什么问题
show
1 | __int64 sub_1122() |
打印堆的内容
须知
off_by_one的操作
通过输入的size比真实size大10来覆盖size位
通用操作:
- 申请三个堆
- 编辑第一个堆,修改第二个堆的size大小为第二个和第三个堆的size的和
- free第二个堆,再申请回来
此时第二个堆就包含了第三个堆,可以通过编辑第二个堆对第三个堆的内容进行修改(注意本道题堆分配用的是calloc,会在分配时把堆的内容清空,所以需要手动恢复一下堆的信息)
利用realloc_hook调整栈桢,使one_gadget生效
尝试所有one_gadget都失效应该考虑是栈桢不满足条件,需要利用realloc调整栈桢
什么是realloc呢?
realloc在库函数中作用就是重新调整malloc或calloc所分配的堆大小,它和malloc一样有hook函数,当hook函数不为空时就会跳转运行hook函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19.text:00000000000846C0 ; __unwind {
.text:00000000000846C0 push r15 ; Alternative name is '__libc_realloc'
.text:00000000000846C2 push r14
.text:00000000000846C4 push r13
.text:00000000000846C6 push r12
.text:00000000000846C8 mov r13, rsi
.text:00000000000846CB push rbp
.text:00000000000846CC push rbx
.text:00000000000846CD mov rbx, rdi
.text:00000000000846D0 sub rsp, 38h
.text:00000000000846D4 mov rax, cs:__realloc_hook_ptr
.text:00000000000846DB mov rax, [rax]
.text:00000000000846DE test rax, rax
.text:00000000000846E1 jnz loc_848E8 //跳转执行realloc_hook
.text:00000000000846E7 test rsi, rsi
.text:00000000000846EA jnz short loc_846F5
.text:00000000000846EC test rdi, rdi
.text:00000000000846EF jnz loc_84960
.text:00000000000846F5
从realloc源码可以看到开头会有改变栈桢的操作,然后跳转执行realloc_hook
实际操作为将 malloc_hook 劫持为 realloc ,realloc_hook 劫持为 onegadget ,实际运行顺序:1
malloc->malloc_hook->realloc_realloc_hook->one_gadget
思路:
注意为了利用off_by_one,申请的堆大小需要为0x?8,这样为了字节对齐,系统会把下一个chunk的pre_size位给我们使用,我们再溢出一个字节便能更改size位
泄露基址
- 编辑chunk0更改chunk1的size位使其包含chunk2,释放chunk1再申请回来,编辑恢复chunk2的size位(申请的chunk2大小应为small chunk范围)
- 释放chunk2,其被放入unsorted bin,同时由于只有这一个空闲chunk,其fd和bk指针均指向main_arena+88处(释放时chunk2后面需要其他chunk隔开top chunk)
- 打印chunk1的内容。由于之前已经伪造使得chunk1包含了chunk2,这时会把chunk2的fd和bk打印出来,从而计算得到libc基址
fastbin attack
- 把刚才释放的chunk2申请回来
- 编辑chunk3修改chunk4的size使其包含chunk5
- 释放物理相邻的chunk5,chunk4,后一个chunk5size位应为0x70(申请时为0x68,为了和malloc_hook-0x23处对应的size匹配)
- 把chunk4申请回来,此时chunk4已经包含处于fastbin中的chunk5。编辑chunk4把malloc_hook-0x23填入chunk5的fd指针
- 连续申请两次0x68大小的堆,第二次就能得到指向malloc_hook-0x23处的我们伪造的堆
- 编辑伪造的堆,one_gadget填入realloc_hook,realloc+offset填入malloc_hook,然后再申请一个堆,即可getshell
exp
1 | from pwn import* |




