짱짱해커가 되고 싶은 나

[안드로이드 취약점 진단] 3-8. 안전하지 않은 콘텐츠 프로바이더 접근 본문

모바일

[안드로이드 취약점 진단] 3-8. 안전하지 않은 콘텐츠 프로바이더 접근

동로시 2022. 6. 22. 14:42

콘텐츠 프로바이더

콘텐츠 프로바이더를 사용해 안드로이드는 자신의 데이터에 다른 apk가 접근하거나 부여한 권한대로 이용할 수 있도록 해준다. ex. DB, 파일 접근, IPC 역할 (다른 apk과 데이터 공유)

-> 애플리케이션의 DB에 접근하는게 아니라 사용자가 원하는 항목에만 접근하도록 할 수 있음

 

AndroidMainfest.xml에 <provider> 요소로 정의되며 Content Provider의 주소인 URI Content Resolver가 필요하다.

(이 때 URI 형식은 content://authority/path 형식으로, content://로 시작하고 authority는 콘텐츠 프로바이더의 고유 주소, path는 데이터 위치에 대한 정보를 의미한다.)

-> 취약하다면 공격자가 민감한 데이터에 접근해 조회 및 변경이 가능할 수 있다.

 

인시큐어뱅크 - Insecure Content Provider access

AndroidMainfest.xml

provider는 1개가 정의되어 있다. 이름은 TrackUserContentProvider이고 exported=true로 설정되어 있다.

이 provider는 TrackUserContentProvider에서 사용된다.

 

TrackUserContentProvider

코드를 보면 DB 정보와 콘텐츠 프로바이더의 주소 정보를 확인할 수 있다.

데이터베이스 이름은 mydb 이고 테이블 이름은 names이며 id와 name 칼럼이 사용된다.

SQLite를 사용하고 db 버전은 1이다.

콘텐트 프로바이더의 주소는 content://com.android.insecurebankv2.TrackUserContnetProvier/trackusers다.

코드를 자세히 분석해보자.

먼저 uriMatcher.addURI를 통해 프로바이더가 지원하는 요청 Uri를 등록해준다. provider/trackusers/로 시작하면 된다.

그리고 등록한 uri랑 매치될 경우 delte함수에서는 db.delete(테이블, where 절, where 인자)를 통해 정해진 조건에 해당하는 delte 쿼리를 실행한다. 그리고 content resolver들에게 DB의 내용이 변경됐다는 사실을 알린다.

getType 함수에서는 uri가 매치하면 vnd.android.cursor.dir/u를 반환한다.

insert함수는 db.insert를 수행한다. ContentValues는 자바의 map 같은 걸로(key,value) 형식이다.

insert를 성공할 경우 withAppendedId를 통해 콘텐츠 uri에 id를 추가합니다. (insert 반환값 = idx로 설정)

그리고 마찬가지로 컨텐츠 리솔버에게 알린다. update도 유사하다.

query 함수는 SQLiteQueryBuilder를 사용해서 사용할 테이블을 설정하고, uri가 매치할 경우 쿼리를 생성한다. 이 때 쿼리에 들어가는 인자는 '사용할 db, 값을 가져올 컬럼 이름의 배열, where 구문, where 구문에 들어가는 인자값, group by 구문, order by 구문, having 구문' 순이다. 테이블 이름을 제외하고 각 값이 필요없다면 null을 지정한다.

따라서 여기서는 query 함수의 인자에 콘테츠 프로바이더 uri, 사용할 컬럼 배열, where 절, where 인자, having 구문이 들어간다. 만약에 별도로 having 구문 값으로 들어오는게 없으면 name을 이용한다.

-> 우선 db에 접근하기 때문에 sql injection이 가능한가? 라는 의문이 드는데 query로 다 정해져있어서 가능할지 아직 모르겠다.

-> having은 group by랑 같이 사용되야 하는걸로 아는데  groupby 구문이 null인데,, 흠

 

 

adb를 통해서 콘텐츠 프로바이더 취약점을 확인하려면 다음과 같이 query --uri 명령어를 사용해서 들어있는 데이터를 확인할 수 있다. 내용을 보면, 느낌상 로그인한 기록 같아 보이고 contentresolver 쓰는 모습을 보면 mydb에서 가져온 내용일 것 같다.

 

앱에는 mydb 하나가 있고 adb pull 명령어를 통해 추출했다.

 

names 테이블의 내용을 보면 똑같이 나오는걸 볼 수 있다.

아마 저기서 이름별로 정렬되는건 name으로 묶어서 그런 것 같다.

우선, 이처럼 exported=true여서 해당 컨텐츠 프로바이더에 접근할 수 있어서 데이터가 유출되는 취약점을 확인할 수 있다.

 

아까 의문이었던 SQL Injection이 가능한지 한 번 테스트해보자.

'가 그대로 SELECT 문 안에 그대로 들어가진다. 

기존 sql injection 할 때 하듯이 db를 모른다고 가정하고 sqlite의 master db 정보에서 테이블을 확인하고 뒤에 명령어인 FROM names ORDER BY name은 주석처리해준다.

그럼 이제 테이블이름이 names고 id, name 칼럼을 갖고 있다. 안에 내용 보면 동일

-> 근데 SQL injection이 가능해서 중요한 정보를 갖는 db가 있으면 그 내용을 모두 획득할 수 있는 취약점이 있다.

 

대응 방안

1. exported=false

콘텐츠 포로바이더를 통해 애플리케이션의 데이터가 유출되지 않도록 exported=false 처리한다.

-> 이렇게 하면 콘텐츠 프로바이더의 uri 주소를 통해 접근하면 권한이 없기 때문에 결과값을 보여주지 않는다.


ps. 드로저

드로저를 통해서 취약점을 찾을 때는 app.package.attacksurface 명령어를 사용하면 된다. 

결과로 겉으로 드러나는 (즉, mainfest에 exported=true인 것) attack surface 목록을 보여준다.

run app.package.attacksurface com.android.insecurebankv2

콘텐츠 프로바이더 정보를 확인하려면 다음과 같은 명령어를 사용하면 되고 mainfest.xml에 있는 정보를 보여준다.

run app.provider.info -a com.android.insecurebankv2

추가적인 정보를 얻으려면 다음 명령을 사용해서 콘텐츠 프로바이더의 uri 주소를 검색해서 접근 가능한 목록을 보여준다. 결과로 모든 uri 주소와 접근 가능한 항목을 별도로 출력해주는데 여기서는 동일하게 trackusers의 uri가 나온다.

run scaaner.provider.finduris -a com.android.insecurebankv2

해당 콘텐츠 프로바이더를 통해 데이터를 출력하려면 다음과 같은 명령을 사용한다.

run app.provider.query content://com.android.insecurebankv2.TrackUserContentProvider/trackusers

 

Comments