안드로이드 탐지 및 우회/루팅 탐지 및 우회

ANDITER를 활용한 프로세스 기반의 루팅 탐지 및 우회 방법

naroSEC 2023. 6. 11. 01:34

들어가기 앞서

2023.06.01 - [안드로이드] - ANDITER를 활용한 시스템 속성 기반의 루팅 탐지 및 우회 방법

 

ANDITER를 활용한 시스템 속성 기반의 루팅 탐지 및 우회 방법

들어가기 앞서 2023.05.31 - [안드로이드] - ANDITER를 활용한 Writeable 기반의 루팅 탐지 및 우회 방법 ANDITER를 활용한 Writeable 기반의 루팅 탐지 및 우회 방법 들어가기 앞서 이전 포스팅에 이어 시스템

naro-security.tistory.com

이전 포스팅에 이어서 백그라운드 프로세스를 통한 탐지 방법과 또 이를 공격자의 관점에서 어떻게 우회할 수 있는지 다뤄보겠다.

 

실습 진행에 사용되는 ANDITER 앱은 아래의 Github에서 다운로드 가능하다.

 

GitHub - naroSEC/Anditer

Contribute to naroSEC/Anditer development by creating an account on GitHub.

github.com


개요

[그림 1] Bypass Check Process 탐지

애플리케이션은 크게 두 가지로 구분되어 나눠진다. 쇼핑몰, 은행, 학교 행정 업무 등과 같은 사용자 편의성을 위해 만들어진 애플리케이션과 관리자 권한을 획득해 시스템 설정 변경, 데이터 위 변조 등 분석 및 악의적인 목적을 가지고 만들어진 애플리케이션이다. 그리고 후자의 경우 대부분이 관리자 권한을 필요로 하는 루팅 전용 애플리케이션들로 Magisk Manager, MT Manager, Game Guardian 등이 있으며, 이들은 백그라운드 프로세스에서 동작하다가 필요시 사용자에 의해 호출된다.

 

Bypass Check Process 항목은 디바이스에서 실행 중인 프로세스 목록을 확인해 Magisk와 같은 특정 애플리케이션들이 동작 중인지 확인하고 동작 중이면 루팅 디바이스로 판단해 탐지하게 된다.


분석

[그림 2] isCheckRootingProcesses() 함수 소스코드

[그림 2]isCheckRootingProcesses() 함수는 Bypass Check Process 탐지 결과를 반환해 주는 역할을 한다. 코드를 살펴보면에서 psef 문자열을 isRootCommand() 함수의 인수 값으로 전달해 그 결괏값을 반환받고 있다.

에서는 contains() 함수를 통해 반환받은 결괏값이 magisk라는 문자열이 포함되어 있는지 검사하고 있으며, 해당 문자열을 포함하고 있다면, true를 반환해 루팅 디바이스로 탐지하게 된다. 참고로 코드에서 사용된 ps 명령어는 현재 실행 중인 프로세스 목록 및 상태를 출력해 준다.

 

[그림 3] isRootCommand() 함수 소스코드

[그림 3]isCheckRootingProcesses() 함수에서 ps 명령어 동작을 위해 사용됐던 isRootCommand() 함수의 코드이다. 코드를 살펴보면 조금 특이한 점이 있는데 바로 ①에서 사용된 su 명령어이다.

su 명령어는 이전에도 언급했듯이 디바이스에서 일반 사용자가 관리자 권한을 획득하기 위해 사용하는 명령어로 주로 루팅 전용 애플리케이션들에서 사용된다. 해당 명령어가 여기서 사용된 이유는 프로세스 목록에 접근하기 위해서는 관리자 권한이 필요하기 때문이다. ②에서는 ①을 통해 획득한 su 권한을 가진 프로세스를 이용해 인수로 전달되는 명령어를 수행하게 된다.

 

[그림 4] 애플리케이션 권한으로 ps 명령어 수행한 결과
[그림 5]  관리자 권한으로 ps 명령어 수행한 결과

[그림 4]는 ANDITER 애플리케이션 권한으로 ps 명령어를 수행한 결과이고 [그림 5]는 관리자 권한으로 ps 명령어를 수행한 결과이다. 두 그림을 보면 알 수 있듯이 똑같은 명령어라도 어떤 권한을 가지고 동작되냐에 따라 결과가 달라진다. 이러한 결과가 나타나는 이유는 바로 Android 보안 모델 때문이다.

예전 Android 버전에서는 일반 사용자 권한이라도 프로세스 목록에 접근할 수 있었으며, isRootCommand() 함수와 같이 Runtime 클래스의 exec() 함수를 사용하지 않더라도 Java API를 통해 실행 중인 프로세스 상태 값 확인이 가능했다.

하지만, Android OS 버전이 업그레이드되면서 보안 모델도 함께 강화되어 이제는 일반 사용자 권한으로 확인이 불가해졌다. 때문에, [그림 3] 코드에서 프로세스 목록 확인을 위해 su 명령어가 사용됐지만 상용 애플리케이션에서는 이와 같은 방법보다는 su 명령어 사용 가능 유무를 통해 루팅 디바이스를 탐지하는 경우가 더 많다.

 

Bypass Check Process 탐지를 우회하기 위한 후킹 포인트는 세 가지가 있다. 첫 번째는 함수 결과 상관없이 무조건 false를 반환하도록 isCheckRootingProcesses() 함수를 재 작성하는 방법이고 두 번째는 equals() 함수 호출 시 전달되는 인수 값을 변조하는 방법이다. 그리고 세 번째는 isRootCommand() 함수의 매개 변수로 들어오는 문자열을 검사해 psef일 경우 더미 값으로 변조하는 방법이다. 여기서는 세 번째 방법을 사용해 탐지를 우회해 보도록 하겠다.


우회 실습

[그림 6]  isRootCommand() 함수를 후킹하기 위한 Frida 스크립트

[그림 6]isRootCommand() 함수를 후킹하기 위해 필자가 작성한 Frida 스크립트이다. 코드를 보면 에서 RootTools 클래스 사용을 위해 클래스 객체를 반환 받고 isRootCommand() 함수를 오버로딩으로 구현한다.

에서는 isRootCommand() 함수로 들어오는 매개 변수 값을 검사해 psef인 경우 더미 값으로 변조하고 변조한 더미 값을 인수로 원본 isRootCommand() 함수를 호출해 그 결과를 반환하게 된다.

 

[그림 7]  Bypass Check Process 우회 성공

Frida를 통해 작성한 스크립트를 ADITER 애플케이션에 어태치 한다. 그 후 Bypass Check Process 탐지 항목을 체크하면 Success! 가 출력되며 탐지가 우회된 것을 볼 수 있다.


마무리

지금까지 백그라운드 프로세스에서 동작 중인 루팅 전용 앱들을 검사해 루팅을 탐지하는 방법과 또 이를 공격자의 관점에]서 어떻게 우회할 수 있는지 살펴보았다. 다음 포스팅부터는 앱 동적 분석 시 사용하는 디버깅을 탐지하는 방법과 우회 방안에 대해 알아보겠다.