본문 바로가기

[+] Hacking/[-] Challenge Report

GitS 2012 - TeL aViv+

듣도보도 못한 GitS CTF(이번년도에 열렸다고 함)에서 출제 된 문제라고 한다. 사실 이 문제는 외국에 있는 어떤 해커에게 멘붕을 겪어보라며 받은 문제인데 정말 이틀간은 멘붕을 경험하였다.


해당 문제는 패스워드를 찾는 문제이며 힌트로는 TeL aViv+이 나왔다고 한다.(힌트를 이용해 풀이하지는 못하였다.) 


그럼 문제풀이를 시작해보자.


일단 파일을 받아보면 bin 확장자 파일인데 이를 시그니처 식별이나 file 명령어로 확인하여 보면 금방 패킷 덤프 파일이란 것을 알 수 있다. 


그 후 Whireshark로 열어보면 정말 몇 안되는 패킷이 보이고 결국 이 패킷은 단 하나의 프레임만을 보여주고 있다.


[그림 1 - 전송되는 프레임 하나의 패킷들]


첫번째 단은 접속시 환영한다는 메시지처럼 보이며 두번째 단은 무언가 알 수 없는 문자들이 있으며 마지막 단에는 로그인 성공 메시지로 보이는 문자열들이 존재한다.


이렇게 봤을 때 당연히 패스워드는 가운데 단인 것을 추측할 수 있다. 하지만 패스워드라고 하기에는 조금 무리가 있는 듯 싶다. 패스워드는 일반적으로 평문 문자열들인데 위 값들은 hex 값들이기 때문이다.


여기서부터 멘붕이 시작되었다. 처음에는 bruteforce 공격을 시도해 봤지만 무한 경우의수만 생산 할 뿐 딱히 이렇다 할 패스워드는 나오지 않았다.


hex 값들을 계속해서 정독하던 중 마지막 hex 값인 04 2f 04 0b 01이 눈에 들어왔다. 04가 마치 다음 이어지는 hex 값들의 개수를 나타내고 있는 것 같았다. 조금 더 앞으로 이동해 확인하여 보니 그 추측은 정확하였다.


[그림 2 - 정확한 규칙의 패킷 hex 값들]


일일이 수작업으로 하기 힘들어 간단히 python의 힘을 빌렸다. 처음에는 python의 파일 핸들 함수들로 하였으나 f.read()가 0x20을 만나는 순간 읽기를 그만두어 모든 패킷 hex 값들을 읽어들일 수가 없었다. 그래서 scapy 모듈의 힘을 빌리기로 하였다.

(scapy 모듈은 backtrack5에 기본적으로 존재함)


[그림 3]과 같은 소스로 규칙에 맞게 출력해 보았다.(소스는 최종 풀이소스이다.)


[그림 3 - 풀이 소스]


일단 출력 된 결과를 보면 다음과 같다.


packet Block Count : 37


0x8 0x2b 0x2e 0x1 0x17 0x10 0x1 0x5 0x1

0x7 0x57 0x21 0x57 0x1 0x1 0x12 0x1

0x6 0x4d 0x5d 0x1d 0x8 0xd 0x2

0x5 0x1b 0xa 0x18 0x2 0x1

0x4 0x5a 0x4 0x46 0x10

0x5 0x84 0x27 0x16 0x12 0x3

0x5 0x9d 0x22 0x5 0x1 0x1

0x4 0xb8 0x9 0x4 0x1

0x5 0x33 0x5d 0x38 0x5 0x1

0x4 0x5e 0xd 0x68 0x1f

0x7 0x50 0x2d 0x1a 0x20 0x2 0x9 0x2

0x6 0x90 0xc 0x20 0x10 0xf 0x1

0x4 0x3a 0x4 0x1 0x1

0x8 0x17 0x3b 0x34 0x18 0x37 0xf 0x1 0x1

0x4 0x21 0x78 0x25 0x8

0x5 0x1d 0x4b 0x8 0x3 0x1

0x4 0x1a 0x21 0x2 0x3

0x5 0x19 0x25 0x4 0x1 0x1

0x5 0x5c 0x17 0x12 0x2 0x1

0x8 0x5d 0x49 0x33 0x4 0x3 0x2 0x1 0x1

0x4 0x96 0x1a 0x29 0x5

0x3 0x3a 0x5 0x1

0x6 0x39 0x4 0x53 0xa 0x1 0x1

0x7 0x79 0x2 0x7 0x1b 0x1 0x37 0x1

0x4 0x3 0xe 0x18 0x17

0x5 0x6e 0x11 0x9 0x3 0x1

0x9 0xb4 0x6 0x1 0x3 0x4 0x3 0x1e 0x2 0x1

0x7 0x2 0xa7 0x10 0x10 0x12 0x13 0x2

0x7 0x4c 0x9 0x43 0x7 0xd 0x4 0x2a

0x4 0xd 0x78 0x5f 0x2

0x4 0x2b 0x7 0xd 0x1

0x5 0x74 0xd 0xe 0x9 0x2

0x6 0x2d 0xa6 0xd 0xb 0x1 0x6

0x4 0x9d 0x39 0x5 0x1

0x2 0xd5 0x9

0x6 0x38 0x6 0x2 0x2 0x1 0x1

0x4 0x2f 0x5 0xb 0x1


맨 앞에는 hex의 개수를 나타내고 그 뒤부터가 그에 맞는 hex 값들이다. 여기에서 또 한번의 멘붕이 찾아왔다. 이 값들로 무엇을 어떻게 해야 할지 감이 오질 않는 것이다. 그러던 와중 힌트로 제공 된 TeL aViv+에서 +가 보였다. 각 자리를 합치라는 힌트 같았다. 모두 다 합쳐보니 다음과 같은 값들이 얻어졌다.


88 e4 de 40 b4 d6 c6 c6 ce f2 c4 dc 40 e6 c6 74 40 44 88 e4 de 40 9c d6 40 8c e6 f0 da e6 40 9a f2 dc de 44 40


각 hex 값을 10진수로 변환하여 보니 다음과 같았다.


136 228 222 64 180 214 198 198 206 242 196 220 64 230 198 116 64 68 136 228 222 64 156 214 64 140 230 240 218 230 64 154 242 220 222 68 64


아스키코드를 안다면 이 값들은 아스키 코드에 해당하지 않는 값들 이란 것을 알아 볼 수 있을 것이다. 하지만 큰 값들이 200대로 2로 나누면 아스키코드 값에 포함되는 값들인 것을 금방 알 수 있었다.


[그림 4 - 2로 나눈 모습]


이를 기반으로 모든 값을 더하고 2로 나누어 아스키코드 값으로 변환하는 소스를 작성해 풀어보면 다음과 같다.


packet Block sum and char: 68 ==> D

packet Block sum and char: 114 ==> r

packet Block sum and char: 111 ==> o

packet Block sum and char: 32 ==>  

packet Block sum and char: 90 ==> Z

packet Block sum and char: 107 ==> k

packet Block sum and char: 99 ==> c

packet Block sum and char: 99 ==> c

packet Block sum and char: 103 ==> g

packet Block sum and char: 121 ==> y

packet Block sum and char: 98 ==> b

packet Block sum and char: 110 ==> n

packet Block sum and char: 32 ==>  

packet Block sum and char: 115 ==> s

packet Block sum and char: 99 ==> c

packet Block sum and char: 58 ==> :

packet Block sum and char: 32 ==>  

packet Block sum and char: 34 ==> "

packet Block sum and char: 68 ==> D

packet Block sum and char: 114 ==> r

packet Block sum and char: 111 ==> o

packet Block sum and char: 32 ==>  

packet Block sum and char: 78 ==> N

packet Block sum and char: 107 ==> k

packet Block sum and char: 32 ==>  

packet Block sum and char: 70 ==> F

packet Block sum and char: 115 ==> s

packet Block sum and char: 120 ==> x

packet Block sum and char: 109 ==> m

packet Block sum and char: 115 ==> s

packet Block sum and char: 32 ==>  

packet Block sum and char: 77 ==> M

packet Block sum and char: 121 ==> y

packet Block sum and char: 110 ==> n

packet Block sum and char: 111 ==> o

packet Block sum and char: 34 ==> "

packet Block sum and char: 32 ==>  


===============================================================

Dro Zkccgybn sc: "Dro Nk Fsxms Myno" 

==============================================================


무언가 나왔지만 아직 평범한 문자열로 보이지 않는다. 하지만 깨진 문자열이 없어 일반적인 치환암호로 생각 할 수 있어 ROT 암호 알고리즘을 적용해 보았다.


[그림 5 - ROT16]


많은 ROT 알고리즘 결과 중에서 정상적인 문자열을 출력한 알고리즘은 ROT16 알고리즘이었고 결국 패스워드는 The Da Vinci Code이다.






잡담 : 이 문제에서 사용 된 알고리즘이 다빈치 코드 알고리즘?! 그리고 저 힌트는 뭐지... ㅜㅜ;;