반응형

시작하기 전에 사실 지금 나는 UnCrackable을 풀 이유는 없다.

 

대부분 UnCrackable은 모바일 취약점을 진단하는 입문자용으로 많이 쓰인다.

 

하지만 나도 처음에 모바일 취약점을 진단할 때를 생각해보면 조금 진입장벽이 높았다고 생각했다.

 

나처럼 처음에 어떻게 진단을 해야할까? 라는 사람에게 조금 도움이 되었으면 하는 바람이다.

 

또한 나중에 스스로 해결하고 생각할 수 있도록 풀이과정을 전부 다 포스팅하지 않을 것이다.

 

다만 해당 문제의 출제 원리를 자세히 설명할 것이다.

 

아래의 내용을 제대로 이해했다면 나머지도 금방 혼자서 해결할 수 있을 것이다.

 

그럼 시작!!!

 

UnCrackable에 대해서 짧게 설명하자면

 

OWASP에서 만든 모바일 테스트용 앱으로써, AoSiOS가 있다.

 

인터넷에 조금만 검색해보면 Level 1 apk 파일을 구할 수 있다.

 

Level 1의 apk 파일을 구했다면 테스트 단말기에 설치해준다.

 

 

앱을 단말기에 설치하면 다음과 같은 앱 아이콘이 보이며 실행하면 다음과 같은 문구가 뜬다.

 

 

Root detected!

 

모의해킹 직무를 하다 보면 모바일 진단을 하는 경우가 많다.

 

그리고 위와 같은 루팅이 탐지되었다는 문구를 수도 없이 많이 봤을 것이다.

 

따라서 이 앱을 실행하기 위해서는 Level 1에서 루팅 탐지 로직을 우회하여야 한다.

 

이것이 모바일 진단에서 가장 중요한 작업이다.

 

요즘 대부분 앱에서는 이러한 루팅 탐지디버깅 탐지 등 수많은 탐지 로직이 실행되고 있으며 

 

진단을 하기 위해서는 가장 첫 번째인 루팅 탐지를 우회하여야 한다.

 

(참고로 이 정도 난이도는 상용 앱에서는 거의 없다고 보면 된다.)

 

그럼 해당 문구가 어떻게 어떤 로직으로 인해 루팅이 탐지되었는지 살펴보자.

 

Level 1은 가장 처음 시작하는 부분이 sg.vantagepoint.uncrackable1.MainActivity이다.

 

그렇다면 sg.vantagepoint.uncrackable1.MainActivity을 살펴보기 위해

 

앱을 디컴파일해서 static 분석을 진행해보자.

 

 

앞에서 봤던 문구를 소스코드단에서 볼 수 있다.

 

먼저 onCreate 메소드를 보면 if문 안에

 

 if((c.a()) || (c.b()) || (c.c()))가 존재한다.

 

(c.a()) || (c.b()) || (c.c())) 이 3개의 메소드 중 하나만 true여도 this.a라는 메소드가 실행되어

 

"Root detected!"라는 문구를 볼 수 있을 것이다.

 

그럼 (c.a()) || (c.b()) || (c.c()))라는 메소드를 모두 false로 만들어 줘야 한다.

 

c.a() 메소드를 살펴보자.

 

 

먼저 c.a 메소드이다.

 

java.lang.System.getenv 메소드는 현재 시스템의 환경변수 값을 얻어오는 메소드이다.

 

환경변수를 얻어온 값에서 :split 한 값을 for문을 loop 한다.

 

loop 하는 과정에서 File.exists() 메소드를 통해

루트 권한을 얻는 su 명령어(바이너리)가 존재하면 return 1을 하는 로직이다.

frida로 해당 System.getenv 메소드와 c.a()의 return 값을 찍어보자.

먼저 System.getenv 메소드의 return 값은 다음과 같다.

 

 

return 값을 :로 split 했기 때문에 String v0에는 다음과 같이 들어갈 것이다.

 

 

for문 로직을 살펴보자.

 

v0[0]에는 "/sbin"이라는 문자열이 들어가 있다.

 

그렇다면 for문에서 다음과 같이 실행될 것이다.

 

 

테스트용 단말기에 /sbin 디렉토리에 su라는 바이너리가 있는지 확인해보자.

이렇게 su라는 바이너리가 존재한다.

 

따라서 c.a()는 return 1이 되면서 루팅이 탐지되는 것이다.

 

 

이처럼 c.a()와 c.b(), c.c()를 우회해주면 루팅 우회는 끝이 난다.

 

밑의 사진은 c.a()와 c.b(), c.c()를 후킹 하여 루팅 체크 로직을 우회한 모습이다.

 

 

이제 문제에서 원하는 Secret String을 찾아야 한다.

 

사실 위의 루팅 우회Secret String을 우회하는 방법은 한 가지가 있는 것이 아니라

 

여러 가지가 있다.

 

Level 1 문제에서 후킹 포인트가 너무 많다.

 

하지만 Level 1에서 만든 문제의 출제 의도에 맞게 풀어보는 것을 추천한다.

 

다시 돌아와서 핵심은 빨간 박스다.

 

a.a(v4)라는 값이 true이면 된다는 의미이다.

 

a.a 메소드를 살펴보자.

 

마찬가지로 핵심은 빨간색 박스이다.

 

사진이 조금 잘리긴 했지만 우리가 Enter the Secret String에 입력하는 값이 arg5에 저장된다.

 

 

그 후 입력했던 arg5값과 아래의 sg.vantagepoint.a.a.a 메소드에서 return 된 값이 같다면

 

그 값이 Secret key가 된다.

따라서 sg.vantagepoint.a.a.a에서 return 되는 값을 알아내고 입력한다면

 

Level 1을 clear 할 수 있다.

 

sg.vantagepoint.a.a.a 메소드를 살펴보자.

 

sg.vantagepoint.a.a.a 메소드를 보면 AES/ECB/PKCS7Padding라는 문구가 보인다.

 

이것은 AES 암호의 한 종류이다.

 

AES 암호와 관련이 있다는 말이다.

 

그렇다면 AES 암호를 하기 위해서는 key가 있어야 한다. (대칭키 암호이기 때문)

 

또한 암호화 과정이면 평문이 있어야 하고

 

복호화 과정이면 암호화된 암호문이 있어야 할 것이다.

 

이것은 v2.init(2, v0)을 보면 알 수 있다.

 

init에 첫 번째 인자가 1이면 암호화 과정이고

 

2이면 복호화 과정이다.

 

init의 두 번째 인자는 key이다.

 

keyv0의 변수가 들어가 있으며

 

v0SecretKeySpec v0 = new SecretKeySpec(arg2, "AES/ECB/PKCS7Padding")을 나타낸다.

 

v0 SecretKeySpec(arg2, "AES/ECB/PKCS7Padding")리턴 값으로 arg2값이 필요하다.

 

arg2값은 앞의 메소드에서 본 byte값을 의미한다.

 

이렇게 key 셋팅과 AES 셋팅이 끝나면 dofinal 메소드로 복호화를 진행한다.

 

dofinal에는 arg3값이 인자로 들어가 있는데

 

arg3은 앞의 메소드에서 Base64 decode 한 값이 들어간다.

 

이것이 바로 암호문이며 이것을 복호화를 한다면 문제에서 원하는

 

즉 Level 1의 출제의도인 Secret key를 얻을 수 있는 것이다.

 

 

위의 과정을 코드를 작성해도 좋고 후킹을 해도 좋고 방법은 여러 가지이다.

 

밑의 사진은 위의 과정을 코드로 작성하여 Secret key를 구한 모습이다.

 

 

 

반응형

'모바일 해킹 > AoS' 카테고리의 다른 글

[UnCrackable AoS] Level 3  (0) 2022.03.24
[UnCrackable AoS] Level 2  (0) 2022.03.23
[Android] NDK란??  (0) 2022.03.09
[Android] Frida 설치  (0) 2022.01.23
Byte Code & Binary Code  (2) 2021.11.09

+ Recent posts