Android/InsecureBankv2

인시큐어뱅크 앱 취약점 - 브로드캐스트 리시버 결함

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

인시큐어뱅크 앱 취약점 - 브로드캐스트 리시버 결함

 

취약점 소개

브로드캐스트 리시버란 안드로이드 시스템의 중요 요소 중 하나이다.

브로드캐스트란 ‘방송하다’라는 의미가 있으며, 브로드캐스트 리시버는 ‘방송 수신자’라는 의미로 유추할 수 있다.

안드로이드 시스템에서 특정 이벤트가 발생 시 시스템은 시스템 브로드캐스트 메세지를 이벤트가 수신되도록 신청한 모든 앱에 보내고, 브로드캐스트는 이를 수신한다.

표준 브로드캐스트 액션 종류

  • ACTION_BOOT_COMPLETED
  • 부팅이 끝났을 때 (RECEIVE_BOOT_COMPLETED 권한 등록 필요)
  • ACTION_CAMERA_BUTTON
  • 카메라 버튼이 눌렸을 때
  • ACTION_DATE_CHANGED
  • ACTION_TIME_CHANGED
  • 폰의 날짜, 시간이 수동으로 변했을 때 (설정에서 수정했을 때)
  • ACTION_SCREEN_OFF
  • ACTION_SCREEN_ON
  • 화면 on, off
  • ACTION_AIRPLANE_MODE_CHANGED
  • 비행기 모드
  • ACTION_BATTERY_CHANGED
  • ACTION_BATTERY_LOW
  • ACTION_BATTERY_OKAY
  • 배터리 상태변화
  • ACTION_PACKAGE_ADDED
  • ACTION_PACKAGE_CHANGED
  • ACTION_PACKAGE_DATA_CLEARED
  • ACTION_PACKAGE_INSTALL
  • ACTION_PACKAGE_REMOVED
  • ACTION_PACKAGE_REPLACED
  • ACTION_PACKAGE_RESTARTED
  • 어플 설치/제거
  • ACTION_POWER_CONNECTED
  • ACTION_POWER_DISCONNECTED
  • 충전 관련
  • ACTION_REBOOT
  • ACTION_SHUTDOWN
  • 재부팅/종료
  • ACTION_TIME_TICK
  • 매분마다 수신
  • android.provider.Telephony.SMS_RECEIVED
  • sms 수신 (RECEIVE_SMS 권한 필요)

 

즉 브로드캐스트 리시버는 배터리가 충전되고, 시스템이 방전되고, 부팅이 완료되는 것 등의 시스템 브로드캐스트 메세지를 수신하여사전에 정의된 작업을 수행하는 것이다.

만약 브로드캐스트 리시버가 안전하지 않게 설정되어 있는 경우, 사용자가 받는 메세지/전화 등의 알림을 중간에 가로채는 행위가 가능하며 특정 상황에서만 발생하는 작업을 수행하도록 악의적으로 조작할 수 있다.

인시큐어뱅크 앱애서 브로드캐스트 리시버가 포함된 코드의 취약성을 확인해본다.

취약점 진단

브로드 캐스트 리시버는 AndroidManifest.xml의 <receiver></receiver> 요소에 선언된다.

인시큐어뱅크 앱을 디컴파일하여 Insecurebankv2/app/src/main/AndroidManifest.xml파일의 <receiver> 요소를 Bytecode Viewer로 확인한 코드는 다음과 같다.

브로드캐스트의 이름은 theBroadcast로, exported=”true”로 인해 외부 앱으로부터 Intent 객체를 받을 수 있다.

 

브로드캐스트 신호를 받을 시 MyBroadCastReceiver라는 메서드에 설정된 작업을 수행하도록 설정되어있으므로 MyBroadReceiver 클래스 파일을 보도록 한다.

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

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub

        String phn = intent.getStringExtra("phonenumber");
        String newpass = intent.getStringExtra("newpass");

		if (phn != null) {
			try {
                SharedPreferences settings = context.getSharedPreferences(MYPREFS, Context`.MODE_WORLD_READABLE);
                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");
        }
	}

}

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

 

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

 

만약 사용자 정의 브로드캐스트 리시버를 이용하거나 Intent-filter에 특정 권한이 명시되어있지 않다면 다른 애플리케이션에 의해서 브로드캐스트 리시버가 오남용될 위험이 있다.

 

먼저 nox_adb shell 명령어로 장치 프롬포트로 진입한 후, 브로드캐스트를 생성하기 위해 am(액티비티 매니저) 명령을 사용한다.

 

am은 안드로이드 시스템의 다양한 액션을 명령으로 수행할 수 있도록 한다.

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

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 태그:우선순위>를 사용하여 콘솔 출력 값만 확인하도록 하였다.

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

이번에는 매개변수를 포함하여 am 명령어를 수행해보자.

 

여기서 매개변수의 유무를 고려하는 이유는 MyBroadCastReceiver 클래스 코드에서 매개변수의 포함 유무에 따라 출력 메세지가 달라지도록 구현했기 때문이다.

 

전의 명령어에서 —es 옵션만 추가하여 명령을 실행한다.

 

명령어는 am broadcast -a theBroadcast -n com.android.insecurebankv2/.MyBroadCastReceiver —es phonenumber 01012345678 —es newpass default이다.

이전 출력 값과 다르게 기존에 사용하던 Dinesh@123$ 라는 비밀번호가 평문으로 노출되고 있다.

즉, 디컴파일한 안드로이드 앱의 코드를 보고 문자 메시지를 통해 입력된 번호로 기존의 비밀번호까지 전송되는 점을 파악한다면 충분히 시도 가능한 공격이다.

대응방안

AndroidManifest.xml의 리시버 항목에 위치하는 “android:exported=true”항목을 “false”로 설정한다.

기본 세팅은 true로 설정되어 있는 상태이다. 이 값을 false로 변경하게 되면발생하는 인텐트에 영향을 받지 않게 되므로 브로드캐스트 리시버도 임의의 브로드캐스트에 영향을 받지 않는다.

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