상세 컨텐츠

본문 제목

CVE-2016-3918 : 이메일 정보유출 취약점 분석

국내외 보안동향

by 알약(Alyac) 2016. 10. 17. 16:55

본문

CVE-2016-3918 : 이메일 정보유출 취약점 분석


구글이 2016년 10월 공개한 Nexus Security Bulletin에는 360 Alpha Team이 제보한 CVE-2016-3918 취약점이 포함되어 있습니다. 구글은 해당 취약점을 높은 위험 등급으로 분류했습니다. 


공격자가 해당 취약점을 이용할 경우, 악성앱이 이메일의 내용, 첨부파일 및 계정정보를 탈취할 수 있습니다. 현재 구글은 해당 취약점에 대하여 이미 패치를 완료하였으며, OEM 업체들에게 관련 패치를 배포하였습니다. 



취약점 원인


안드로이드 AOSP의 Email 앱 코드 중, AndroidManifest.xml 파일에 있는 ContentProvider에서 AttachmentProvider라는 이름의 파일이 존재하는 것을 확인하였습니다. 


<provider

    android:name=".provider.AttachmentProvider"

    android:authorities="com.android.email.attachmentprovider"

    android:grantUriPermissions="true"

    android:exported="true"

    android:readPermission="com.android.email.permission.READ_ATTACHMENT"

    />


주요 속성은 다음과 같습니다. 


exported true : 외부에 해당 컴포넌트 접근 허용

authorities com.android.email.attachmentprovide : URI 유일한 표기방식

readPermission com.android.email.permission.READ_ATTACHMENT : 읽기는 해당 권한이 필요


com.android.email.permission.READ_ATTACHMENT Permission의 속성 중, protectionLevel은 dangerous로 설정되어 있습니다. 이는 제 3의 앱이 접근할 수 있다는 것을 의미합니다.


<permission

    android:name="com.android.email.permission.READ_ATTACHMENT"

    android:permissionGroup="android.permission-group.MESSAGES"

    android:protectionLevel="dangerous"

    android:label="@string/permission_read_attachment_label"

    android:description="@string/permission_read_attachment_desc"/>


ContentProvider에 제 3의 앱이 접근한 후, 전문가들은 AttachmentProvider의 코드를 찾아보았습니다. 코드 경로는 다음과 같습니다. 


/packages/apps/Email/provider_src/com/android/email/provider/AttachmentProvider.java


이후 인터페이스를 구현하는 것을 확인하였으며, 해당 인터페이스는 ParcelFileDescriptor의 파일을 열 수 있는 호출자를 반환합니다.  


public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {


openFile 인터페이스에 들어가면 mode 값이 "w"인지 확인하며, 만약 "w"라면 쓰기가능한 파일 디스크립터(File Descriptor)를 반환합니다. 


그러나 반환 전에 호출자가 com.android.email.permission.ACCESS_PROVIDER 권한이 없다면, 함수에 대한 구현 코드에서는 예외가 발생합니다. 해당 권한 정의는 다음과 같습니다. 


<permission

    android:name="com.android.email.permission.ACCESS_PROVIDER"

    android:protectionLevel="signature"

    android:label="@string/permission_access_provider_label"

    android:description="@string/permission_access_provider_desc"/>


해당 권한은 제 3의 앱이 획득할 수 없기 때문에, 쓰기권한을 획득하는 것은 불가능합니다.


List<String> segments = uri.getPathSegments();

String accountId = segments.get(0);

String id = segments.get(1);

String format = segments.get(2);

if (AttachmentUtilities.FORMAT_THUMBNAIL.equals(format)) {

    int width = Integer.parseInt(segments.get(3));

    int height = Integer.parseInt(segments.get(4));

    ...

}

else {

    return ParcelFileDescriptor.open(

        new File(getContext().getDatabasePath(accountId + ".db_att"), id),

            ParcelFileDescriptor.MODE_READ_ONLY);


코드의 다음 줄에서 uri.getPathSegments() 각기 다른 필드로 분할하고, 해당 필드에 상응하는 매개변수를 읽어옵니다. Format 매개변수가 "THUMBNAIL"가 아닐 경우, 해당 코드는 바로 getDatabasePath() 목록 하위의 id라는 이름을 가진 파일의 파일 디스크립터를 반환합니다. 


id매개변수는 위의 uri.getPathSegments().get(1)에서 획득한 것으로, 획득한 후 어떠한 처리도 하지 않습니다. 


uri.getPathSegments() 함수는 "/"로 문자열을 나누지만, 이는 URL 인코딩된 문자열에 대한 디코딩을 진행하지 않습니다. 따라서 처리 과정 중에 "/"의 인코딩 문자열인 "%2f"에 대한 어떠한 처리도 하지 않으며, getPathSegments를 나누는 것을 우회합니다.



취약점 악용


윗부분에서 코드에 대해 분석한 것을 근거로 전문가들은 AttachmentProvider의 uri를 획득할 수 있습니다. 


content://accountId/id/format/width/height


만약 해당 취약점을 이용하여 데이터를 읽고 싶다면, 프로그램을 목표 위치에서 실행시켜야 합니다. 이를 위해서 다음과 같은 구조의 uri가 필요합니다. 


content://com.android.email.attachmentprovider/1/file_position/1/1/1


또한 getDatabasePath()의 디렉토리는 /data/user/0/com.android.email/databases/입니다. Email의 데이터를 읽고 싶다면, 목표 디렉토리를 /data/data/com.android.email/로 바꾸어 Email 앱의 sqlite DB문서를 읽어야 합니다. 이를 위해서 다음과 같은 형식의 uri가 필요합니다. 


content://com.android.email.attachmentprovider/1/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fdata%2Fdata%2Fcom.android.email%2Fdatabases%2FEmailProvider.db/1/1/1


EmailProvider.db 중에는 이미 등록해 놓은 아이디와 비밀번호가 저장되어 있습니다. 이에 대응되는 구조는 HostAuth표의  login과 password필드입니다.







출처

http://bobao.360.cn/learning/detail/3107.html

관련글 더보기

댓글 영역