티스토리 뷰

최종 수정: 2014-09-29


안녕하세요. Hackability 입니다.


이번에 포스팅 할 내용은 2014 Sharif University(SU) CTF 에서 나온 Reverse 200 문제입니다. 문제에서는 suCTF.apk 는 아래 링크 하였으며, 문제 내용은 다음과 같습니다.

suCTF.apk

Flag is a serial number.


문제 내용은 크게 복잡한 것 없이 suCTF.apk를 리버싱 하여 시리얼 번호를 찾는 것 같습니다. 먼저 apk이기 때문에 안드로이드 어플리케이션 임을 알 수 있고, 소스 코드 복원을 통해 어떤 행위를 하는지 분석하였습니다.


먼저, apk파일 확장자를 zip으로 변경하여 압축을 해제 하면 classes.dex 파일이 나오게 되는데 이 파일을 dex2jar (dex2jar link)를 이용하여 jar 파일을 추출합니다.


(dex2jar의 위치는 미리 환경 변수에 추가해 두었습니다.)


그러면 해당 폴더에 classes_dex2jar.jar 라는 파일이 생기고 이를 jd-gui decompiler [jd-gui decompiler link] 를 이용하여 아래와 같이 소스 코드를 확인 할 수 있습니다.



소스 코드 내용을 둘러보면, suCTF.apk 프로그램은 사용자에게 시리얼 키 입력을 요구 하여 맞는지 틀린지 확인하는 프로그램임을 알 수 있습니다.



위의 코드 내용을 보면 isValidLicenceKey 함수가 True 라면 정확한 라이센스를 입력한 것이고, 틀리다면 틀렸다고 뜨게 됩니다. isValidLicenceKey 함수가 어떤 역할을 하는지 따라가보면 다음과 같습니다.



함수 내용을 보면 encrypt 함수에 3개의 인자를 넣고 이 함수의 결과와 "29a002d9340fc4bd54492f327269f3e051619b889dc8da723e135ce486965d84" 의 값이 동일한지 비교를 하게 됩니다.


encrypt에 들어가는 인자에서 paramString1은 유저가 입력한 값이 되고, paramString2는 Security Key, 그리고 마지막 paramString3에 들어 가는 내용은 Initial Vector 값이 들어가게 됩니다. (Main Activity의 내용을 참고하시면 확인할 수 있습니다.) Encrypt 함수의 내용을 보면 위의 인자 사용에 대한 내용이 확실해 집니다.


내용을 보면 AES 알고리즘에 CBC 운영모드, 그리고 PKCS5 Padding 방식을 사용하는 암호 알고리즘을 알 수 있기 때문에, 우리가 입력한 값을 위의 암호 알고리즘으로 암호화한 결과가, "29a0..." 의 결과와 같아야 함을 알 수 있습니다. 간단히 생각하면 decrypt("29a0...")을 하면 우리가 입력해야 하는 값 (Serial Key)를 알 수 있을 것 같습니다. 하지만 암호화된 값을 복호화 하기 위해서는 2번째와 3번째 인자였던 Secure Key와 Initial Vector 값을 알아야 합니다.


이 값이 어디 있는지 찾기 위해 따라가보면 DB Package의 DBHelper Class에서 가져옴을 알 수 있고, 여기서는 db.db 에 접근하여 데이터를 가져옴을 알 수 있었습니다.


다시 suCTF.apk (zip)의 압축을 푼 폴더로 들어 가면 assets 폴더에 db.db 파일이 존재함을 알 수 있습니다. Android 에서는 sqlite 를 이용하기 때문에 sqlite browser 를 이용하여 위의 db 파일을 열어 보았습니다. [sqlite browser link]



위의 내용을 DBHelper 클래스 내용과 비교해보면 [e] 필드의 값이 Initial Vector 값이며 [f] 필드의 값이 Security Key 임을 알 수 있습니다. 


이제 우리가 필요한 내용은 모두 얻었기 때문에 아래 연산만 하면 어떤 값을 입력해야 요구 되는 키 값과 동일한 값이 나오는지 알 수 있습니다.

User Input = decrypt(encrypt data, IV, Security Key, Operation Mode) 


python에서 PyCrypto 모듈을 이용하여 위의 역할을 하는 코드를 다음과 같이 구현해 보았습니다. (사용된 모듈: PyCrypto [link])


(*PADDING의 경우 굳이 지정해 주지 않아도 BLOCK 사이즈 만큼 동일한 문자가 나오기 때문에 flag 구별이 가능합니다. 원문에서 암호문으로 암호화 시, 0x06으로 패딩을 하는 것을 알았기 때문에 0x06으로 padding 삭제 처리를 해 주었습니다.)


위와 같이 코딩 후, 프로그램을 실행 하면 결과는 다음과 같습니다.


FLAG: fl-ag-IS-se-ri-al-NU-MB-ER

댓글