概要
モバイルアプリセキュリティテストの演習を行うことができるAndroGoatを用いて、セキュリティテストのやり方をまとめていく。
検証環境:Android11エミュレータ(Pixel4a)
問題
以下のようなUserNameとPassWordの入力欄がある。
それがShared Preferencesというものに保存される。
保存方法を調査し、セキュリティ上のリスクを検証していきます。

解答
1.Shared preferencesとは
名前の通り共有設定を保存するために使われ、UIのテーマなどを保存できる。値はキーとバリューのペアでXMLの形式で保存される。
https://developer.android.com/reference/android/content/SharedPreferences
2.値の確認
場所は/data/data/[パッケージ名]/shared_prefs/
にある。
早速確認する。
まずパッケージ名を取得するためにadb shell pm list packages
コマンドで確認する。
sortやgrepをパイプすることをおすすめする。一番早いのはgrep。以下全文
adb shell pm list packages | sort | grep goat
後述するjadxにてAndroidManifestを確認する方法もある。こちらは正確かつ早い。後に解説。
どちらのやり方でもpackage:owasp.sat.agoatであるとわかる。
さっそく値を見ていく。事前にusernameとpasswordをSAVEボタンから保存する。
Data Savedと下に出れば問題ない。
続いてadb shellで中身を確認する。
adb shell
管理者権限が必要なのでsuで昇格。その後SharedPrefの中身を確認($,#はそれぞれshellなので以降を入力)
$ su
# ls /data/data/owasp.sat.agoat/shared_prefs/
score.xmlとusers.xmlが確認できる。今回つかうのはuser.xmlなのでcat等でも中身を確認する。
# cat /data/data/owasp.sat.agoat/shared_prefs/user.xml
するとあっさりと中身を確認することができた。
3.コードの確認
どのような実装によってこのようになっているのか、jadxというデコンパイルツールを使って、APKファイルからJavaソースコードに変換して中身を確認します。
Sorce code → owasp.sat.agoat → InsecureStorageSharedPrefs

Oncreate関数内に注目すると一行目にSharedPreferenceを呼び出している。
SharedPreferences sharedPreference = InsecureStorageSharedPrefs.this.getSharedPreferences("users", 0);
第1引数にはファイル名を指定している。先ほど確認したuser.xmlと一致している事がわかる。
第二引数にはモードまたはを指定できるが、今回は0がはいっているのでContext.MODE_PRIVATEと一致している。
その後sharedPreference.edit();をeditorという変数に格納して、editor.putString("username", username2.getText().toString());
でKeyとValueを実際に格納している
今回のリスクまとめ
今回はgetSharedPreferencesの第2引数が0のため、他アプリからは参照できないが、依然としてroot化されている場合やマルウェアによる侵害などでは依然として高いリスクになり得ます。
SharedPreferenceは、共有設定をキーとバリューとして保存できるがroot化されていれば簡単に除き見ることができるため、機密情報は格納しないようにしましょう。もしやむを得ない事情で保存する場合は、暗号化を行いキーを安全に保存しましょう。
おまけ
ResourcesのAndroidManifest.xmlから様々な情報を得ることができる。
先ほど紹介したパッケージ名の他にもsdkの最低バージョンおよび推奨バージョンなどを知ることができる他おいおい解説するであろうパーミッションなどを知ることができる。
今回はsdkVersionが最低でも18になっているが、MASTGによると
「Android 4.2(API レベル 17)以降、SharedPreferencesオブジェクトはプライベートとしてのみ宣言できます(つまり、すべてのアプリからアクセス可能な、つまり誰でも読み取り可能な状態ではありません)。」
とある。逆に言えば17以前はプライベートでない宣言も行えたため、第2引数が何かをしっかり確かめる必要性が上がっていた。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="owasp.sat.agoat">
<uses-sdk
android:minSdkVersion="18"
android:targetSdkVersion="26"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>