Participation

[제 14회 중고생 정보보호 올림피아드 안드로이드] 출제후기 및 Write up

D4tai1 2019. 10. 26.

 

제작년 12회에는 네트워크 문제팀과 DDoS탐지 및 방어를 했고,

작년 13회에는 운영팀에서 웹서버 및 전체운영, 시스템팀 소속에 있었으며,

이번 14회에는 시스템팀과 안드로이드팀 소속으로 

문제를 출제하게 되었습니다.

 

예선은 9월 20일 토요일 온라인,

본선은 10월 25일 금요일 국회의사당에서 

진행되었습니다.

[그림1] 국회의사당 정문

 

[그림2] 대회현장

 

[그림3] 저녁에 바라본 국회의사당

 


그럼 예선 Q3 안드로이드 문제풀이를 시작하겠습니다.

 

먼저 저의 안드로이드는 루팅된 상태입니다.

[그림1] 안드로이드의 IP 확인

제 핸드폰의 IP는 172.16.100.6입니다.

 

[그림2] Ubuntu를 핸드폰에 연결

$ adb connect 172.16.100.6 명령어로 연결을 하였습니다.

 

[그림3] Q3을 핸드폰으로 전송

$ adb install -r ./Q3.apk 명령어로 휴대폰에 apk 설치하였습니다.

 

[그림4] Q3 확인

 오오 정상적으로 Q3을 받았습니다.

이 부분은 핸드폰으로 대회사이트에 접속해서 파일을 다운받아도 됩니다.

 

[그림5] Q3 실행 후 Login 시도

Q3을 실행은 했으나 로그인 버튼을 눌러도

다음으로 진행이 되지 않습니다.

이런거는 분석을 해야 제 맛이죠!!

 

[그림6] bytecode viewer로 Q3 확인

왼쪽에도 MybroadcastReceiver.class가 있고

오른쪽에도 왠지 broadcast 취약점이 있을 것 같습니다.

 

[그림7] 브로드캐스트 리시버 취약점 이용

 브로드캐스트 리시버를 호출시키고 나자

새로운 창이 열렸습니다.

뚜둔!!

 

[그림8] 새로운 화면

3개의 퀴즈고 무슨 암호같네요.

 

[그림9] Secret Table

비밀스러운 표가 있네요.

돼지우리 암호로 풀거나 

bytecode viewer로 보면 

평문으로 퀴즈 3개에 대한 답을 알 수 있습니다.

 

[그림10] 아무 값이나 입력

아무 값이나 입력하면 유효하지 않다고 하네요.

까다롭기는..!!

 

[그림11] 퀴즈 3개의 정답

이렇게 정리하니까 복잡해보이지만

실제로는 바이트코드뷰어에 올려서 보면 

3개 단어 모두 평문으로 나옵니다.

 

[그림12] 암호문?

암호문이 나왔지만 메신저나 메일로 전송하기 편하도록

친절하게 복사까지 해줍니다.

 

더 이상의 진행은 없고 앞에서 푼 퀴즈 3개가 전부이니

암호문에 대한 키는 앞에 퀴즈 3개의 답이 되지 않을까요?

 

 

import sys

msg = '*|>:!*>/!:|<!_&/:<`&!.`&=:-!_>.|;^<!:|>:!>==<>`<~!;^!:|<!_-%;<!;_;:>:;-^!#>_<!>^~!.-^:`;+,:<!#`<>:@&!:-!:|<!%;.:-`&!-$!:|<!>@@;</!;^!*-`@~!*>`!2?'

def make(hint):
	tmp = {}	# 순서를 저장
	res = ''
	index = 0

	for c in hint:	
		if c in tmp:
			res += tmp[c]
		else:
			tmp[c] = str(index)
			res += str(index)
			index += 1
	return res

def find_pattern(msg, hint):
	pattern = make(hint)	# 선형화
	psize = len(hint)		# 선형화한 문자열의 길이
	pos = 0 	# 암호문내에서 비교할 시작인덱스

	while True:
		data = msg[pos:pos+psize]
		if len(data) < psize:
			break

		d_pattern = make(data)
		if d_pattern == pattern:
			return data
		pos += 1

def dec(msg, key):
	pmsg =''
	
	for c in msg:
		if c in key:
			c = key[c]
			
		pmsg = pmsg + c

	return pmsg

def usage():
	print('Usage: "python3 {} [PLAIN_TEXT1] [PLAIN_TEXT2] ..."'.format(sys.argv[0]))
	sys.exit(1)

def main():
	if len(sys.argv) < 2:
		usage()

	print('-------------------- 암호문 ----------------------')
	print(msg)

	key = {'|':'h', '=':'p', '%': 'v', '#':'g'}
	#key = {}
	# hints = ['world war', 'mystery', 'contribute']
	hints = [x for x in sys.argv[1:]]
	print(hints, len(sys.argv))

	pattern = []

	cnt = 0
	for hint in hints:
		pattern.append(make(hint))
#		print('{}. 알려진 평문[{}]의 패턴 : {}'.format(cnt + 1, hint, pattern[cnt]))

		data = find_pattern(msg, hint)

		index = 0
		for k in data:
			key[k] = hint[index]
			index += 1

#		print('{} 알려진 평문의 알파벳'.format('>>>'))
#		print(' [+] {}\n'.format(key))

		cnt += 1
	
	pmsg = dec(msg, key)
	
	print('-------------------- 찾은 알파벳으로 복호화 ----------------------')
	print(pmsg)

if __name__ == '__main__':
	main()

기지 평문공격(알려진 평문공격)을 구현하였습니다.

 

[그림13] 기지 평문공격(KPA)

 3개 단어를 적어주고 암호문에 매칭되는 것을 찾아서 복호화합니다.

보통 선형공격이라고 부르며, 이론이 많이 알려져 있기 때문에

이론에 맞춰서 소스만 작성하면 됩니다.

 

그러나 몇 개 해석이 안된 것이 보이긴 하네요.

약간의 추리를 해보자면?

|(파이프)는 딱봐도 what의 h고

=(등호)는 누가봐도 appered의 p로 보이고

%(퍼센트)는 눈 감고봐도 movie의 v로 보이고

#(샵)은 name, game등으로 해석될 수 있으나

#reatly를 보니 g가 어울리겠네요.

 

[그림14] 추가 복호화

조금 더 그럴듯 해졌나요?

 

[그림15] 조력자

파파고의 도움을 받아서..

 

[그림16] flag 확인

 flag : enigma


암호문까지는 확인하신 분들은 꽤 계시길래

중간에 기지평문공격을 이용하라는 힌트를

올렸습니다.

 

안드로이드문제의 난이도는

시스템1보다 훨씬 쉽다고 생각했으나..

아쉽게도 한 분도 풀지 못한 문제가 되었습니다.

댓글