브로드캐스트 리시버(Broadcast Receiver)는 안드로이드 디바이스에서 이벤트가 발생하면 브로드캐스트 리시버 신호를 보내게 되는데, 이 신호를 받아 처리하는 역할을 수행한다.
신호를 받는 경우 애플리케이션에 정의해 놓은 작업을 수행한다. => 이 작업은 브로드캐스트 리시버를 상속받은 메서드에서 처리한다.
AndroidManifest.xml의 <receivcer>, </receiver> 항목에 선언된다.
-- 취약점 진단 방법 --
1. Manifest 확인
<receiver android:exported="true" android:name="com.android.insecurebankv2.MyBroadCastReceiver">
<intent-filter>
<action android:name="theBroadcast"/>
</intent-filter>
</receiver>
- 브로드캐스트 리시버 이름 : theBroadcast
- 신호를 받으면 MybroadcastReceiver에 설정된 작업을 수행
- exported : true => 그렇기 때문에 외부 애플리케이션으로 부터 intent를 받을수 있다.
2. MybroadcastReceiver smali 파일
.class public Lcom/android/insecurebankv2/MyBroadCastReceiver;
.super Landroid/content/BroadcastReceiver;
.source "MyBroadCastReceiver.java"
# static fields
.field public static final MYPREFS:Ljava/lang/String; = "mySharedPreferences"
# instance fields
.field usernameBase64ByteString:Ljava/lang/String;
# direct methods
.method public constructor <init>()V
.locals 0
.prologue
.line 16
invoke-direct {p0}, Landroid/content/BroadcastReceiver;-><init>()V
return-void
.end method
# virtual methods
.method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V
.locals 16
.param p1, "context" # Landroid/content/Context;
.param p2, "intent" # Landroid/content/Intent;
.prologue
.line 24
const-string v3, "phonenumber"
move-object/from16 v0, p2
invoke-virtual {v0, v3}, Landroid/content/Intent;->getStringExtra(Ljava/lang/String;)Ljava/lang/String;
move-result-object v12
.line 25
.local v12, "phn":Ljava/lang/String;
const-string v3, "newpass"
move-object/from16 v0, p2
invoke-virtual {v0, v3}, Landroid/content/Intent;->getStringExtra(Ljava/lang/String;)Ljava/lang/String;
move-result-object v10
.line 27
.local v10, "newpass":Ljava/lang/String;
if-eqz v12, :cond_0
.line 29
:try_start_0
const-string v3, "mySharedPreferences"
const/4 v5, 0x1
move-object/from16 v0, p1
invoke-virtual {v0, v3, v5}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;
move-result-object v13
.line 30
.local v13, "settings":Landroid/content/SharedPreferences;
const-string v3, "EncryptedUsername"
const/4 v5, 0x0
invoke-interface {v13, v3, v5}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
move-result-object v14
.line 31
.local v14, "username":Ljava/lang/String;
const/4 v3, 0x0
invoke-static {v14, v3}, Landroid/util/Base64;->decode(Ljava/lang/String;I)[B
move-result-object v15
.line 32
.local v15, "usernameBase64Byte":[B
new-instance v3, Ljava/lang/String;
const-string v5, "UTF-8"
invoke-direct {v3, v15, v5}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
move-object/from16 v0, p0
iput-object v3, v0, Lcom/android/insecurebankv2/MyBroadCastReceiver;->usernameBase64ByteString:Ljava/lang/String;
.line 33
const-string v3, "superSecurePassword"
const/4 v5, 0x0
invoke-interface {v13, v3, v5}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
move-result-object v11
.line 34
.local v11, "password":Ljava/lang/String;
new-instance v7, Lcom/android/insecurebankv2/CryptoClass;
invoke-direct {v7}, Lcom/android/insecurebankv2/CryptoClass;-><init>()V
.line 35
.local v7, "crypt":Lcom/android/insecurebankv2/CryptoClass;
invoke-virtual {v7, v11}, Lcom/android/insecurebankv2/CryptoClass;->aesDeccryptedString(Ljava/lang/String;)Ljava/lang/String;
move-result-object v8
.line 36
.local v8, "decryptedPassword":Ljava/lang/String;
invoke-virtual {v12}, Ljava/lang/String;->toString()Ljava/lang/String;
move-result-object v2
.line 37
.local v2, "textPhoneno":Ljava/lang/String;
new-instance v3, Ljava/lang/StringBuilder;
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
const-string v5, "Updated Password from: "
invoke-virtual {v3, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
invoke-virtual {v3, v8}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
const-string v5, " to: "
invoke-virtual {v3, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
invoke-virtual {v3, v10}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v4
.line 38
.local v4, "textMessage":Ljava/lang/String;
invoke-static {}, Landroid/telephony/SmsManager;->getDefault()Landroid/telephony/SmsManager;
move-result-object v1
.line 39
.local v1, "smsManager":Landroid/telephony/SmsManager;
sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream;
new-instance v5, Ljava/lang/StringBuilder;
invoke-direct {v5}, Ljava/lang/StringBuilder;-><init>()V
const-string v6, "For the changepassword - phonenumber: "
invoke-virtual {v5, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v5
invoke-virtual {v5, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v5
const-string v6, " password is: "
invoke-virtual {v5, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v5
invoke-virtual {v5, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v5
invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v5
invoke-virtual {v3, v5}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
.line 40
const/4 v3, 0x0
const/4 v5, 0x0
const/4 v6, 0x0
invoke-virtual/range {v1 .. v6}, Landroid/telephony/SmsManager;->sendTextMessage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;)V
:try_end_0
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
.line 48
.end local v1 # "smsManager":Landroid/telephony/SmsManager;
.end local v2 # "textPhoneno":Ljava/lang/String;
.end local v4 # "textMessage":Ljava/lang/String;
.end local v7 # "crypt":Lcom/android/insecurebankv2/CryptoClass;
.end local v8 # "decryptedPassword":Ljava/lang/String;
.end local v11 # "password":Ljava/lang/String;
.end local v13 # "settings":Landroid/content/SharedPreferences;
.end local v14 # "username":Ljava/lang/String;
.end local v15 # "usernameBase64Byte":[B
:goto_0
return-void
.line 41
:catch_0
move-exception v9
.line 42
.local v9, "e":Ljava/lang/Exception;
invoke-virtual {v9}, Ljava/lang/Exception;->printStackTrace()V
goto :goto_0
.line 46
.end local v9 # "e":Ljava/lang/Exception;
:cond_0
sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream;
const-string v5, "Phone number is null"
invoke-virtual {v3, v5}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
goto :goto_0
.end method
- 브로드캐스트가 발생하는 경우 intent-filter에 의해 걸러진 Intent들이 onReceiver() 메서드로 들어와 입력된 전화번호에 문자 메시지를 전송하도록 정의
3. ADB를 사용한 브로드캐스트 생성
- am 명령을 사용해서 브로드캐스트 생성 시도
명령어 : am broadcast -a theBroadcast -n com.android.insecurebankv2/.MyBroadCastReceiver
명령어 구성
- am: Activity Manager의 약자로, 안드로이드 시스템에서 액티비티, 서비스, 브로드캐스트 리시버 등을 제어하는 데 사용됩니다.
- broadcast: 브로드캐스트 인텐트를 보내는 명령입니다.
- -a: 인텐트의 액션을 지정합니다. 여기서 theBroadcast는 브로드캐스트 인텐트의 액션 이름입니다.
- -n: 구체적인 컴포넌트 이름을 지정합니다. 여기서 com.android.insecurebankv2/.MyBroadCastReceiver는 호출할 브로드캐스트 리시버의 전체 경로입니다.
해당 명령어 수행 시 발생하는 로그를 logcat을 통해서 확인해보면
2번에서 있는 smali 코드에서 있던 폰 번호 없이 실행 시킬때 발생하는 오류 인 "Phone number is null" 이라는 결과를 발생
4. 드로저를 사용한 브로드캐스트 생성
- 앱 자체에 취약점이 존재하는지 확인
- 브로드캐스트 리시버 정보 확인
dz> run app.broadcast.info -a com.android.insecurebankv2
Package: com.android.insecurebankv2
com.android.insecurebankv2.MyBroadCastReceiver
Permission: null
>> 결과 : MyBroadcastReceiver가 포함되어 있고, 권한은 설정되어있지 않음
명령어 : run app.broadcast.send --component com.android.insecurebankv2 com.android.insecurebankv2.MyBroadcastReceiver --extra string phonenumber 1111 --extra string newpass test
>> 결과 : --extra 옵션을 사용해 변수명, 값을 입력해서 변경을 시도
5. 대응방안
- androidmanifest.xml 내 android:exported 를 false로 설정
- 각 리시버에 별도의 권한을 설정
'보안 공부 > 모바일 보안' 카테고리의 다른 글
안드로이드 취약점 진단(3) - 액티비티 컴포넌트 취약점 (0) | 2024.02.19 |
---|---|
안드로이드 취약점 진단(2) - 취약한 인증 메커니즘(activity 취약점) (0) | 2024.02.18 |
드로저(drozer) 사용법 - 취약점 분석(1) (1) | 2024.02.03 |
드로저(drozer) 사용법 - 앱 패키지 정보 확인 (0) | 2024.02.02 |
모바일 앱 취약점 진단 드로저(drozer) 설치 및 세팅 방법 (1) | 2024.01.31 |