2017. 9. 21. 03:13

## HDCON_2017(Fabuary, rev)


[Summary]

1. Android APK 리버싱 & native library 리버싱 문제이다.

2. 가위바위보를 하는 어플리케이션이 있는데 17916점을 넘기면 이기는 어플이다.

3. 한번 이길 때마다 1점씩오르며 각 가위,바위,보를 34999번이상 시도할 수 없다.(수동 방지인듯..)

4. rpc_calc()함수에서 score가 17916점을 넘기면 하드코딩된 값과 xor연산을 하여 키값을 생성해냄.

5. CallMe에서 해당 키값을 이용하여 하드코딩된 encrypt된 flag를 ck()를 호출하여 decrypt함.


[Analysis] 

 이 문제는 간단하게 요약하면 가위바위보를 하는 어플리케이션이 있는데 이기면 Score가 1점 올라가는 시스템이다. 

해당 어플리케이션은 아래 [그림 1]과 같다.



[그림 1] HDcon 어플리케이션 UI



 이제 이 apk를 jadx로 분석해보면 크게 2개의 중요한 루틴이 있다. 첫 번째는 가위, 바위, 보 버튼을 눌렀을 때 동작하는 

ClickListener인데 코드는 아래 [그림 2]와 같다. 



[그림 2] Paper button ClickListener 코드


 위 [그림 2]에 나온 코드는 보를 클릭했을 때의 동작을 나타내는 코드인데 나머지도 코드가 비슷하므로 이것만 

분석하면 된다.

 우선 qq라는 변수에 시스템이 랜덤으로 생성해 낸 가위, 바위, 보 중 하나를 넣고 '보'를 의미하는 3을 첫번째 인자로

qq를 2번째 인자로 rps_calc라는 함수를 호출하는데 이는 native library에 있으므로 해당 라이브러리를 IDA로

분석해야한다. 일단은 코드를 쭉 보면 rps_calc()함수의 리턴 값을 setText()로 어플리케이션에 출력하는데 

2017일 경우는 특별한 동작을 한다. "mm"에다가 rps_calc()함수의 리턴 값을 넣고 send broadcast를 한다.


 대충 딱 봐도 이게 문제를 풀었을 때 동작하는 루틴이겠구나라고 알 수 있는 부분이다.

이제 그럼 rps_calc()를 분석해보도록 하겠다. IDA로 library를 열어서 rps_calc()함수를 들여다보면 아래 [그림 3]

과 같다.



[그림 3] rps_calc() 함수 디컴파일


 다른 부분은 볼필요가 거의 없다. 그냥 이겼을 때 "You Win"을 출력하고 졌을 때 "You Lose"를 출력하고 뭔가 이상한 

걸 탐지하면 이상하다고 출력하는 부분이다. [그림 3]의 코드를 보면 score > 17916인 분기문을 볼 수 있는데 딱봐도

score가 17916이상이면 뭔가를 하고 아까 분석했던 것처럼 2017이 들어있는 문자열이 나오겠구나 생각할 수 있다.

 그럼 그안에를 보면 하드코딩된 값과 0x58을 xor하는 것을 볼 수 있는데 이걸 그냥 직접 해보면 "HD-C-O-N-2-0-1-7"

이 나온다. 이제 이걸로 아까 [그림 2]에서 분석했던 걸 참조하면 mm변수에 해당 키값을 넣고 send한다는 것을 

알 수 있다.


 그럼 이제 apk에서 봐야한다고 했던 2번째 부분을 보면 되는데 바로 CallMe이다. 코드는 아래 [그림 4]와 같다.



[그림 4] CallMe 코드

 이 코드를 보면 mmm 변수에 mm으로 받은 값을 집어넣고 하드코딩된 encrypted flag와 뭔가 

쿵짝쿵짝을 하는걸 알 수 있는데 키 값이 16자이므로 16자넘어가면 첨부터 key값 사용하는 루틴이 보이고

핵심 decrypt하는 루틴은 ck()함수에서 하는 것이라고 생각할 수 있다. ck()함수는 index를 첫 번째 인자로,

key값dmf 2번째 인자로, decrypted flag를 3번째 인자로 받고 호출된다. 그럼 이제 IDA로 ck()함수를 

분석하면 되는데 디컴파일된 결과는 아래 [그림 5]와 같다.



[그림 5] ck() 함수 디컴파일


 위 [그림 5]의 코드도 굉장히 간단한데 index값을 기준 삼아 case문으로 분기를 나누고 그냥 시프트 연산

xor연산으로 쿵짝쿵짝하고 리턴하는 간단한 함수이다. 따라서 이건 파이썬으로 똑같이 짜주면 decrypt가 

가능하다. 그렇게 나온 결과는 "[*] flag is : W@tching_7th_Sunse7_in_B@li" 이었다.


[Exploit Code] - rock_exploit.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
key = list("HD-C-O-N-2-0-1-7")
enc_flag = list("SBtbhfle_7tg]Runsj5]io_MBmi")
dec_flag = []
 
def ck(i, key, enc_flag):
    if(i%6 == 0):
        result = chr(((ord(key) & 0xfff0>> 4) ^ ord(enc_flag))
        return result
    elif(i%6 == 1):
        result = chr(((ord(key) & 0xffe0>> 5) ^ ord(enc_flag))
        return result
    elif(i%6 == 2):
        result = chr(((ord(key) & 0xff80>> 7) ^ ord(enc_flag))
        return result
    elif(i%6 == 3):
        result = chr(((ord(key) & 0xffc0>> 6) ^ ord(enc_flag))
        return result
    elif(i%6 == 4):
        result = chr(ord(enc_flag))
        return result
    elif(i%6 == 5):
        result = chr(ord(enc_flag) ^ 0xf)
        return result
    else:
        result = chr(67)
        return result
        
 
for i in xrange(len(enc_flag)):
    if(i<16):
        dec_flag.append(ck(i, key[i], enc_flag[i]))
    else:
        dec_flag.append(ck(i, key[i-16], enc_flag[i]))
 
print "[*] flag is : " + "".join(dec_flag)
 
cs


[Get Flag~~!!!!]


[그림 6] flag



끝~!





Posted by holinder4S