💡Introduction
OWASP Mobile Application Security Testing Guide (MASTG) 프로젝트의 일부인 iOS에 대한 Crack 문제이다.
owasp-mastg/Crackmes/iOS/Level_01/UnCrackable-Level1.ipa at master · OWASP/owasp-mastg
The Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes the technical processes for verifying the contr...
github.com
🔧Preferences
문제를 풀기 전 환경 세팅이 필요해서 해당 과정에 대해 설명을 작성해 봤다.
1) 아래 링크에서 Sideloadlly 설치를 진행해 준다. 로컬 PC에서 IPA 파일을 단말기에 설치할 수 있는 앱이다.
Sideloadly - iOS, Apple Silicon & TV Sideloading
Sideloadly is a tool for sideloading apps on iOS, Apple Silicon Macs, and Apple TV without jailbreak. Download now for a secure and easy sideloading experience.
sideloadly.io
2) 다운로드한 IPA 파일을 Sideloadlly를 이용해서 설치를 진행해 줬다.
3) 설치한 앱에 접근을 하면 아래 사진과 같이 '신뢰하지 않는 개발자'라며 앱이 실행되지 않는다. 그래서 설정을 통해 신뢰하는 앱으로 변경해줘야 한다.
4) '설정 > 일반 > VPN 및 기기 관리'에 접근하여 신뢰하도록 설정을 해줬다.
5) 그러면 앱 실행이 가능해진다. 이제 문제를 풀어보자
📌Step-By-Step
Step1) 앱 실행 후 입력하는 창이 보며 'test'라는 문자열을 작성해 봤는데, 'Verification Failed'라고 알림 창이 떴다. 숨겨진 라벨의 비밀을 찾아야 하는 거 같다.
Step2) 정확한 분석을 위해 앱의 바이너리 파일을 IDA를 통해 분석을 했다. 바이너리 파일을 꺼내기 위해서는 다운로드한 IPA의 파일의 확장자를 ZIP으로 변경 후 압축을 풀어준다. (UnCrackable-Level1.ipa → UnCrackable-Levle1.zip)
압축을 푼 후 폴더에 접근하여 크기 순으로 정렬을 하게 되면 제일 파일 크기가 큰 파일이 바이너리 파일이다. 해당 파일을 IDA로 분석을 진행하면 된다.
Step3) IDA에서 우리가 유일하게 가지고 있는 단서인 'Verification Failed' 문자열을 검색해 봤다. 뭐가 검색되는 것을 볼 수 있다.
Step4) 해당 부분의 코드를 자세히 보기 위해서 코드 쪽으로 접근을 시도했다.
Step5) 어떤 조건에 의해서 True일 때 'Congratulations!' 문자열을 띄우고 False일 때 처음에 우리가 확인한 ' Verification Failed' 문자열을 띄우는 것을 확인했다. 우린 'Congratulations!' 문자열을 띄우는 값이 무엇인지 찾아야 한다.
Step6) 해당 코드를 더 자세히 보기 위해 디컴파일을 진행하여 C언어로 작성된 코드를 확인해 봤다.
Step7) if(v12) 조건에서 v12 값이 True일 때 'Congratulations!'을 띄운다. V12는 objc_msgSend를 직접 호출하는 방식으로, v7의 객체가 v11 문자열과 같은지를 확인하는 비교하는 코드이다.
v12 = (unsigned int)objc_msgSend(v7, "isEqualToString:", v11);
Step8) v7이 뭔지 흐름을 확인해 보니 마지막 v4 객체를 보면 ViewController라는 클래스 안에 있는 theTextField라는 텍스트 입력 상자를 가져온다. 즉, 사용자의 입력값을 가져오는 객체이다.
v7 = objc_retainAutoreleasedReturnValue(v6);
→
v6 = objc_msgSend(v5, "text");
→
v5 = objc_retainAutoreleasedReturnValue(v4);
→
v4 = -[ViewController theTextField](self, "theTextField", a3);
Step9) 그렇다면 사용자의 입력 값(v7)과 v11을 비교해서 v7이 v11과 같다면 'Congratulations!'를 출력하게 된다. v11이 무엇인지 찾아야 한다. v11의 흐름을 따라가 보면 마지막 v8에서 현재 ViewController 화면에서 theLabel이라는 UILabel 객체를 가져와 v8에 저장하는 것으로 추측된다.
v11 = objc_retainAutoreleasedReturnValue(v10);
→
v10 = objc_msgSend(v9, "text");
→
v9 = objc_retainAutoreleasedReturnValue(v8);
→
v8 = -[ViewController theLabel](self, "theLabel");
Step10) 해당 Label의 값을 보기 위한 후킹코드를 아래와 같이 작성했다. 후킹 코드를 실행하면 숨겨진 Label의 값을 얻을 수 있다.
if (ObjC.classes.ViewController) {
const method = ObjC.classes.ViewController["- theLabel"];
Interceptor.attach(method.implementation, {
onLeave: function (retval) {
console.log("\n[+] Hidden Label :", new ObjC.Object(retval));
}
});
}
코드 해석:
theLabel이라는 라벨이 언제 누구에 의해 호출되는지 확인하고 싶었다 → 그래서 [ViewController theLabel] 메서드를 후킹 해서 반환값(UILabel 객체)이 실제로 어떤 건지, 어떤 타이밍에 호출되는지 확인하려고 한 것이다 이 반환값을 읽기 위해, onLeave와 retval을 사용한 것이다.
코드 실행 후 입력 창에 아무 값이나 입력하면 Label의 값이 나타난다.
🚩Flag Revealed
'Mobile' 카테고리의 다른 글
[Mobile] Uncrackable_Level3 (3) | 2025.06.12 |
---|---|
[Mobile] Uncrackable_Level2 (3) | 2025.06.10 |
[Mobile] Uncrackable_Level1 (2) | 2025.06.09 |
[iOS] Sileo 필수 트윅 리스트 (0) | 2024.08.01 |
[Mobile] iOS 탈옥(Jailbreak) 방법 (2) | 2024.07.28 |