외로운 Nova의 작업실
insecurebankv2 - 애플리케이션 패칭 본문
insecurebankv2 - 애플리케이션 패칭
Nova_ 2023. 5. 18. 14:09- 취약점 소개
요즘 배포되는 안드로이드 모바일 악성코드는 정상적으로 서비스되고 있는 앱을 조작하여 사용자 개인 정보를 포함해 원하는 데이터를 얻기위한 코드들만 삽입해서 사용하고 있습니다. 따라서 기업들은 조작하지못하도록 자사의 앱 변조방지 솔루션들을 도입하고 있습니다. 만약, 변조방지 솔루션을 사용안한다면 어떻게 조작하는지 알아보겠습니다.
- 취약점 진단 과정
먼저 apk 파일을 디컴파일 해줍니다.
apktool d app-release.apk
app-release 폴더에 들어가게되면 디컴파일된 파일들이 있습니다. 이중에서 not rooted device!! 라는 문구를 위조하기 위해 postLogin.smali 파일을 찾아줍니다.
C:\Android-InsecureBankv2-master\InsecureBankv2\app\app-release\smali\com\android\insecurebankv2
열어보겠습니다.
.class public Lcom/android/insecurebankv2/PostLogin;
.super Landroid/app/Activity;
.source "PostLogin.java"
# instance fields
.field changepasswd_button:Landroid/widget/Button;
.field root_status:Landroid/widget/TextView;
.field statement_button:Landroid/widget/Button;
.field transfer_button:Landroid/widget/Button;
.field uname:Ljava/lang/String;
# direct methods
.method public constructor <init>()V
.locals 0
.prologue
.line 28
invoke-direct {p0}, Landroid/app/Activity;-><init>()V
return-void
.end method
.method private doesSUexist()Z
.locals 9
.prologue
const/4 v3, 0x1
const/4 v4, 0x0
.line 99
const/4 v1, 0x0
.line 101
.local v1, "process":Ljava/lang/Process;
:try_start_0
invoke-static {}, Ljava/lang/Runtime;->getRuntime()Ljava/lang/Runtime;
move-result-object v5
const/4 v6, 0x2
new-array v6, v6, [Ljava/lang/String;
const/4 v7, 0x0
const-string v8, "/system/xbin/which"
aput-object v8, v6, v7
const/4 v7, 0x1
const-string v8, "su"
aput-object v8, v6, v7
invoke-virtual {v5, v6}, Ljava/lang/Runtime;->exec([Ljava/lang/String;)Ljava/lang/Process;
move-result-object v1
.line 102
new-instance v0, Ljava/io/BufferedReader;
new-instance v5, Ljava/io/InputStreamReader;
invoke-virtual {v1}, Ljava/lang/Process;->getInputStream()Ljava/io/InputStream;
move-result-object v6
invoke-direct {v5, v6}, Ljava/io/InputStreamReader;-><init>(Ljava/io/InputStream;)V
invoke-direct {v0, v5}, Ljava/io/BufferedReader;-><init>(Ljava/io/Reader;)V
.line 103
.local v0, "in":Ljava/io/BufferedReader;
invoke-virtual {v0}, Ljava/io/BufferedReader;->readLine()Ljava/lang/String;
:try_end_0
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0
move-result-object v5
if-eqz v5, :cond_1
.line 108
if-eqz v1, :cond_0
invoke-virtual {v1}, Ljava/lang/Process;->destroy()V
.line 106
.end local v0 # "in":Ljava/io/BufferedReader;
:cond_0
:goto_0
return v3
.line 108
.restart local v0 # "in":Ljava/io/BufferedReader;
:cond_1
if-eqz v1, :cond_2
invoke-virtual {v1}, Ljava/lang/Process;->destroy()V
:cond_2
move v3, v4
.line 104
goto :goto_0
.line 105
.end local v0 # "in":Ljava/io/BufferedReader;
:catch_0
move-exception v2
.line 108
.local v2, "t":Ljava/lang/Throwable;
if-eqz v1, :cond_3
invoke-virtual {v1}, Ljava/lang/Process;->destroy()V
:cond_3
move v3, v4
.line 106
goto :goto_0
.line 108
.end local v2 # "t":Ljava/lang/Throwable;
:catchall_0
move-exception v3
if-eqz v1, :cond_4
invoke-virtual {v1}, Ljava/lang/Process;->destroy()V
:cond_4
throw v3
.end method
.method private doesSuperuserApkExist(Ljava/lang/String;)Z
.locals 4
.param p1, "s" # Ljava/lang/String;
.prologue
const/4 v2, 0x1
.line 115
new-instance v1, Ljava/io/File;
const-string v3, "/system/app/Superuser.apk"
invoke-direct {v1, v3}, Ljava/io/File;-><init>(Ljava/lang/String;)V
.line 116
.local v1, "rootFile":Ljava/io/File;
invoke-virtual {v1}, Ljava/io/File;->exists()Z
move-result v3
invoke-static {v3}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
move-result-object v0
.line 117
.local v0, "doesexist":Ljava/lang/Boolean;
invoke-virtual {v0}, Ljava/lang/Boolean;->booleanValue()Z
move-result v3
if-ne v3, v2, :cond_0
.line 123
:goto_0
return v2
:cond_0
const/4 v2, 0x0
goto :goto_0
.end method
# virtual methods
.method public callPreferences()V
.locals 2
.prologue
.line 176
new-instance v0, Landroid/content/Intent;
const-class v1, Lcom/android/insecurebankv2/FilePrefActivity;
invoke-direct {v0, p0, v1}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
.line 177
.local v0, "i":Landroid/content/Intent;
invoke-virtual {p0, v0}, Lcom/android/insecurebankv2/PostLogin;->startActivity(Landroid/content/Intent;)V
.line 178
return-void
.end method
.method protected changePasswd()V
.locals 3
.prologue
.line 132
new-instance v0, Landroid/content/Intent;
invoke-virtual {p0}, Lcom/android/insecurebankv2/PostLogin;->getApplicationContext()Landroid/content/Context;
move-result-object v1
const-class v2, Lcom/android/insecurebankv2/ChangePassword;
invoke-direct {v0, v1, v2}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
.line 133
.local v0, "cP":Landroid/content/Intent;
const-string v1, "uname"
iget-object v2, p0, Lcom/android/insecurebankv2/PostLogin;->uname:Ljava/lang/String;
invoke-virtual {v0, v1, v2}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
.line 134
invoke-virtual {p0, v0}, Lcom/android/insecurebankv2/PostLogin;->startActivity(Landroid/content/Intent;)V
.line 135
return-void
.end method
.method protected onCreate(Landroid/os/Bundle;)V
.locals 3
.param p1, "savedInstanceState" # Landroid/os/Bundle;
.prologue
.line 41
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 42
const v1, 0x7f04001e
invoke-virtual {p0, v1}, Lcom/android/insecurebankv2/PostLogin;->setContentView(I)V
.line 43
invoke-virtual {p0}, Lcom/android/insecurebankv2/PostLogin;->getIntent()Landroid/content/Intent;
move-result-object v0
.line 44
.local v0, "intent":Landroid/content/Intent;
const-string v1, "uname"
invoke-virtual {v0, v1}, Landroid/content/Intent;->getStringExtra(Ljava/lang/String;)Ljava/lang/String;
move-result-object v1
iput-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->uname:Ljava/lang/String;
.line 46
const v1, 0x7f0d007f
invoke-virtual {p0, v1}, Lcom/android/insecurebankv2/PostLogin;->findViewById(I)Landroid/view/View;
move-result-object v1
check-cast v1, Landroid/widget/TextView;
iput-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->root_status:Landroid/widget/TextView;
.line 48
invoke-virtual {p0}, Lcom/android/insecurebankv2/PostLogin;->showRootStatus()V
.line 52
const v1, 0x7f0d007c
invoke-virtual {p0, v1}, Lcom/android/insecurebankv2/PostLogin;->findViewById(I)Landroid/view/View;
move-result-object v1
check-cast v1, Landroid/widget/Button;
iput-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->transfer_button:Landroid/widget/Button;
.line 53
iget-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->transfer_button:Landroid/widget/Button;
new-instance v2, Lcom/android/insecurebankv2/PostLogin$1;
invoke-direct {v2, p0}, Lcom/android/insecurebankv2/PostLogin$1;-><init>(Lcom/android/insecurebankv2/PostLogin;)V
invoke-virtual {v1, v2}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
.line 65
const v1, 0x7f0d007d
invoke-virtual {p0, v1}, Lcom/android/insecurebankv2/PostLogin;->findViewById(I)Landroid/view/View;
move-result-object v1
check-cast v1, Landroid/widget/Button;
iput-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->statement_button:Landroid/widget/Button;
.line 66
iget-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->statement_button:Landroid/widget/Button;
new-instance v2, Lcom/android/insecurebankv2/PostLogin$2;
invoke-direct {v2, p0}, Lcom/android/insecurebankv2/PostLogin$2;-><init>(Lcom/android/insecurebankv2/PostLogin;)V
invoke-virtual {v1, v2}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
.line 74
const v1, 0x7f0d007e
invoke-virtual {p0, v1}, Lcom/android/insecurebankv2/PostLogin;->findViewById(I)Landroid/view/View;
move-result-object v1
check-cast v1, Landroid/widget/Button;
iput-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->changepasswd_button:Landroid/widget/Button;
.line 75
iget-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->changepasswd_button:Landroid/widget/Button;
new-instance v2, Lcom/android/insecurebankv2/PostLogin$3;
invoke-direct {v2, p0}, Lcom/android/insecurebankv2/PostLogin$3;-><init>(Lcom/android/insecurebankv2/PostLogin;)V
invoke-virtual {v1, v2}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
.line 83
return-void
.end method
.method public onCreateOptionsMenu(Landroid/view/Menu;)Z
.locals 2
.param p1, "menu" # Landroid/view/Menu;
.prologue
.line 151
invoke-virtual {p0}, Lcom/android/insecurebankv2/PostLogin;->getMenuInflater()Landroid/view/MenuInflater;
move-result-object v0
const v1, 0x7f0e0002
invoke-virtual {v0, v1, p1}, Landroid/view/MenuInflater;->inflate(ILandroid/view/Menu;)V
.line 152
const/4 v0, 0x1
return v0
.end method
.method public onOptionsItemSelected(Landroid/view/MenuItem;)Z
.locals 5
.param p1, "item" # Landroid/view/MenuItem;
.prologue
const/4 v2, 0x1
.line 161
invoke-interface {p1}, Landroid/view/MenuItem;->getItemId()I
move-result v1
.line 162
.local v1, "id":I
const v3, 0x7f0d009f
if-ne v1, v3, :cond_0
.line 163
invoke-virtual {p0}, Lcom/android/insecurebankv2/PostLogin;->callPreferences()V
.line 171
:goto_0
return v2
.line 165
:cond_0
const v3, 0x7f0d00a0
if-ne v1, v3, :cond_1
.line 166
new-instance v0, Landroid/content/Intent;
invoke-virtual {p0}, Lcom/android/insecurebankv2/PostLogin;->getBaseContext()Landroid/content/Context;
move-result-object v3
const-class v4, Lcom/android/insecurebankv2/LoginActivity;
invoke-direct {v0, v3, v4}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
.line 167
.local v0, "i":Landroid/content/Intent;
const/high16 v3, 0x4000000
invoke-virtual {v0, v3}, Landroid/content/Intent;->addFlags(I)Landroid/content/Intent;
.line 168
invoke-virtual {p0, v0}, Lcom/android/insecurebankv2/PostLogin;->startActivity(Landroid/content/Intent;)V
goto :goto_0
.line 171
.end local v0 # "i":Landroid/content/Intent;
:cond_1
invoke-super {p0, p1}, Landroid/app/Activity;->onOptionsItemSelected(Landroid/view/MenuItem;)Z
move-result v2
goto :goto_0
.end method
.method showRootStatus()V
.locals 3
.prologue
const/4 v1, 0x1
.line 86
const-string v2, "/system/app/Superuser.apk"
invoke-direct {p0, v2}, Lcom/android/insecurebankv2/PostLogin;->doesSuperuserApkExist(Ljava/lang/String;)Z
move-result v2
if-nez v2, :cond_0
.line 87
invoke-direct {p0}, Lcom/android/insecurebankv2/PostLogin;->doesSUexist()Z
move-result v2
if-eqz v2, :cond_1
:cond_0
move v0, v1
.line 88
.local v0, "isrooted":Z
:goto_0
if-ne v0, v1, :cond_2
.line 90
iget-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->root_status:Landroid/widget/TextView;
const-string v2, "Rooted Device!!"
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
.line 96
:goto_1
return-void
.line 87
.end local v0 # "isrooted":Z
:cond_1
const/4 v0, 0x0
goto :goto_0
.line 94
.restart local v0 # "isrooted":Z
:cond_2
iget-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->root_status:Landroid/widget/TextView;
const-string v2, "Device not Rooted!!"
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
goto :goto_1
.end method
.method protected viewStatment()V
.locals 3
.prologue
.line 142
new-instance v0, Landroid/content/Intent;
invoke-virtual {p0}, Lcom/android/insecurebankv2/PostLogin;->getApplicationContext()Landroid/content/Context;
move-result-object v1
const-class v2, Lcom/android/insecurebankv2/ViewStatement;
invoke-direct {v0, v1, v2}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
.line 143
.local v0, "vS":Landroid/content/Intent;
const-string v1, "uname"
iget-object v2, p0, Lcom/android/insecurebankv2/PostLogin;->uname:Ljava/lang/String;
invoke-virtual {v0, v1, v2}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
.line 144
invoke-virtual {p0, v0}, Lcom/android/insecurebankv2/PostLogin;->startActivity(Landroid/content/Intent;)V
.line 145
return-void
.end method
위 코드중에서 Device not rooted 영어로 찾아줍니다.
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
.line 96
:goto_1
return-void
.line 87
.end local v0 # "isrooted":Z
:cond_1
const/4 v0, 0x0
goto :goto_0
.line 94
.restart local v0 # "isrooted":Z
:cond_2
iget-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->root_status:Landroid/widget/TextView;
const-string v2, "Device not Rooted!!"
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
이 문자를 저는 Nova!!로 변조해보겠습니다.
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
.line 96
:goto_1
return-void
.line 87
.end local v0 # "isrooted":Z
:cond_1
const/4 v0, 0x0
goto :goto_0
.line 94
.restart local v0 # "isrooted":Z
:cond_2
iget-object v1, p0, Lcom/android/insecurebankv2/PostLogin;->root_status:Landroid/widget/TextView;
const-string v2, "Nova!!"
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
goto :goto_1
.end method
이제 디컴파일된 파일을 컴파일 해줍니다.
apktool b app-release
이후 app-release/dist 파일이 생기면 apk 파일이 하나 생깁니다.
근데, 아직 서명을 하지않아서 안드로이드에 설치하지못합니다. 따라서 서명을 해줘야합니다. 서명키는 안드로이드 스튜디오에서 생성할 수 있고, 이를 가지고 서명해보겠습니다. 서명 툴은 아래 경로에 있습니다.
C:\Program Files\Java\jdk-20\bin
먼저, 키 파일에대해서 알아보겠습니다.
keytool -list -v -keystore C:\Android-InsecureBankv2-master\insecurebank_test.jks
별칭이 key0인 것을 확인할 수 있습니다. 이를 이용해서 apk 파일을 서명해줍니다.
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore [키스토어경로] [서명할apk경로] [키스토어별명]
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore C:\Android-InsecureBankv2-master\insecurebank_test.jks C:\Android-InsecureBankv2-master\InsecureBankv2\app\app-release\dist\app-release.apk key0
이후 dist에 있는 apk파일이 변경됩니다. 이제 apk파일을 nox의 앱을 지운후 설치하고 접속해줍니다.
Nova!!로 변경된 것을 확인할 수 있습니다. 변조가 된 것 입니다.
- 취약점 대응 방안
앱의 위변조를 하려면 앱의 로직을 알아야합니다. 이 로직을 알게하기 어렵게하면 앱의 위변조를 막을 수 있습니다. 즉, 난독화를 해서 로직을 어렵게해야합니다. 안드로이드 스튜디오는 난독화 도구로 프로가드를 무료로 제공합니다. 그래들 파일에 buildeTypes의 속성중 minifyEnabled를 true로 설정하면 난독화가 적용됩니다. 하지만 프로가드는 사용 난독화도구들과 비교했을때 부족한 부분이 많습니다. 따라서 dexGuard나 다른 난독화 솔루션을 사용하는 것이 좋습니다.
'Mobile App Penetesting > Android App Vulnerability' 카테고리의 다른 글
insecurebankv2 - 안전하지 않은 로깅 메커니즘 (0) | 2023.05.20 |
---|---|
insecurebankv2 - 메모리내 민감한 정보 저장 (0) | 2023.05.19 |
insecurebankv2 - 취약한 암호화 실행 (0) | 2023.05.15 |
insecurebankv2 - 안전하지 않은 콘텐츠 프로바이더 접근 (0) | 2023.05.13 |
insecurebankv2 - 루팅 탐지 우회 (0) | 2023.05.12 |