SVE-2021-20722 / CVE-2021-25440
1) APP info
* APP: FactoryCameraFB (com.sec.factory.camera) * REWARD: $10310 * DESCRIPTION: Read/write arbitrary files as system (UID 1000) user * Occur: FactoryCameraFB > CameraTestActivity
2) FactoryCameraFB (com.sec.factory.camera)
- FactoryCameraFB 앱은 디바이스의 카메라 테스트 모드 관련 시스템 앱(카메라 펌웨어 표준, phone/CAM FW 버전체크 등)이며 android_secret_code를 처리하는 기능을 포함(전화 창에 코드를 입력하면 다양한 테스트 모드 사용과 설정이 가능함).

3) 취약점 설명
< AndroidManifest.xml >

- FactoryCameraFB 앱은 android.uid.system(1000) 권한을 가짐.
- 인텐트 필터가 있고 exported 정의가 안되어 있기 때문에 외부에서 접근이 가능한 액티비티임.
- 안드로이드 11 이하에서는 인텐트 필터를 선언한 컴포넌트에서 exported를 명시적으로 선언하지 않아도 되며 디폴트는 exported=true로 간주됨.
- 안드로이드12 부터는 인텐트필터를 선언한 컴포넌트에서 exported를 명시적으로 선언해야 함.
< CameraTestActivity - onCreate >

- getIntent 메소드를 통해 onCreate에 전달된 인텐트를 받아 mIncomingIntetn에 저장하게 됨. 취약점은 mIncomingIntent로 인해 발생하며 우회 분기문은 getTestCode 밖에 없음.
< CameraTestActivity - onCreate - mIntentDecoder.getTestCode >

- getTestCode 파라미터는 공격자가 인텐트를 통해 원하는 값을 전달할 수 있음.
- getTestCode 내부의 decodeTestCode 함수는 인텐트를 파라미터로 받는데 전달 받은 인텐트의 testtype, arg1 ,arg2 ,arg3 ,arg4 파라미터를 검사함.
- 해당 인텐트 값을 rule.Arr에 있는 값과 맞춰 주면, return rule.textCode를 통해 취약점을 위한 분기문으로 갈 수 있음.
- 결과적으로 5개 파라미터는 조작된 인텐트로 전달이 가능하므로 분기를 정할 수 있음.
< CameraTestActivity - onResume >

- 취약점을 트리거하기 위해선 onResume 메소드를 거쳐야함. > mIncomingIntent에 저장된 인텐트를 호출.
- isCameralyzerTest 메소드나 device_policy 서비스를 통해 카메라가 작동이 가능한지 체크하고 카메라 프레그먼트 설정 과정을 거치고 인텐트 내용과 파라미터를 체크함.
- mTestCode가 “TestCode.None”이 아닌지 체크함 > mTestCode는 onCreate에 getTestCode 메소드로 받아옴.(조작 가능)
- 이후에 mTestCode와 외부에서 전달받은 인텐트를 runTest 함수에 전달.
< FactoryCameraFragment - runTest >

- onResume에서 만든 프레그먼트가 isResumed인지 체크함.
- isRestrictedTestByOsVersion에서는 Build.VERSION.SDK_INT를 통해 최신 sdk 버전인지 체크하고 구버전이면 True를 리턴 최신버전이면 False
- CameraTestActivity.printAllExtra를 통해 전달받은 파라미터들을 다 출력하고 sendResultAndFinish 메소드를 호출.(getActivity(): Fragment에서 Activity를 호출)
< CameraTestActivity - sendResultAndFinish >

- int형 파라미터 하나를 받는 sendResultAndFinish가 먼저 호출이되고 또 다른 오버로딩된 sendResultAndFinish 메소드를 호출하게 됨.
- 취약점은 sendResultAndFinish의 setResult, finish 메소드에서 발생하며 setResult의 파라미터로 onCreat에서 인텐트로 받았던 mIncomingIntent를 넘김.
- setResult 메소드는 액티비티 간의 데이터를 주고 받을 때 사용하는데 주로 startActivityForResult 메소드와 함께 사용됨.
- 단순 액티비티를 실행하는 startActivity와는 달리 startActivityForResult는 액티비티를 실행하고 그 결과를 받아오는 기능까지 수행함. setResult가 startActivityForResult의 결과를 세팅해주는 역할을 수행함.
- 결과적으로 setResult에 전달되는 인텐트를 마음대로 조작할 수 있다면 공격자의 앱에서 startActivityForResult를 구현하고 setResult 통해 조작된 인텐트를 실행한 뒤 결과를 받을 수 있음.
4) Payload

- 페이로드는 13번줄의 startActivityForResult를 통해 결과를 받아올 액티비티를 실행하고 16번줄의 onActivityResult를 통해 결과를 받아 출력함.
- 간단한 취약점에도 만 달러 이상 받을 수 있었던 이유는 취약점을 2개 사용했기 때문.(5번줄에 해당)
- 취약점 2개는
FactoryCameraFB + com.sec.imsservice com.sec.imsservice서비스 취약점은 파일 프로바이더에서 발생하는데, 파일프로바이더 기본 경로를 지정하는 xml이 외부에서 접근 가능하기 때문에 발생함. 이를 이용하여 더 상위에 있는 디렉토리의 파일에 접근 가능- 결과적으로 FactoryCameraFB 취약점으로 인텐트를 조작할 수 있고 com.sec.imsservice를 통해 상위 디렉토리에 접근 가능.
< com.sec.imsservice - AndroidManifest.xml >
< com.sec.imsservice - res/xml/imfilepath.xml >

- com.sec.imsservice 앱은 FactoryCameraFB와 같이 시스템 권한을 가진 앱임.
- 프로바이더에 authorities는 com.sec.internal.ims.rcs.fileprovider이고 grantUriPermissions가 true이기 때문에 외부에서 권한 설정만 해주면 접근이 가능함.
- 가장 중요한 부분은 resource에 프로바이더가 접근하는 시작 경로가 설정되어 있는데 res/xml/imfilepath.xml를 보면 root 경로로 설정되어 있음.
- imsservice로 인해 페이로드의 5번줄은 결과적으로 아래와 같음.
content://com.sec.internal.ims.rcs.fileprovider/./data/system/users/0/settings_secure.xml
- 그러므로 임의의 파일 /data/system/users/0/settings_secure.xml(-rw ——- 1 system system)을 읽어올 수 있음.
Ref.
https://blog.oversecured.com/