Codegate2018 welcome to droid

By puing | April 23, 2018

Codegate2018 Welcome To Droid 출제자 Write Up

안녕하세요. 이번에 Codegate2018 예선에 melongdroid 문제를 출제한 puing 입니다.
이번 글에서는 welcome to droid 문제에 대한 write-up 을 써 볼까 합니다.


Step 1 - 문제환경 세팅하기

해당 문제에 droid.apk 이라는 바이너리가 주어집니다.



먼저 이 apk 파일을 에뮬레이터안에 설치하여 실행해봅시다.


저는 android studio 에서 사용할 수 있는 AVD(android virtual device) 를 사용하였습니다.
기종은 Nexus 5 API 23, arm 버전으로 선택하였습니다.


에뮬레이터를 실행하면 아래와 같은 화면을 확인할 수 있습니다.



자 이제 이 에뮬레이터에 droid.apk 를 설치해보겠습니다.
대회 당시에 설치 관련해서 질문주신분들이 계셨는데.. 정상적으로 설치되는 apk 파일입니다.ㅜㅜ 설치 방법은 검색으로도 쉽게 알 수 있습니다.


AVD 를 이용하여 설치해봅시다.


AVD 는 pc 와 연결된 android 기기와 통신할 수 있는 도구입니다.
shellandroid 기기에 접속, apk 설치 등등 여러 작업들을 할 수 있습니다.


먼저 adb devices 를 터미널에서 입력하면 현재 연결된 에뮬레이터나 기기를 보여줍니다.
avd 에뮬레이터를 실행시키면 다음과 같이 연결된 장치를 확인할 수 있습니다.



자 이젠 droid.apk 파일을 에뮬레이터 안에 넣어보겠습니다. 저같은 경우는 /data/local/tmp 에 droid.apk 를 넣었습니다.


adb push droid.apk /data/local/tmp 명령어를 입력하면 해당 경로에 파일이 정상적으로 위치하게 됩니다.

> adb push droid.apk /data/local/tmp


adb shell 로 에뮬레이터에 접속하여 확인해보면 apk 파일이 있는 것을 확인할 수 있습니다.



adb shell pm install -t /data/local/tmp/droid.apk 명령어를 입력하면 에뮬레이터에 droid.apk 가 설치됩니다.

> adb shell pm install -t /data/local/tmp/droid.apk


설치 후 앱을 실행하면 아래와 같은 화면을 확인할 수 있습니다.



정상적으로 앱을 실행시켰습니다. 이제 해당 apk 을 디컴파일하여 소스를 볼까요?


Step 2 - 문제 디컴파일decompile 하기


1. 먼저 apk 파일 확장자를 zip 으로 바꾼 후, 압축을 풉니다.

압축을 푼 디렉터리 안에 여러 파일들을 확인할 수 있습니다.



2. 위 파일들 중에서 dex 파일을 jar 파일로 바꿉니다.

저는 dex2jar 라는 도구를 사용했습니다. 사용법은 다음과 같습니다.

> d2j-dex2jar.bat [dex 파일 이름]


jar 파일을 jd-gui 도구로 열어보면 java로 된 소스코드를 확인할 수 있습니다.



Step 3 - ID와 Password 통과하기


문제의 처음 화면에서 무작위로 aaaaaaaaaa 을 입력하고 다음 화면으로 이동하면 비밀번호를 입력해야 합니다.
이 부분을 소스코드에서 찾아보면, 사용자가 입력한 비밀번호와 무언가를 비교하고, 같으면 다음 화면으로 이동하는 로직인 것을 확인할 수 있습니다.


어떤 값과 비교하는지를 알아봅시다.


처음 화면과 두 번째 화면의 소스코드를 보면, 아이디를 입력받는 첫 번째 화면에서 사용자가 입력한 값을 다음 화면으로 전달합니다.(1st activity 에서 putExtra 를 이용하여 str 을 전달합니다.)
그리고 두 번째 화면에서 사용자가 입력한 아이디를 받아와서(getIntent() 로 받아와서 paramBundle 에 담아두죠) a라는 함수의 인자로 넣어주게 됩니다.



그럼 첫 번째 화면에서 사용자가 입력한 아이디가 인자로 들어간 함수 a 의 리턴 값과 두 번째 화면에서 사용자가 입력한 비밀번호를 비교하여 맞으면 세 번째 화면으로 이동하겠네요.


그럼 이번엔 a 라는 함수를 볼까요?



인자의 길이를 i1 변수에 저장하고 이-만큼 while 문을 돌고..어쩌구 저쩌구하는데… 이 로직을 그대로 python 으로 만들어봅시다.
이 로직을 그대로 만들고 우리가 아-까 입력했던 아이디 aaaaaaaaa 가 인자로 들어갔을 때 어떤 값을 리턴하는지 확인하여 그대로 비밀번호로 입력해볼까요?


저는 아래와 같이 간단하게 만들어보았습니다.

#function_a_logic 

input_ = raw_input(">>")
a = ['c','o','d','e','g','a','t','e','2','0','1','8','h','u','r','r','a','y','!','H','A','H','A','H','A','L','O','L']
pass1 = ""
tmp2 = ""

lenth = len(input_)
print 'input lenght %d'% lenth

for i in range(0,lenth):

	tmp = int(input_[i].encode("hex"),16) ^ int(a[lenth+i].encode("hex"),16)


	for j in range(0,len(a) -1):
		if(tmp == a[j]):
			print "wrong"


	k = 0
	while k < tmp:
		k = k + k
		k = k+1

	tmp = k
	tmp2 += str(tmp)

for i in range(0,lenth):
	pass1 += str(int(tmp2[i].encode("hex"),16) ^ i)

print "password is"
print pass1


위처럼 로직을 짠 후 aaaaaaaaaa 를 입력하면 해당 로직에서 어떤 값을 리턴해주는지 확인할 수 있습니다.


$ python logic.py 
>>aaaaaaaaaa
input lenght 10
password is
49515350545055505956


결과값을 비밀번호로 입력하고 나면 다음 화면으로 이동하게 되는 것을 확인할 수 있습니다.



Step 4 - 후킹Hooking을 통해 Serial Key 체크 로직 우회하기


다음 화면에선 앱에서 요구하는 올바른 serial key 를 입력해야 합니다.

소스를 확인해보면, k 라는 함수의 리턴값과 사용자가 입력한 serial key 가 일치하면 다음 화면으로 이동하게됩니다.
k 라는 함수를 보면, 20개의 랜덤값을 생성합니다. 게다가 k 함수는 버튼을 클릭할 때마다 호출하게됩니다.
즉 우리는 serial key 와 랜덤으로 생성되는 20자리수의 랜덤값을 맞춰야합니다.



NEXT 버튼을 누를때 생성되는 랜덤값을 어떻게 예측하고 serial key 로 입력할까요?
이 부분은 k 함수를 후킹hooking하여 해결할 수 있습니다.


위키피디아 - 후킹Hooking이란?


쉽게 말해, 우리가 k 함수를 후킹하여 호출될 때마다 랜던값을 리턴하는게 아니라 aaa 를 리턴하게 바꾸는 것으로 문제를 해결하는 것입니다.
후킹을 통해 serial key 로 aaa 를 입력하면, 우리가 입력한 serial key aaa 와 호출된 k 함수에서 리턴한 aaa 를 비교했을 때 일치하게 되므로 다음 화면으로 이동할 수 있게 되겠죠!


후킹할 수 있는 도구로 frida 라는 도구를 사용했습니다. python pip 를 이용하여 쉽게 설치할 수 있습니다. 그리고 frida server 를 해당 에뮬레이터에서 사전에 실행시켜줘야 합니다.


GitHub Official - FRIDA server


frida server 를 다운받아서 우리가 droid.apk 를 에뮬레이터에 넣어줬던 방법 그대로 에뮬레이터에 넣어줍니다.
에뮬레이터에 넣어준 후 실행만하면 됩니다.



그리고 아래와 같이 python 코드 하나를 만들어 줍니다.
아래의 소스코드는 연결된 device 정보를 가져온 후에 프로세스를 찾아 attach 하고, js.js 파일을 로드합니다.


import frida
import time
import sys

package_name = "com.example.puing.a2018codegate"

device = frida.get_usb_device()
pid = device.spawn( [ "com.example.puing.a2018codegate" ] )
device.resume( pid )
time.sleep( 2 )

session = device.attach( pid )
with open( "D:\\jm\\ctf\\codegate\\2018\\droid\\ex\\js.js" ) as f :

script.load()
input( "start >>" )



js.js 코드는 아래와 같습니다.
우리가 후킹하고자하는 k 를 재정의하는 코드입니다.
따라서 세 번째 화면에서 NEXT 버튼을 누를 때 k 함수가 호출될 때, 우리가 재정의한 코드가 실행될 것 입니다.


console.log( "script loding" );

Java.perform( function( ) {

	var string_class = Java.use( "java.lang.String" );
	var main4_class = Java.use("com.example.puing.a2018codegate.Main3Activity");

	console.log("instance : " + main4_class);
	main4_class.k.implementation = function( ){
		console.log( "============ here is k() ===========" );

		var ret = string_class.$new("aaa");
		return ret;
	};

} );


python 코드를 실행하면 에뮬레이터에서 앱이 새로 시작하고 아이디, 비밀번호를 알맞게 넣어준 후에 serial key 입력하는 곳에서 aaa 를 입력하고 NEXT 버튼을 누르면 다음 화면으로 넘어가는 것을 알 수 있습니다.



다음 화면에서 flag 내용을 출력해줍니다.

flag 값은 W3_w3r3_Back_70_$3v3n7een!!! 입니다.


모두들 수고하셨습니다 :)

comments powered by Disqus