Skip to content

MASTG-DEMO-0001: File System Snapshots from External Storage

Content in BETA

This content is in beta and still under active development, so it is subject to change any time (e.g. structure, IDs, content, URLs, etc.).

Send Feedback

Sample

The snippet below shows sample code that creates two files in the external storage using the getExternalFilesDir method and the MediaStore API.

MastgTest.kt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package org.owasp.mastestapp

import android.content.Context
import android.util.Log
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import android.content.ContentValues
import android.os.Environment
import android.provider.MediaStore
import java.io.OutputStream

class MastgTest (private val context: Context){

    fun mastgTest(): String {
        mastgTestApi()
        mastgTestMediaStore()
        return "SUCCESS!!\n\nFiles have been written with API and MediaStore"
    }

    fun mastgTestApi() {
        val externalStorageDir = context.getExternalFilesDir(null)
        val fileName = File(externalStorageDir, "secret.txt")
        val fileContent = "secr3tPa\$\$W0rd\n"

        try {
            FileOutputStream(fileName).use { output ->
                output.write(fileContent.toByteArray())
                Log.d("WriteExternalStorage", "File written to external storage successfully.")
            }
        } catch (e: IOException) {
            Log.e("WriteExternalStorage", "Error writing file to external storage", e)
        }
    }

    fun mastgTestMediaStore() {
        try {
            val resolver = context.contentResolver
            var randomNum = (0..100).random().toString()
            val contentValues = ContentValues().apply {
                put(MediaStore.MediaColumns.DISPLAY_NAME, "secretFile$randomNum.txt")
                put(MediaStore.MediaColumns.MIME_TYPE, "text/plain")
                put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
            }
            val textUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)

            textUri?.let {
                val outputStream: OutputStream? = resolver.openOutputStream(it)
                outputStream?.use {
                    it.write("MAS_API_KEY=8767086b9f6f976g-a8df76\n".toByteArray())
                    it.flush()
                }
                Log.d("MediaStore", "File written to external storage successfully.")
            } ?: run {
                Log.e("MediaStore", "Error inserting URI to MediaStore.")
            }
        } catch (exception: Exception) {
            Log.e("MediaStore", "Error writing file to URI from MediaStore", exception)
        }
    }
}

Steps

  1. Install an app on your device.
  2. Execute run_before.sh which runs adb.
  3. Open an app and exercise it to trigger file creations.
  4. Execute run_after.sh.
  5. Close the app once you finish testing.
1
2
3
4
5
6
#!/bin/bash

# SUMMARY: This script creates a dummy file to mark a timestamp that we can use later
# on to identify files created during the app exercising

adb shell "touch /data/local/tmp/test_start"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash

# SUMMARY: List all files created after the creation date of a file created in run_before

adb shell "find /sdcard/ -type f -newer /data/local/tmp/test_start" > output.txt
adb shell "rm /data/local/tmp/test_start"
mkdir -p new_files
while read -r line; do
  adb pull "$line" ./new_files/
done < output.txt

Observation

There is a list of all created files inside output.txt.

output.txt
1
2
/sdcard/Android/data/org.owasp.mastestapp/files/secret.txt
/sdcard/Download/secretFile75.txt

Their content is inside the ./new_files/ directory and contains:

A password:

new_files/secret.txt
1
secr3tPa$$W0rd

And an API key:

new_files/secretFile75.txt
1
MAS_API_KEY=8767086b9f6f976g-a8df76

Evaluation

This test fails because the files are not encrypted and contain sensitive data (a password and an API key). You can further confirm this by reverse engineering the app and inspecting the code.