Lucene search

K
hackeroneAtorralbaH1:1650270
HistoryJul 26, 2022 - 1:38 p.m.

ownCloud: GitHub Security Lab (GHSL) Vulnerability Report: Insufficient path validation in ReceiveExternalFilesActivity.java (GHSL-2022-060)

2022-07-2613:38:15
atorralba
hackerone.com
$50
10

0.001 Low

EPSS

Percentile

30.7%

The GitHub Security Lab team has identified potential security vulnerabilities in Owncloud Android app.

We are committed to working with you to help resolve these issues. In this report you will find everything you need to effectively coordinate a resolution of these issues with the GHSL team.

If at any point you have concerns or questions about this process, please do not hesitate to reach out to us at [email protected] (please include GHSL-2022-059 or GHSL-2022-060 as a reference).

If you are NOT the correct point of contact for this report, please let us know!

Summary

The Owncloud Android app handles externally-provided files in the activity ReceiveExternalFilesActivity, where potentially malicious file paths are not properly sanitized, allowing attackers to read from and write to the application’s internal storage.

##Β Details

Access to arbitrary files in the app’s internal storage fix bypass

ReceiveExternalFilesActivity handles the upload of files provided by third party components in the device. The received data can be set arbitrarily by attackers, causing some functions that handle file paths to have unexpected behavior. https://hackerone.com/reports/377107 shows how that could be exploited in the past, using the android.intent.extra.STREAM extra to force the application to upload its internal files, like com.owncloud.android_preferences.xml. To fix it, the following code was added:

ReceiveExternalFilesActivity.java:521

private void prepareStreamsToUpload() {
    // --snip--

    for (Uri stream : mStreamsToUpload) {
        String streamToUpload = stream.toString();
        if (streamToUpload.contains("/data") &&
                streamToUpload.contains(getPackageName()) &&
                !streamToUpload.contains(getCacheDir().getPath())
        ) {
            finish();
        }
    }
}

This protection can be bypassed in two ways:

  • Using the path returned by getCacheDir() in the payload, e.g. "file:///data/user/0/com.owncloud.android/cache/../shared_prefs/com.owncloud.android_preferences.xml".
  • Using a content provider URI that uses the org.owncloud.files provider to access the app’s internal file folder, e.g. "content://org.owncloud.files/files/owncloud/logs/owncloud.2022-07-25.log".

With those payloads, the original issue can be still exploited with the same impact.

Write of arbitrary .txt files in the app’s internal storage

Additionally, there’s another insufficient path validation when uploading a plain text file that allows to write arbitrary files in the app’s internal storage.

When uploading a plain text file, the following code is executed, using the user-provided text at input to save the file:

ReceiveExternalFilesActivity:920

private void showUploadTextDialog() {
        // --snip--
        final TextInputEditText input = dialogView.findViewById(R.id.inputFileName);
        // --snip--
        setFileNameFromIntent(alertDialog, input);
        alertDialog.setOnShowListener(dialog -> {
            Button button = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
            button.setOnClickListener(view -> {
                // --snip--
                } else {
                    fileName += ".txt";
                    Uri fileUri = savePlainTextToFile(fileName);
                    mStreamsToUpload.clear();
                    mStreamsToUpload.add(fileUri);
                    uploadFiles();
                }
                inputLayout.setErrorEnabled(error != null);
                inputLayout.setError(error);
            });
        });
        alertDialog.show();
    }

By reviewing savePlainTextToFile, it can be seen that the plain text file is momentarily saved in the app’s cache, but the destination path is built using the user-provided fileName:

ReceiveExternalFilesActivity:983

private Uri savePlainTextToFile(String fileName) {
    Uri uri = null;
    String content = getIntent().getStringExtra(Intent.EXTRA_TEXT);
    try {
        File tmpFile = new File(getCacheDir(), fileName); // here
        FileOutputStream outputStream = new FileOutputStream(tmpFile);
        outputStream.write(content.getBytes());
        outputStream.close();
        uri = Uri.fromFile(tmpFile);

    } catch (IOException e) {
        Timber.w(e, "Failed to create temp file for uploading plain text: %s", e.getMessage());
    }
    return uri;
}

An attacker can exploit this using a path traversal attack to write arbitrary text files into the app’s internal storage or other restricted directories accessible by it. The only restriction is that the file will always have the .txt extension, limiting the impact.

Remediation

Validate user input before using it to construct a file path. Ideally, follow these rules:

  • Do not allow more than a single . character.
  • Do not allow directory separators such as / or \ (depending on the file system).
  • Do not rely on simply replacing problematic sequences such as ../. For example, after applying this filter to
    .../...// the resulting string would still be ../.
  • Ideally use an allowlist of known good patterns.

Resources

The following PoC demonstrates how to upload arbitrary files from the app’s internal storage:

adb shell am start -n com.owncloud.android.debug/com.owncloud.android.ui.activity.ReceiveExternalFilesActivity -t "text/plain" -a "android.intent.action.SEND" --eu "android.intent.extra.STREAM" "file:///data/user/0/com.owncloud.android.debug/cache/../shared_prefs/com.owncloud.android.debug_preferences.xml"

The following PoC demonstrates how to upload arbitrary files from the app’s internal files directory:

adb shell am start -n com.owncloud.android.debug/com.owncloud.android.ui.activity.ReceiveExternalFilesActivity -t "text/plain" -a "android.intent.action.SEND" --eu "android.intent.extra.STREAM" "content://org.owncloud.files/files/owncloud/logs/owncloud.2022-07-25.log"

The following PoC demonstrates how to write an arbitrary test.txt text file to the app’s internal storage:

adb shell am start -n com.owncloud.android.debug/com.owncloud.android.ui.activity.ReceiveExternalFilesActivity -t "text/plain" -a "android.intent.action.SEND" --es "android.intent.extra.TEXT" "Arbitrary contents here" --es "android.intent.extra.TITLE" "../shared_prefs/test"

GitHub Security Advisories

We recommend you create a private GitHub Security Advisory for these findings. This also allows you to invite the GHSL team to collaborate and further discuss these findings in private before they are published.

Credit

These issues were discovered and reported by the CodeQL team member @atorralba (Tony Torralba).

Contact

You can contact the GHSL team at [email protected], please include a reference to GHSL-2022-059 or GHSL-2022-060 in any communication regarding these issues.

Disclosure Policy

This report is subject to our coordinated disclosure policy.

Impact

These issues may lead to information disclosure when uploading the app’s internal files, and to arbitrary file write when uploading plain text files (although limited by the .txt extension).

0.001 Low

EPSS

Percentile

30.7%