티스토리 뷰

반응형

취약점 소개

브로드캐스트 리시버란 안드로이드 시스템의 중요 요소 중 하나이다.
브로드캐스트란 '방송하다'라는 의미가 있으며,
브로드캐스트 리시버는 '방송 수신자'라는 의미로 유추할 수 있다.
안드로이드 시스템에서 특정 이벤트가 발생 시 시스템은
시스템 브로드캐스트 메세지를 이벤트를 수신하도록 신청한 모든 앱에 보내고, 브로드캐스트는 이를 수신한다.



표준 브로드캐스트 액션에는

  • ACTION_SHUTDOWN
  • ACTION_TIME_TICK,
  • ACTION_BOOT_COMPLETE
  • ACTION_PACKAGE_ADD
  • ACTION_BATTERY_CHANGED
  • ACTION_POWER_CONNECTED

등이 있다.



즉, 브로드캐스트 리시버는 배터리가 충전되고, 시스템이 방전되고, 부팅이 완료되는 것 등의
시스템 브로드캐스트 메시지를 수신하여 사전에 정의된 작업을 수행하는 것이다.
만약 브로드캐스트 리시버가 안전하지 않게 설정되어 있는 경우,
사용자가 받는 메시지/전화 등의 알림을 중간에 가로채는 행위가 가능하며
특정 상황에서만 발생하는 작업을 수행하도록 악의적으로 조작할 수 있다.
인시큐어뱅크 앱에서 브로드캐스트 리시버가 포함된 코드의 취약성을 확인해본다.





취약점 진단 수행

브로드캐스트 리시버는 AndroidManifest.xml의 <receiver></receiver> 요소에 선언된다.
인시큐어뱅크 앱을 디컴파일하여
Insecurebankv2/app/src/main/AndroidManifest.xml 파일의
<receiver> 요소를 확인한 코드는 다음과 같다.



브로드캐스트 리시버 요소 확인

<receiver
    android:name=".MyBroadCastReceiver"
    android:exported="true" >
    <intent-filter>
        <action android:name="theBroadcast" >
        </action>
    </intent-filter>
</receiver>
표 3-1 브로드캐스트 리시버 취약한 코드



브로드캐스트의 이름은 theBroadcast로,
exported="true"로 인해 외부 앱으로부터 Intent 객체를 받을 수 있다.
브로드캐스트 신호를 받을 시
MyBroadCastReceiver라는 메서드에 설정된 작업을 수행하도록 설정되어 있으므로
MyBroadCastReceiver 클래스 파일을 보도록 하자.



MyBroadCastReceiver 클래스 파일 확인

public class MyBroadCastReceiver extends BroadcastReceiver {
   String usernameBase64ByteString;
   public static final String MYPREFS = "mySharedPreferences";

   @Override
   public void onReceive(Context context, Intent intent) {
        String phn = intent.getStringExtra("phonenumber");
        String newpass = intent.getStringExtra("newpass");

      if (phn != null) {
         try {
                SharedPreferences settings = context.getSharedPreferences(MYPREFS, Context.MODE_PRIVATE);
                final String username = settings.getString("EncryptedUsername", null);
                byte[] usernameBase64Byte = Base64.decode(username, Base64.DEFAULT);
                usernameBase64ByteString = new String(usernameBase64Byte, "UTF-8");
                final String password = settings.getString("superSecurePassword", null);
                CryptoClass crypt = new CryptoClass();
                String decryptedPassword = crypt.aesDeccryptedString(password);
                String textPhoneno = phn.toString();
                String textMessage = "Updated Password from: "+decryptedPassword+" to: "+newpass;
                SmsManager smsManager = SmsManager.getDefault();
                System.out.println("For the changepassword - phonenumber: "+textPhoneno+" password is: "+textMessage);
                smsManager.sendTextMessage(textPhoneno, null, textMessage, null, null);
         } catch (Exception e) {
            e.printStackTrace();
         }
      }
        else {
            System.out.println("Phone number is null");
        }
   }
}
표 3-2 MyBroadCastReceiver.class 파일 코드



위와 같이 MyBroadCastReceiver.class 파일의 코드를 보면,
BroadcastReceiver 객체를 상속받고 있고,
Intent-filter로 걸러진 Intent가 onReceive() 메서드로 들어온다.


💥 이때, 전화번호가 입력되어 있다면
newpass에 해당하는 새 비밀번호가 smsManager 객체를 통해 문자로 발송된다.
💥 전화번호가 입력되지 않았다면 "Phone number is null"을 출력한다.


만약 사용자 정의 브로드캐스트 리시버를 이용하거나,
Intent-filter에 특정 권한이 명시되어 있지 않다면
다른 애플리케이션에 의해서 브로드캐스트 리시버가 오∙남용될 위험이 있다.
어떤 위험한 공격이 가능한지 ADB를 이용하여 브로드캐스트를 직접 생성해본다.


먼저, nox_adb shell 명령어로 장치 프롬프트에 진입한 후,
브로드캐스트를 생성하기 위해 am(액티비티 매니저) 명령을 사용한다.
am은 안드로이드 시스템의 다양한 액션을 명령으로 수행할 수 있도록 한다.



1) 매개변수를 포함하지 않은 브로드캐스트 생성

그림 3-1 am broadcast 명령어로 브로드캐스트 생성



am broadcast -a theBroadcast -n com.android.insecurebankv2/.MyBroadCastReceiver 명령을 수행한다.


🐤 -a theBroadcast 옵션
theBroadcast라는 액션을 가진 Intent가 브로드캐스트로 전달된다는 의미이고,
🐤 -n com.android.insecurebankv2/.MyBroadCastReceiver
com.android.insecurebankv2 패키지에 있는
MyBroadCastReceiver 클래스에 Intent가 전달된다는 의미이다.


즉, MyBroadCastReceiver에 theBroadcast 액션을 가진 Intent를
MyBroadCastReceiver 클래스에 전달하는 브로드캐스트를 임의로 생성한 코드이다.


로그캣으로 확인해보면 다음과 같이 'Phone number is null' 메시지가 출력된다.
브로드캐스트를 발생시켰을 때 phn(휴대폰 번호)가 입력되지 않았다는 뜻이다.
로그캣으로 확인하기에 다양한 레벨과 태그로부터 오는 많은 양의 로그가 있으므로,
<logcat -s 태그:우선순위>를 사용하여 콘솔 출력 값만 확인하도록 하였다.



그림 3-2 매개변수가 없는 브로드캐스트 생성의 출력 값




2) 매개변수를 포함한 브로드캐스트 생성

이번에는 매개변수를 포함하여 am 명령을 수행해보자.
여기서 매개변수의 유무를 고려하는 이유는
MyBroadCastReceiver 클래스 코드에서 매개변수의 포함 유무에 따라
출력 메시지가 달라지도록 구현했기 때문이다.
1)의 명령에서 --es 옵션만 추가하여 명령을 실행한다.


명령어는 am broadcast -a theBroadcast -n com.android.insecurebankv2/.MyBroadCastReceiver --es phonenumber 01012345678 --es newpass default이고,
로그캣 출력 값은 다음과 같다.



그림 3-3 매개변수가 포함된 브로드캐스트 생성의 출력 값



이전 출력 값과 다르게,
For the changepassword - phonenumber : 01012345678 password is: Updated Password from: Jack@123$ to: default 메시지가 출력되고 있다.
입력된 전화번호과 비밀번호 값은 임의로 매개변수를 입력한 것이라 사용자의 정보가 아니지만,
기존에 사용하던 Jack@123$라는 비밀번호가 평문으로 노출되고 있다.
즉, 디컴파일한 안드로이드 앱의 코드를 보고 문자 메시지를 통해 입력된 번호로
기존의 비밀번호까지 전송되는 점을 파악한다면 충분히 시도 가능한 공격이다.




위험성

2019년 구글과 해리스 여론조사소에 의하면,
사용자들의 52%는 대부분의 서비스에 같은 비밀번호를 적용하고 있으며,
13%는 모든 서비스에서 같은 비밀번호를 사용하는 것으로 나타났다는 응답 결과가 있다.
약 65%의 사용자들은 대다수의 사이트에 같은 비밀번호를 사용하고 있는 셈이다.


이러한 일반 사용자들의 성향은 본 브로드캐스트 취약점의 관점에서 본다면,
기존 비밀번호를 안다는 가정하에 특정 사용자를 표적으로 하여
비밀번호 대입 공격을 여러 사이트에서 시도하고 계정을 탈취하는 등의
공격이 이루어질 수 있는 위험성의 근거가 된다.





대응 방안

컴포넌트에 대한 외부 접근을 허락하지 않는 것이 안전하다.
android:exported는 다른 앱 컴포넌트에서 액티비티를 불러올 수 있는지를 결정한다.
이것이 false인 경우 다른 앱에서는 불러올 수 없고,
같은 앱 내 또는 같은 user ID인 경우에만 컴포넌트 불러오기가 가능하다.
그러므로 기본적으로는 false로 적용해주는 것이 안전하며,
true로 설정할 경우에는 Intent-filter로 검증해야 한다.



이를 코드에 적용하면 다음과 같다.

<receiver
    android:name=".MyBroadCastReceiver"
<!-- 브로드캐스트 리시버 결함에 대한 수정: 다른 앱에서 컴포넌트를 불러올 수 없게 하였음 -->
    android:exported="false" > 
    <intent-filter>
        <action android:name="theBroadcast" >
        </action>
    </intent-filter>
</receiver>
그림 4-1 브로드캐스트 리시버 결함: AndroidManifest.xml 코드의 수정



본 취약점은 간단한 설정으로 방지가 가능하므로,
개발 시 이러한 부분을 인지하고 주의한다면 충분히 대응이 가능하다.



반응형
댓글
반응형
Recent Post.
Recent Reply.
Thanks for comming.
오늘은
명이 방문했어요
어제는
명이 방문했어요