Android/InsecureBankv2

인시큐어뱅크 앱 취약점 - 취약한 인증 메커니즘

박연준 2023. 7. 3. 17:16

인시큐어뱅크 앱 취약점 - 취약한 인증 메커니즘

취약점 소개

취약한 인증 메커니즘은 정상적인 인증 절차를 우회하여 잘못된 인증으로 접근 권한을 취득하는 취약점이다.

 

취약한 인증 메커니즘은 다음과 같은 경우에 해당한다.

  • 적절하지 않은 앱 퍼미션 설정 여부
  • 서비스 권한 상승 행위에 대한 통제 여부
  • 기능에 대한 제한 또는 우회 금지 여부
  • 불필요하거나 사용하지 않는 액티비티 제거 여부
  • 인텐트 사용에 대한 안정성 여부
  • 마스터 키 취약점 대응 여부

이번 취약점에서는 AndroidManifest.xml을 액티비티 속성으로 로그인 인증 없이 권한을 우회해 볼 것이다.

취약점 진단

다음 코드는 AndroidManifest.xml 코드이다. 코드를 살펴보면 안드로이드 액티비티의 속성이 android.exported=”true”로 설정되어 있다는 것을 알 수 있다. 이 경우 다른 액티비티에서 인증 없이 접근할 수 있다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.insecurebankv2" >

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.SEND_SMS" />

    <!--
     To retrieve OAuth 2.0 tokens or invalidate tokens to disconnect a user. This disconnect
     option is required to comply with the Google+ Sign-In developer policies
    -->
    <uses-permission android:name="android.permission.USE_CREDENTIALS" /> <!-- To retrieve the account name (email) as part of sign-in: -->
    <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <!-- To auto-complete the email text field in the login form with the user's emails -->
    <uses-permission android:name="android.permission.READ_PROFILE" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <android:uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <android:uses-permission
        android:name="android.permission.READ_EXTERNAL_STORAGE"
        android:maxSdkVersion="18" />
    <android:uses-permission android:name="android.permission.READ_CALL_LOG" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.Holo.Light.DarkActionBar">
        <!--
        android:theme="@style/AppTheme"-->
        <activity
            android:name=".LoginActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".FilePrefActivity"
            android:label="@string/title_activity_file_pref"
            android:windowSoftInputMode="stateVisible|adjustResize|adjustPan">
        </activity>
        <activity
            android:name=".DoLogin"
            android:label="@string/title_activity_do_login" >
        </activity>
        <activity
            android:name=".PostLogin"
            android:exported="true"
            android:label="@string/title_activity_post_login" >
        </activity>
        <activity
            android:name=".WrongLogin"
            android:label="@string/title_activity_wrong_login" >
        </activity>
        <activity
            android:name=".DoTransfer"
            android:exported="true"
            android:label="@string/title_activity_do_transfer" >
        </activity>
        <activity
            android:name=".ViewStatement"
            android:exported="true"
            android:label="@string/title_activity_view_statement" >
        </activity>

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

        <receiver
            android:name=".MyBroadCastReceiver"
            android:exported="true" >
            <intent-filter>
                <action android:name="theBroadcast" >
                </action>
            </intent-filter>
        </receiver>

        <activity
            android:name=".ChangePassword"
            android:exported="true"
            android:label="@string/title_activity_change_password" >
        </activity>

    </application>

</manifest>

ADB를 이용하여 확인하는 명령어는 다음과 같다.

adb shell am start [앱이 설치된 주소] / [호출하고 싶은 패키지 주소]

 

다음과 같이 명령 프롬포트 창에서 nox_adb shell로 접속하고

am start com.android.insecurebankv2/com.android.insecurebankv2.PostLogin를 하면 아래의 이미지와 같은 매세지와 함께 로그인 없이 인증을 무시하고 바로 액티비티를 호출할 수 있다.

(PostLogin, WrongLogin, DoTransfer 등 원하는 패키지 입력 후 접속 가능)

다음과 같이 별도 로그인 없이 인증에 성공한 것을 확인할 수 있다.

대응 방안

  • 컴포넌트에 대한 접근은 외부에 허락하지 않는 것이 안전하다.
  • android:exported는 다른 앱의 컴포넌트에서 현재 액티비티를 불러올 수 있는지를 설정한다.
  • 만약 설정값이 “false”라면 이 액티비티는 같은 앱 혹은 같은 유저 ID를 가진 앱의 컴포넌트만 불러올 수 있다.
  • 즉, 특별한 경우가 아니라면 액티비티 속성은 android:exported=”false”로 설정하고, android:exported=”true”로 설정할 경우 별도의 인텐트 필터로 검증한다.