가. 런타임 조작 취약점 및 대응방안
- 런타임 조작에 대한 설명 및 대응방안은 아래의 게시글을 참고하길 바란다.
[AOS App 취약점 진단 · 모의해킹] - [AOS 취약점 진단] 14강 - 런타임 조작 취약점 점검(Frida/ADB)
- 본글에서는 Frida 코드가 많이 나오므로, 초보자들은 아래의 게시글을 참고하여 실습을 진행하길 바란다.
[Mobile App 취약점 진단 · 모의해킹] - 프리다(Frida) 문법 및 후킹에 사용되는 함수 설명
나. Frida 설명 및 설치방법
- Frida Server/Client 설치방법은 아래의 게시글을 참고하길 바란다.
[AOS App 취약점 진단 · 모의해킹] - 안드로이드 프리다 서버/클라이언트 설치방법
다. FridaLab 설치방법
- 아래의 사이트에 접속하여 Download 버튼을 클릭, 다운로드된 FridaLab.apk 파일을 모바일 디바이스에 설치한다.
https://rossmarks.uk/blog/fridalab/
- FridaLab에서는 다음과 같은 항목을 실습할 수 있다.
실습 항목 | 실습 내용 |
1. Change class challenge_01's variable 'chall01' to: 1 | 클래스 challenge_01의 변수 chall01을 1로 변경하기 |
2. Run chall02() | chall02() 메서드 실행하기 |
3. Make chall03() return true | chall03() 메서드가 true 반환하게 만들기 |
4. Send "frida" to chall04() | chall04() 메서드에 frida 문자열 전송하기 |
5. Always send "frida" to chall05() | 버튼 클릭 시 chall05() 메서드에 frida 문자열 전송하기 |
6. Run chall06() after 10 seconds with correct value | 올바른 값으로 10초 후 chall06() 메서드 실행하기 |
7. Bruteforce check07Pin() then confirm with chall07() | chall07Pin() 메서드를 무차별대입공격으로 확인하기 |
8. Change 'check' button's text value to 'Confirm' | 'check' 버튼의 텍스트를 'Confirm'으로 변경하기 |
라. FridaLab 문제 풀이
1번 문제풀이 : Change class challenge_01's variable 'chall01' to: 1
- 아래의 링크에 접속하여 jadx-gui-x.x.x-with-jre-win.zip 파일을 다운로드한 뒤, 압축을 해제한다.
https://github.com/skylot/jadx/releases/tag/v1.4.7
- jadx-gui-x.x.x.exe를 실행한 뒤 'FridaLab.apk' 파일을 로드한 다음 challenge_01 클래스 파일을 열람한다.
- getChall01Int() 메소드의 반환값인 chall01 변수의 값을 1로 변경하는 것이 이 문제의 목표이다.
- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.
- 예제 1은 chall01 변수의 값을 변조하는 것이고, 예제 2는 함수 반환값 자체를 변조하는 것이다.
//후킹 예제 소스코드 1 : chall01 변수 값 조작
setImmediate(function(){
Java.perform(function(){
var Question_01 = Java.use("uk.rossmarks.fridalab.challenge_01");
console.log("[+] 변경전의 chall01 변수 값 : " + Question_01.chall01.value);
Question_01.chall01.value = 1;
console.log("[+] 변경후의 chall01 변수 값 : " + Question_01.chall01.value);
})
})
//후킹 예제 소스코드 2 : 함수 리턴 값 조작
setImmediate(function(){
Java.perform(function(){
var Question_01 = Java.use('uk.rossmarks.fridalab.challenge_01');
Question_01.getChall01Int.implementation = function(){
return 1;
}
})
})
- 위에서 작성한 코드를 PC의 frida client를 통해 실행시킨다.
//현재 디바이스에서 실행중인 앱 정보를 출력
frida-ps -Ua
//Frida Code 실행 명령어
//frida -U -l [파일경로] [PID/ProcessName/PackageName]
frida -U -l hagsig_hooking.js FridaLab
- 후킹코드를 실행한 다음 CHECK 버튼을 누르면 1번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.
2번 문제풀이 : Run chall02()
- chall02() 함수를 강제로 호출하는 게 목표인 문제이다. 문자열검색을 통해 chall02() 함수를 찾아낸다.
- 'MainActivity'에 chall02 메소드가 존재하는 것을 확인하였다. 런타임 조작을 통해 해당 메소드를 강제로 실행할 것이다.
- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.
- 두 예제는 동일한 결과를 내지만 클래스를 저장하고 호출하는 방식에 차이가 있다.
- 문자는 더블쿼터("), 싱글쿼터(') 중 무엇을 사용하든 상관없으면 본인에게 편한 방식을 사용하면 된다.
//후킹 예제 소스코드 1
setImmediate(function(){
Java.perform(function(){
var Question_02 = Java.choose("uk.rossmarks.fridalab.MainActivity",{
"onMatch" : function(Question_02){
Question_02.chall02();
},
"onComplete" : function() {
console.log("[+] chall02 메소드 호출 완료");
}
})
})
})
//후킹 예제 소스코드 2
setImmediate(function(){
Java.perform(function(){
var Question_02;
Java.choose('uk.rossmarks.fridalab.MainActivity',{
onMatch: function(instance) {
Question_02 = instance;
Question_02.chall02();
},
onComplete : function() {
console.log('[+] chall02 메소드 호출 완료');
}
})
})
})
- 후킹코드를 실행한 다음 CHECK 버튼을 누르면 2번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.
3번 문제풀이 : Make chall03() return true
- chall03() 메소드의 리턴값을 true로 변조하는 것이 목표인 문제이다.
- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.
//후킹 예제 소스코드
setImmediate(function(){
Java.perform(function(){
var Question_03 = Java.use("uk.rossmarks.fridalab.MainActivity");
Question_03.chall03.implementation = function(){
return true;
}
})
})
- 후킹코드를 실행한 다음 CHECK 버튼을 누르면 3번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.
4번 문제풀이 : Send "frida" to chall04()
- chall04() 메소드를 강제로 호출하면서 인자값으로 "frida" 문구를 입력하는 것이 목표인 문제이다.
- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.
//후킹 예제 소스코드 1
setImmediate(function(){
Java.perform(function(){
var Question_04 = Java.choose("uk.rossmarks.fridalab.MainActivity", {
"onMatch" : function(Question_04){
Question_04.chall04("frida");
},
"onComplete" : function() {
console.log("[+] chall04 메소드 호출 완료");
}
})
})
})
//후킹 예제 소스코드 2
setImmediate(function(){
Java.perform(function(){
var Question_04;
Java.choose('uk.rossmarks.fridalab.MainActivity', {
onMatch: function(instance) {
Question_04 = instance;
Question_04.chall04('frida');
},
onComplete: function() {
console.log('[+] chall04 메소드 호출 완료');
}
})
})
})
- 후킹코드를 실행한 다음 CHECK 버튼을 누르면 4번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.
5번 문제풀이 : Always send "frida" to chall05()
- 4번 문제와 같이 chall05()메소드 호출 시 인자값에 "frida" 문구를 입력하여 실행하는 것이 목표인 문제이다.
- 'MainActivity' 클래스의 chall05 메소드 내용을 보면 "frida" 문구 입력 여부로 성공/실패를 구분하는 것을 알 수 있다.
- 4번과 동일한 코드로 후킹을 시도하고 'CHECK' 버튼을 누르면 실패하는 것을 알 수 있다.
- 버튼 클릭 이벤트 onClick()의 소스를 보면 버튼 클릭 시 "notfrida!"가 입력되어 실패하는 것을 알 수 있다.
- chall05() 메소드가 호출될 때 무조건 "frida" 문구가 인자값으로 입력되도록 수정한다.
- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.
*overload와 implementation를 이해하지 못했다면, '가. 런타임 조작 취약점 및 대응방안'에 적힌 Frida 문법 설명 게시글을 참고하자.
//후킹 예제 소스코드
setImmediate(function(){
Java.perform(function(){
var Question_05 = Java.use("uk.rossmarks.fridalab.MainActivity");
Question_05.chall05.overload("java.lang.String").implementation = function(arg){
this.chall05("frida");
console.log("[+] chall05 메소드 오버로드 완료")
}
})
})
- 후킹코드를 실행한 다음 'CHECK' 버튼을 누르면 5번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.
6번 문제풀이 : Run chall06() after 10 seconds with correct value
- 10초가 지난 이후 chall06() 함수를 호출하면서 인자값으로 정확한 정수를 입력하는 것이 목표인 문제이다.
- 'MainActivity' 클래스의 chall06() 함수를 보면 challenge_06 클래스의 confirmChall06() 메소드를 호출하는 것을 알 수 있다.
- 그리고 앱 실행 시 가장먼저 실행되는 이벤트 메소드 onCreate()의 소스코드를 보면, 'challenge_06' 클래스의 startTime(), addChall06() 메소드를 실행하는 것을 알 수 있다.
- 특히 addChall06() 메소드는 0~50 사이의 랜덤값을 인자값으로 입력하여 호출하는 것을 알 수 있다.
- StartTime() 메소드는 현재 시간을 timeStart 변수에 저장한다.
*System.currentTimeMillis() : 1970년 1월 1일부터 경과한 시간을 1/1000초로 계산하여 long 타입으로 리턴한다.
- addChall06() 메소드는 변수 chall06에 인자값을 더하고, chall06의 값이 9000보다 크다면 입력된 값으로 지정한다.
- confirmChall06() 메소드는 입력된 인자값이 chall06 변수와 같고, 앱이 실행된지 10초가 지났으면 Ture(1)를 리턴한다.
- 후킹 시도로부터 10초 이후, 'MainActivity' 클래스의 chall06()메소드를 'challenge_06' 클래스의 변수 chall06 값을 인자값으로 입력하여 호출하는 후킹 소스를 작성한다.
- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.
//후킹 예제 소스코드 1
setImmediate(function() {
Java.perform(function() {
var Question_06 = Java.use('uk.rossmarks.fridalab.challenge_06');
Java.choose('uk.rossmarks.fridalab.MainActivity', {
onMatch: function(instance) {
console.log("[+] 10초 후 chall06 메소드가 실행됩니다");
setTimeout(function() {
console.log("[+] chall06 변수의 값 : " + Question_06.chall06.value);
instance.chall06(Question_06.chall06.value);
console.log("[+] chall06 메소드 후킹 완료");
}, 10000);
},
onComplete: function() {
}
})
})
})
//후킹 예제 소스코드 2
setTimeout(function(){
console.log("[+] 10초 후 chall06 메소드가 실행됩니다");
setImmediate(function(){
Java.perform(function(){
let main;
Java.choose("uk.rossmarks.fridalab.MainActivity", {
onMatch: function(instance) {
main = instance;
const Question_06 = Java.use("uk.rossmarks.fridalab.challenge_06");
Question_06.confirmChall06.implementation = function () {
console.log("[+] chall06 변수의 값 : " + Question_06.chall06.value);
return true;
}
main.chall06(1);
console.log("[+] chall06 메소드 후킹 완료");
},
onComplete: function() {}
});
})
})
}, 10000);
- 후킹코드를 실행한 다음 10초가 지나 완료문구가 출력되면 'CHECK' 버튼을 누른다.
- 6번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.
7번 문제풀이 : Bruteforce check07Pin() then confirm with chall07()
- 7번 문제는 무차별대입공격(brute-force attack)을 통해 정확한 pin코드를 입력하는 것이 목표인 문제이다.
- 'MainActivity' 클래스의 chall07() 메소드를 인자값을 입력하여 호출하면 'challenge_07' 클래스의 check07Pin() 메소드 반환값을 통해 성공/실패를 구분하는 것을 확인할 수 있다.
- 그리고 앱 실행 시 가장먼저 실행되는 이벤트 메소드 onCreate()의 소스코드를 보면, 'challenge_07' 클래스의 setChall07() 메소드를 실행하는 것을 알 수 있다.
- 'challenge_07' 클래스의 setChall07() 메소드는 4 자릿수 난수 값을 문자열 형 chall07 변수에 저장한다.
- check07Pin() 메소드는 입력된 인자값이 chall07 변수와 같은지 비교하여 true/false를 반환한다.
- 정확한 값을 입력할 때까지 4자리 난수 pin 코드를 생성하는 후킹코드를 작성한다.
- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.
//후킹 예제 소스코드 1
setImmediate(function(){
Java.perform(function(){
var Question_07 = Java.use("uk.rossmarks.fridalab.challenge_07");
Java.choose("uk.rossmarks.fridalab.MainActivity",{
onMatch : function(instance){
for(var i=9999; i>=1000; i--){
var hagsig = String(i);
if(Question_07.check07Pin(hagsig)){
console.log("[+] chall07 pin 값 :" + hagsig);
instance.chall07(hagsig);
break;
}
}
},
onComplete : function(){
console.log("[+] 7번 메소드 후킹 완료");
}
})
})
})
//후킹 예제 소스코드 2
setImmediate(function() {
Java.perform(function() {
var main;
Java.choose('uk.rossmarks.fridalab.MainActivity', {
onMatch: function(instance) {
main = instance;
},
onComplete: function() {}
});
var Question_07 = Java.use('uk.rossmarks.fridalab.challenge_07');
for (var i = 1 < 9999 ; i <= 9999 ; i++) {
var hagsig = i.toString(10);
if(Question_07.check07Pin(hagsig.padStart(4,'0'))) {
main.chall07(hagsig);
console.log("[+] chall07 pin 값" + hagsig);
break;
}
}
console.log("[+] 메소드 후킹 완료");
})
})
- 후킹코드를 실행한 다음 'CHECK' 버튼을 누르면 7번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.
8번 문제풀이 : Change 'check' button's text value to 'Confirm'
- 메인 화면 버튼의 텍스트를 'check'에서 'Confirm'으로 변경하는 것이 목표인 문제이다.
- 'MainActivity' 클래스의 chall08()을 호출하여 button의 텍스트가 "Confirm"인지 검사하여 참과 거짓을 반환한다.
참고) findViewById() 함수를 통해 R.id 클래스의 check 변수에 저장된 값을 통하여 View를 찾는다.
- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.
- 예제 1은 View의 ID를 직접 지정하여 버튼의 텍스트를 변조하는 것이고, 예제 2는 동적으로 ID를 찾아 버튼의 텍스트를 변조하는 것이다.
//후킹 예제 소스코드 1 : Button ID를 지정하여 변조
setImmediate(function() {
Java.perform(function() {
var klass = Java.use("android.widget.Button");
Java.choose("uk.rossmarks.fridalab.MainActivity",{
onMatch : function(instance){
var checkid = instance.findViewById(0x7f07002f);
var check = Java.cast(checkid, klass);
var string = Java.use("java.lang.String");
console.log("[+] 변경전 Button Text 값 : " + check.getText());
check.setText(string.$new("Confirm"));
console.log("[+] 변경후 Button Text 값 : " + check.getText());
},
onComplete : function(){
console.log("[+] 8번 메소드 후킹 완료");
}
})
})
})
//후킹 예제 소스코드 2 : Button ID를 알아내어 변조
setImmediate(function() {
Java.perform(function() {
var id = Java.use('uk.rossmarks.fridalab.R$id');
var check_id = id.check.value;
console.log("[+] check id : " + check_id);
var button = Java.use('android.widget.Button');
var main;
Java.choose('uk.rossmarks.fridalab.MainActivity', {
onMatch: function(instance) {
main = instance;
},
onComplete: function() {}
});
var check = Java.cast(main.findViewById(check_id), button);
console.log("[+] 변경전 Button Text 값 : " + check.getText());
var str = Java.use('java.lang.String');
check.setText(str.$new('Confirm'));
console.log("[+] 변경후 Button Text 값 : " + check.getText());
})
})
- 후킹코드를 실행한 다음 'CHECK' 버튼을 누르면 8번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.
https://takudaddy.tistory.com/622
https://snowjeon2.tistory.com/36
'Mobile App 취약점 진단 · 모의해킹 > AOS App 취약점 진단 · 모의해킹' 카테고리의 다른 글
[AOS 취약점 진단] 16강 - 루팅 탐지 우회 취약점 점검 (0) | 2024.02.25 |
---|---|
[AOS 취약점 진단] 15강 - 애플리케이션 패칭/앱 무결성 검증 취약점 (0) | 2024.02.19 |
[AOS 취약점 진단] 14강 - 런타임 조작 취약점 점검(Frida/ADB) (0) | 2024.02.19 |
[AOS 취약점 진단] 13강 - 웹 취약점 점검(SSL Pinning 우회) (0) | 2024.02.04 |
안드로이드 프리다 서버/클라이언트 설치방법 (0) | 2024.02.03 |