Insecurebankv2 - Insecure Content Provider access (취약한 컨텐트 프로바이더 접근)

우선 Content Provider에 대해서 간단하게 살펴보자.

 

[Content Provider]

- Content Provider는 애플리케이션이 자체적으로 저장한 데이터나 다른 애플리케이션의 데이터를 관리하고, 이를 다른 애플리케이션과 안전하게 공유할 수 있도록 돕는 표준 인터페이스다.
- 앱 데이터를 다른 앱에서 사용할 수 있는 통로를 제공한다고 생각하면 된다.
- Content Provider의 주소 URI는 "content://authority/path"와 같은 형식으로 구성된다.


++ 추가적으로 새롭게 알게된 내용!!
UriMatcher를 사용하면 ContentProvider에서 여러 URI 패턴을 처리할 수 있게 되는데, 이러한 패턴은 ContentProvider 내부의 URI 매핑 테이블에 등록되고, 이 테이블을 통해 어떤 URI 요청이 들어왔을 때 해당 요청을 어떤 방식으로 처리할지 결정된다.

만약 앱의 ContentProvider가 UriMatcher를 사용하고 있고, 그 ContentProvider가 exported=true로 설정되어 있다면, 외부 애플리케이션이 해당 URI에 접근할 수 있다. 이때, URI를 정확히 알아내기 위해서는 UriMatcher에서 사용된 패턴을 이해하고, 해당 패턴에 맞는 URI를 시도해보는 것이 중요하다.

일반적으로 UriMatcher는 아래와 같은 형태로 설정된다:

UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
matcher.addURI("authority", "path", SOME_CONSTANT);
matcher.addURI("authority", "path/#", ANOTHER_CONSTANT);


여기서 path나 path/#와 같은 패턴을 외부에서 유추할 수 있으면, adb shell content query --uri content://authority/path와 같은 명령어로 해당 ContentProvider에 접근하여 데이터를 쿼리할 수 있다.

따라서 취약점 점검 시에는 단순히 URI를 바로 사용하는 경우뿐만 아니라, UriMatcher를 통해서 유추할 수 있는 URI 패턴까지도 시도해볼 수 있다.

 


Insecurebankv2에서 취약한 Content Provider를 살펴보면 다음과 같이 진단해볼 수 있다.

 

Analysis

 

1. Androidmanifest.xml에서 선언된 Content Provider의 exported=true의 유무

아래와 같이 "TrackUserContentProvider" 이름의 provider의 exported=true를 확인할 수 있다.

        <provider
            android:name="com.android.insecurebankv2.TrackUserContentProvider"
            android:exported="true"
            android:authorities="com.android.insecurebankv2.TrackUserContentProvider"/>

 

2. content:// 확인

jadx의 검색기능을 통해 아래와 같이 com.android.insecurebankv2.TrackUserContentProvider 파일에서

uri 전체 주소를 확인할 수 있다.

 

3. 취약점 확인

확인된 uri 전체 주소를 갖고,

adb shell content query --uri [확인된 URI 전체 주소]  를 통해서 아래와 같이 사용자가 로그인한 내역을 확인할 수 있다.

 

추가적으로 Drozer를 사용해서 쉽게 Content Provider 공격 가능한 URI를 확인해볼 수 있었는데 그에 대한 방법은 아래와 같다. 우선 Drozer 설치 및 환경 구축은 이전 게시글인 https://benkyoblog.tistory.com/12 에서 참고하면 된다.

 

1. Content Provider URI 검색

run scanner.provider.finduris -a com.android.insecurebankv2 명령어를 통해서 아래와 같이 접근 가능한 목록이 출력되는 것을 확인할 수 있다.

scanner.provider.finduris -a package_name 명령어는 Content Provider의 URI 주소를 검색해서 접근 가능한 목록들을 찾아주고, Unable to Query와 Able to Query로 구분해서 실질적으로 Accessible한 content URI들의 목록까지 출력해준다.

 

2. 데이터 확인

run app.provider.query [Accessible한 URI 주소] 를 통해서 아래와 같이 adb를 통해 확인한 정보와 동일한 결과가 출력되는 것을 확인해볼 수 있다.

 

Content Provider는 대상 앱의 데이터베이스, 데이터 등 확인할 수 있기 때문에 Drozer를 통해 SQL Injection, 경로 탐색 등 진단도 가능하다.

Drozer로 SQL Injection을 아래와 같이 시도해보았다.

우선 싱글 쿼터를 사용해서 run app.provider.query [URI 주소] --projection "'" 명령어를 통해 취약점 존재를 아래와 같이 확인해보았고,

 

테이블 목록을 확인해보기 위해서, run app.provider.query [URI 주소] --projection "* from SQLITE_MASTER where type='table';--" 명령어를 통해서 SQLITE에 존재하는 테이블들을 확인했다.

 

이제 확인된 테이블들을 run app.provider.query [URI 주소] "* from [확인하고자 하는 테이블 이름];--" 명령어를 통해서 아래와 같이 모두 확인해볼 수 있었다.

 

Mitigation

- Content Provider를 통해서 앱 데이터 유출을 막기 위해 Androidmanifest.xml에서 Content Provider 선언시, exported를 true가 아닌 false로 선언한다. 이렇게 하면, 권한이 없다는 메세지와 함께 결과 출력이 되지 않는다.

- 같은 회사에서 여러 앱 서비스를 제공하고 해당 앱들간 데이터를 주고 받는 상황에서 해당 exported가 false로 선언이 되어 있다면, 데이터의 연결통로가 막히게 되므로 사용자의 편의성에 있어서 단점으로 발생할 수 있다. 취약점 진단시, 이런 부분들을 고려해서 확인해 볼 수 있을거 같다는 생각이든다.