Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added the source of Android SDK because it may change in the future.

...

The method Uri.getLastPathSegment() calls Uri.getPathSegments() internally (/frameworks/base/core/java/android/net/Uri.java from Android 4.3.0_r2.2):

Code Block
public String getLastPathSegment() {
  // TODO: If we haven't parsed all of the segments already, just
  // grab the last one directly so we only allocate one string.
  List<String> segments = getPathSegments();
  int size = segments.size();
  if (size == 0) {
    return null;
  }
  return segments.get(size - 1);
}

...

The following malicious code can exploit the vulnerable application that contains the first noncompliant code example:

Code Block
String target = "content://com.example.android.sdk.imageprovider/data/" +
  "..%2F..%2F..%2Fdata%2Fdata%2Fcom.example.android.app%2Fshared_prefs%2FExample.xml";

ContentResolver cr = this.getContentResolver();
FileInputStream fis = (FileInputStream)cr.openInputStream(Uri.parse(target));

byte[] buff = new byte[fis.available()];
in.read(buff);

Proof of Concept (Double Encoding)

The following malicious code can exploit the vulnerable application that contains the second noncompliant code example:

Code Block
String target = "content://com.example.android.sdk.imageprovider/data/" +
  "%252E%252E%252F%252E%252E%252F%252E%252E%252Fdata%252Fdata%252Fcom.example.android.app%252Fshared_prefs%252FExample.xml";

ContentResolver cr = this.getContentResolver();
FileInputStream fis = (FileInputStream)cr.openInputStream(Uri.parse(target));

byte[] buff = new byte[fis.available()];
in.read(buff);

 

Compliant Solution

In the following compliant solution, a path is decoded by Uri.decode() before use. Also, after the File object is created, the path is canonicalized by calling File.getCanonicalPath() and checked that it is included in IMAGE_DIRECTORY.

...