[해킹보안] 창과 방패 끝없는 전쟁

이번 문제는 Jailbreak Test3 문제를 풀어 보았다.

 

일단 아이폰 내 설치 된 응용 프로그램 중, Jailbreak Test3 탭을 누르면 아래와 같은 팝업 창이 뜬다.

 

우선 응용 프로그램에서 어떤 기능이 사용되는지 확인하기 위해서 아래와 같은 명령을 사용하여 추적을 시작했다.

 

frida-trace -U -i "*jail*" DVIA-v2 명령을 실행 , 응용프로그램 jailbreak test3 탭을 누름

 

그러면 버튼을 클릭할 함수를 호출한다. 그래서 Jailbreak Test3 버튼을 클릭 _T07DVIA_v232... Jailbreak Test1TappedypF 호출된다.

 

이제 함수가 진행되는 것을 확인하고 BL(분기 링크) 명령으로 다른 함수를 호출했다. 이것은 기본적으로 JMP명령과 동일하다.

 

호출되는 명령은 아래와 같다.

 

이제 frida 사용해서 Script 작성하고 hooking하려는 명령이 실제로 호출되고 있는지 확인했다.

checkmeminuse.js 스크립트

 

 

응용 프로그램에 대해 대상 모듈을 변경해야 했다. 모듈베이스는 정적이며 frida 자동으로 오프셋을 계산한다.

 

frida -U -l checkmeminuse.js DVIA-v2 명령을 실행 시킨 , Jailbreak Test 3탭을 누르면 메모리 주소가 사용 중이라는 것을 있었다. (아이폰 화면에 Jailbreak Test3 버튼을 눌러도 동작하지 않음)

 

이제 x8 레지스터에 로드되는 값이 무엇인지 알기 위해 아래와 같이 스크립트를 짰다.

Hook3-1

 

 

이는 주소를 출력하는 함수의 변경과 x0 레지스터 내에서 반환되는 값과 동일하다.

 

아래 frida 명령으로 후킹을 했다.

 

frida -U -l hook3-1.js DVIA-v2

이제 응용 프로그램 내에서 실행할 있다. 그리고 주소값 확인할 수 있었다.

 

따라서 주소가 찾았고 x0 레지스터의 값이 1이라는 것을 알게 됐다. 이렇게 해서 번째 함수가 일부 검사를 수행했으며, Return 결과는 탈옥에 대해 1 또는 탈옥되지 않은 경우 0으로 나타난다는 것을 알았다. 그러면 비교를 위해 x8 로드되어 어떤 팝업이 올라올지 분석해 보았다.

 

다음으로 메모리 주소를 가로 채고, x0 레지스터의 값이 0x01인지 확인한 , 만약 그것이, 다음 0x0으로 변경되면 콘솔을 통해 “Bypass Test3”이라고 출력할 것이다.

 

frida -U -l DVIA2bypassjailbreak1.js DVIA-v2 명령을 실행하였다.

DVIA2bypassjailbreak3.js 스크립트

 

 

 

 

Script가 정상 실행 되었으며, 콘솔 창에 Bypass Test3이라고 출력 됨.

 

 

그런 다음 jailbreak test3 탭을 누르면 팝업 창에 Device is Not Jailbroken이란 메시지가 뜨면서 탈옥탐지를 우회할 있었다.

 

-          -

 

[참고 사이트]

https://philkeeble.com/ios/reverse-engineering/iOS-Bypass-Jailbreak/

 

Bypassing JailBreak Detection - DVIAv2 Part 2

A guide on how to bypass jailbreak detection on the DVIAv2 app for iPhones.

philkeeble.com

https://frida.re

 

Jailbreak Test1에 이어 Test2 문제를 풀어보았다.

 

먼저 탈옥 탐지를 담당하는 DVIA-v2 내의 Class 추출하기 위해 스크립트를 짰다. 

Class 추출 스크립트

 

그리고 frida 실행시켰다.

 

frida -U -l classes.js DVIA-v2 | grep Jailbreak

 

아래와 같이 Method를 추출하기 위해 스크립트를 짰다.

Method 추출

 

그리고 frida 실행시켰다.

 

 

Class Method 추출했다.

그리고 return 값을 확인하는 스크립트를 짰.

return 값 확인

 

 

frida 실행시켜 return 값을 추출했다.

 

frida -U -l returnvalue.js DVIA-v2

return 값 추출

 

 

Jailbreak test2 응용 프로그램을 , 1 부울 값이 Method return 되는 것을 알았다.

 

이제 return 값을 변조하기 위해 스크립트를 짰다.

 

return 값 변조 스크립트

 

 

코드를 사용하면 클래스, 메서드 반환 할 값을 정의해야 한다. 앞에서 0x1을 봤기 때문에, 부울의 반대는 0x0일 것이. 따라서 반환 (newretval) 0x0 으로 지정될 것이다.

 

이제 frida를 실행시켰다.

 

frida -U -l overwrite.js DVIA-v2

 

아이폰에서 Jailbreak test2 다시 하면 ‘Device is Not Jilbroken’  이라는 팝업 창을 있었다.

 

 

[참고 사이트]

https://philkeeble.com/ios/reverse-engineering/iOS-Bypass-Jailbreak/

 

Bypassing JailBreak Detection - DVIAv2 Part 2

A guide on how to bypass jailbreak detection on the DVIAv2 app for iPhones.

philkeeble.com

https://frida.re/

iOS 단말기에 설치되어 있는 Jailbreak Test1 클릭하면 

아래와 같은 팝업 창이 표시된다.

 

Device is Jailbroken

 

 

Start point 찾기 위해 frida Attach하여 UI Dump 수행 .

 

DVIA_v2.JailbreakDetectionViewController Class 분석의 기준 점으로 선정 .

 

IDA Pro에서 DVIA_v2.JailbreakDetectionViewController 검색 ,

-[DVIA_v2.JailbreakDetectionViewController jailbreakTest1Tapped:] Method 클릭하여 분석을 진행 .

 

 

Method 내에서 "Device is Jailbroken" 알람 창을 띄우는 Logic 딱히 보이지 않음

BL(Branch with Link)    __T07DVIA_v232JailbreakDetectionViewControllerC20jailbreakTest1TappedyypF

지시어가 의심스러우므로 클릭하여 진입

 

__T07DVIA_v232JailbreakDetectionViewControllerC20jailbreakTest1TappedyypF 함수 내에서도 직접적으로 알람 창을 띄우는 로직은 보이지 않음. 그러나, 많은 B(Branch) 지시어가 보이므로 lldb 동적 디버깅의 시작점으로 삼기에 적합

※ lldb 디버깅 환경 구성https://hackcatml.tistory.com/46

 

lldb 로 DVIA-v2 프로세스에 attach하게 되면 앱 프로세스가 중단됨

c 명령어로 프로세스를 resume 시켜줌

 

그 후 다음 명령어로 디버깅 하고자 하는 함수의 주소에 breakpoint 설정

br s -a 0x<ASLR Offset>+0x<IDA Pro에서 함수의 시작주소>

 

분석하고자 하는 함수의 주소 값은 다음 절차를 통하여 구함

 

image dump sections <appName>

 ASLR Offset = 0x((노란 박스) - (파란 박스))

예컨데, ASLR Offset이 0x488000이고, IDA Pro에서 함수의 시작주소가 0x100192C10이라면 

 br s -a 0x488000+0x100192C10 으로 브레이크포인트 설정

브레이크 포인트 설정 후 화면의 Jailbreak Test1을 탭하게 되면 breakpoint를 hit하게 됨

 

 

 

이제, n(Next, Step Over) 명령어로 arm 지시어를 하나씩 넘기면서 관찰을 진행

쭉 진행하다 의심스러운 blr(Branch with Link to Register) 지시어를 만난 경우, register read 명령어로 어디로 branch 되는지 확인. "~ -> Swift.Bool"이라고 나오는데, 알람창 띄우는 것이랑 관련 없어 보이므로 Pass.

 

다시, n으로 진행하면 의심스러운 blr 지시어를 만나는데, register read 명령어를 수행하면 알람창 띄우는 것과 관련된 함수로 이동하는 것을 알 수 있음. s(Step In) 명령어로 branch된 함수 내부로 진입

 

함수 디버깅을 시작하기 전에, IDA Pro에서 그 함수가 어떤 형식으로 구성되었는지 살펴 보는게 도움되므로, "showAlert"을 검색. IDA Pro 에서는 함수이름이 알아보기 어렵게 표시되어 있는데, 이는 Swift Name Mangling 때문으로, xcrun 명령어를 사용하면 demangling 된 함수이름을 얻을 수 있음

함수 내부를 살펴보면 TBZ(Test bit and Branch if Zero) 지시어에서 분기가 이루어져서 "Device is Jailbroken" 또는 "Device is Not Jailbroken"을 출력하는 것을 알 수 있음

 

목표는 lldb 명령어로 TBZ 지시어로 이동한 다음 register 값을 변경하여 분기 흐름을 변경시켜주는 것임

 

위 그림과 같이 TBZ 지시어에서 w0 레지스터의 값을 읽으면 1인 것을 알 수 있음. 따라서, 이대로 진행하게 되면 "Device is Jailbroken"이 출력되는 것이므로 w0 레지스터의 값을 0으로 변경

 

이제, c명령어로 모든 process 를 resume시키게 되면 "Device is Not Jailbroken" 알람창이 뜨는 것을 확인 가능

 

** 구글 검색을 통해 Jailbreak test1을 풀던 중, 상기 빨간색으로 칠한 글자부터 더 이상 진행이 힘들어서(mangling decode 문제) frida hooking 기술을 통해 문제를 해결 함 **

 

 

 

 

-      아래 페이지 계속 -

 

 

 

Jailbreak Detection Bypass

Jailbreak Test1

frida를 통해서 어떤 기능이 사용되는지 추적을 했다.

frida-trace -U -i "*jail*" DVIA-v2

참고: 테스트 장치는 USB 위에 연결되어 있어야 하며, DVIA-v2가 실행되어야 함.

버튼을 클릭할 때 마다 각 함수를 호출한다. 그래서 Jailbreak Test1 버튼을 클릭 할 때 첫 번째 기능인 (_T07DVIA_v232... Jailbreak Test1TappedypF)를 불러온다. 응용 프로그램을 로드하고 test 1의 첫 번째 함수를 찾았다.

함수가 실제 수행하는 작업을 분석했다. 전체 기능은 아래와 같다.

함수가 진행되는 것을 확인하고 BL(분기 링크) 명령으로 다른 함수를 호출했다.

이것은 기본적으로 JMP명령과 동일하다. 함수에 마우스를 가져 가면 해당 어셈블리도 볼 수 있다.

 

__T07DVIA_v213DVIAUtilitiesCMa

__T07DVIA_v213DVIAUtilitiesCMa

호출되는 명령은 아래와 같다.

 

첫 번째 명령은 참조되는 SP 레지스터 내에서 값을 로드하는 것이다. x8 레지스터에 로드된다. 그리고 값이 x0 레지스터에 기록 되었다. 이후 명령 값을 x8에서 x0으로 이동. 그런 다음 다른 함수에 대한 명령을 받고 그 후 닫힌다. 따라서 x0이 이 주소에서 가치를 보유하고 있다고 가정할 수 있다.

 

이제 frida를 사용해서 Script를 실행하여 hooking하려는 명령이 실제로 호출되고 있는지 확인했다.

아래 Script 파일을 만들었다.

checkmeminuse.js

 

 

모듈베이스는 정적이며 frida가 자동으로 오프셋을 계산한다. 그리고 해당 메모리 주소로 통신할 때 후킹하면 콘솔에 입력을 넣는다.

 

frida 명령을 아래와 같이 실행했다.

frida -U -l checkmeminuse.js DVIA-v2

이제 아이폰에 설치되어 있는 DVIA-v2 응용 프로그램 내의 Jailbreak Test 1버튼을 클릭하면, 팝업이 뜨면서 콘솔 창에 “Address Entered”로 표시가 된다.

이제 Jailbreak Test1을 누르면 메모리 주소가 사용 중이라는 것을 알 수 있다. (아이폰 화면에 Jailbreak Test1 버튼을 눌러도 동작하지 않음)

 

이제 x8 레지스터에 로드되는 값이 무엇인지 알기 위해 분석했다.

그리고 아래 Script 파일을 프래그래밍 한 후,

returnmemvalue.js

 

 

frida 명령을 실행했다. 이는 주소를 출력하는 함수의 변경과 x0 레지스터 내에서 반환되는 값과 동일하다.

frida -U -l returnmemvalue.js DVIA-v2

이제 응용 프로그램 내에서 재 실행할 수 있고,  Script의 출력 화면을 볼 수 있었다.

 

따라서 주소를 적중 시켰고, x0 레지스터의 값이 1이라는 것을 알게 되었다.

이제 이 함수에 대해 알 수는 없으나, 0으로 변경을 시도하고 일부 BOOLEAN (사실 또는 거짓) 결과를 추측 할 수 있다. 이렇게 해서 첫번째 함수가 일부 검사를 수행했으며, Return 결과는 Jailbreak에 대해 1 또는 Jailbreak되지 않은 경우 0으로 나타났다. 그러면 비교를 위해 x8에 로드되어 어떤 팝업이 표시될 지 분석한다.

Script 파일을 만든 후, 다음 코드를 넣을 수 있었다.

DVIA2bypassjailbreak1.js

 

다음으로 메모리 주소를 후킹하고, x0 레지스터의 값이 0x01인지 확인 한 후, 만일 그것이, 다음 0x0으로 변경되면 콘솔을 통해 “Bypass Test1”이라고 출력.

 

(참고 : 우회하려면 x8 레지스터가 아닌 x0 레지스터의 값을 변경해야 함.)

 

이제 아래 명령으로 Script 파일을 실행한 다음, 테스트를 실행하면 이제 탈옥이 아닌 것을 확인할 수 있다.

frida -U -l DVIA2bypassjailbreak1.js DVIA-v2

Script가 정상 실행 되었고, 콘솔 창에 Bypass Test1이라고 출력된 것을 확인하였다.

 

그리고 아이폰 Jailbreak Test1 탭 버튼을 클릭하니 아래와 같이 탈옥 감지 우회(Device is Not Jailbroken)가 되었다.

Device is Not Jailbroken

 

[참고 사이트]

https://philkeeble.com/ios/reverse-engineering/iOS-Bypass-Jailbreak/

 

Bypassing JailBreak Detection - DVIAv2 Part 2

A guide on how to bypass jailbreak detection on the DVIAv2 app for iPhones.

philkeeble.com

https://frida.re/

CrackMe.apk
1.25MB

 

NOX에서 CrackMe.apk 파일을 설치하고 앱을 실행 했는데, 계속 앱 중지가 되었다.

그래서 Android Studio에서 앱을 실행 했더니 정상적으로 실행이 되었다. 앱을 실행 시키면 로그인 화면이 뜨는데, 문자와 숫자를 입력해도 incorrect란 팝업 창만 뜨면서 로그인을 할 수 없어서 다른 방법을 강구했다.

디컴파일(JEB) 툴로 apk파일을 열어 onCreate메소드가 있는 곳을 분석했는데, flag로 보이는 flagging{It_cannot_be_easier_than_this}란 문자가 나와서 flag인 줄 알았는데 확인해 보니 flag가 아니었다.

 

디컴파일 툴로 소스코드 내 flag 확인

 

 

소스코드 내에서 Toast 메소드가 있었는데 어떤 메소드인지 알아내기 위해 계속 분석을 진행 했다. 

Toast 메소드가 true로 반환되므로 함수가 반환되는 것과 동일하게 String(사용자 입력 값)이 필요 했다.

True 로 반환되는 Toast메소드 발견

 

 

if(arg4.equals(c.a(b.a(b.b(b.c(b.d(b.g(b.h(b.e(b.f(b.i(c.c(c.b(c.d(this.getString(2131492920)

 

그 다음에 디컴파일 툴(jadx)res 경로 밑에 values 경로 밑에 strings.xml 소스코드 내에서 의심되는 문자열을 찾았다.

Strings.xml  소스코드 내 의심스런 문자열 발견

 

 

 [[c%l][c{g}[%{%Mc%spdgj=]T%aat%=O%bRu%sc]c%ti[o%n=Wcs%=No[t=T][hct%=buga[d=As%=W]e=T%ho[u%[%g]h%t[%}%

 

 

 

다음으로 c클래스와 b클래스를 분석 했는데, 전체 및 일부 문자열을 치환하는 것을 확인했다.

C 클래스 String 함수에서 문자 치환

 

 

B 클래스 String 함수에서 문자 치환

 

 

C클래스와 B클래스의 메소드를 문자열 값에 적용 시키기 위해 파이썬 스크립트를 만들어 실행 했다.

그러자 아래와 같이 콘솔 창에 flag가 출력 되었다.

 

파이썬 스크립트 실행 후 Flag 획득

 

 

 

-         -

 

clicker.apk
0.23MB

 

Jadx decompile툴을 사용해서 찾기 기능으로 flag 찾아 봤습니다.

flag 검색 소스코드로 직접 접근해서 확인해 보니 flag 획득하면 “Conguraturations!” The flag is ... TMCTF{ …………………} 이런 형식으로 flag 나올 거라는 예상을 봤습니다.

flag로 의심되는 소스코드

 

 

또한, NOX프로그램에서 clicker.apk 실행 시키면 아래와 같은 화면이 실행 되었습니다. 클릭을 1 때마다 1 증가하게 되고, 1000만번을 클릭 경우 flag 획득할 것으로 예상이 되었습니다.

앱 실행 시 화면

 

 

 

디컴파일 툴에 있는 찾기 기능을 통해 SCORE 찾아 봤습니다. 화면 창을 클릭 또는 터치하게 되면 this.g++; 값이 1 증가하게 되고, this.g값이 3769, 10007, 59239, 100003, 495221, 1000003, 9999999 일치하게 되면 브로드캐스트 메시지를 송신하게 됩니다.

Broadcast 메시지 송신 소스코드

 

 

화면을 클릭 경우, 브로드캐스트 메시지가 송신될 있도록 this.g값을 3768, 10006, 59238, 100002, 495220, 1000002, 9999998 되게 스크립트 코드를 작성하였습니다. 그런데 Frida 스크립트를 통해 명령을 실행한 , 9999998 자동 클릭 상태에서 마지막 한번을 클릭해도 flag 나오지 않았고, NOX프로그램의 clicker.apk 앱이 강제 종료 되었습니다.

자동 클릭 스크립트 작성 및 frida실행

 

 

문제는 CongraturationsActivity onCreate 메소드에서 com.tm.ctf.clicker.a.a.c() 메소드를 호출

앱 강제종료 원인 분석 -1

 

SharedPreferences 저장 COUNT 값이 10000000 아니면(if(10000000 !=a.c()) 강제종료(finish();) 되는 문제였습니다.

앱 강제종료 원인 분석 -2

 

 

 소스코드를 수정하기 위해 Apktool 사용하여 디컴파일을 하고

Apktool 로   디컴파일

 

 

smali 파일을 문서 편집기를 사용하여 변조했습니다.

(COUNT값이 10000000 아니어도 앱이 종료되지 않게, if-eq값을 if-ne 변경)

Smali 파일을 수정

 

 

 

Smali  파일을   문서   편지기로   수정

 

 

 

소스코드를 수정한 ,  Apktool 사용하여 리패키징을 했습니다.

 

Apktool 로   리패키징

 

 

그리고 Uber(keytool 종류) 사용하여 서명을 줬습니다.

 

예시) C:\>java -jar uber-apk-signer-1.2.1.jar -a repack_clicker.apk --allowResign –overwrite

 

마지막 단계로 frida 사용해서 후킹을 하고 앱 화면을 1 클릭하자 flag 획득 할 있었습니다.

Frida 로   후킹을   한   후   flag  획득

 

The end!

[참고]

안드로이드CTF - VirusClicker 프리다 활용 :: HACKCATML (tistory.com)

안녕하세요? hackbyr0k입니다.

정말 오랜만에 블로그 글을 쓰게 되었네요.

 

근 2년간 보안업무를 안하고, 창업 준비 및 부동산 경매/공매 공부를 하다가, 다시 내 천직인 보안 쪽으로 돌아왔습니다. ㅎ

 

제가 최근에 모바일 앱 진단 스터디를 하고 있는데, iOS 앱 진단이 진입 장벽이 정말 정말 높더라구요. 구글링을 해도 명쾌한 글들이 많지 않아서, 제가 삽질을 하면서 알게 되는 정보들은 한개씩 시간날 때 마다 올리도록 하겠습니다.

 

그럼. 설명 들어갑니다. ^^

 

iOS 앱 진단을 하기 전에 실습 해 보면 좋은 사이트가 있습니다.

DVIA (Damn Vulnerable iOS App) | A vulnerable iOS app for pentesting

 

DVIA (Damn Vulnerable iOS App) | A vulnerable iOS app for pentesting

Downloads Swift Version (April, 2018) – Download the IPA file from here here Github – Here Make sure to read this for instructions on how to install the app on any device (jailbroken or not jailbroken), and how to compile the app with Xcode. This versi

damnvulnerableiosapp.com

여기에 나와 있는 문제들을 풀기 위해 필요한 tool들 중 IDA Pro를 통해 리버싱을 하는 부분이 여러군데 나오는데, 처음에 DVIA-v2-swift.ipa 파일을 통으로 리버싱을 하려고 하니, 열리기는 열리는데 함수 명이 한개도 안떠서 이방법은 아닌것 같아서 다시 구글링 열심히 해서 다른 방법을 찾아 봤더니 Clutch나 CrackerXI 같은 복호화 툴로 크랙해야 한다는 말도 있어서 아이폰에다가 CrackerXI 내려받기 해서 실행했는데 DVia-v2 앱이 검색이 안되는 겁니다. ㅎㅎㅎ;

 

각설하고,

아래 순서대로 하면 DVia-v2를 역분석 할 수 있습니다.

 

 

1. 위 사이트에서 내려받기한 DVIA-v2-swift.ipa 파일이 있는 곳으로 갑니다.

 

 

 

2. ipa 파일을 우클릭 합니다. 그런 다음 DVIA-v2.app을 더블클릭 합니다.(반디집 설치 필요)

 

 

3. 우측 상단을 보시면 압축 크기를 클릭해서 용량이 큰 순서로 정렬합니다. 그러면 아래 그림과 같이 DVIA-v2란 파일이 있을 겁니다. 용량이 제일 크네요 ㅎㅎㅎ

 

 

 

4. DVIA-v2 파일을 바탕화면이나 자신이 가져다 놓고 싶은 경로에 내려받기 합니다.

 

 

5. 이제 DVIA-v2 파일을 IDA Pro를 통해 실행합니다.

팝업 창이 뜨면 Mach-O file(EXECUTE). ARM64 [macho64.dll]에서 더블 클릭 합니다.

 

 

6. 드디어 좌측 Function name 하단에 함수들이 뜨네요 *.*

이제 DVIA-v2를 신나게 리버싱 하시면 됩니다.

 

 

끝!!!