...
However, when the path is URL encoded, it may denote a file in an unintended directory which is outside of the pre-configured parent directory.
The From Android 4.3.0_r2.2, the method Uri.getLastPathSegment()
calls Uri.getPathSegments()
internally (see: Cross Reference: Uri.java):
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); } |
...
../../../data/data/com.example.android.app/shared_prefs/Example.xml
The string is converted to a Uri object by Uri.parse()
, which is passed to the second call of Uri.getLastPathSegment()
. The resulting string will be: Example.xml
The string is used to create a file object. However, if an attacker could supply a string which cannot be decoded by the first call of the Uri.getLastPathSegment()
, the last path segment may not be retrieved. An attacker can create such a string by using the technique called double encoding:
Double Encoding
(See [OWASP 2009] Double Encoding for more information.)
For example, the following double encoded string will circumvent the fix. %252E%252E%252F%252E%252E%252F%252E%252E%252Fdata%252Fdata%252Fcom.example.android.app%252Fshared_prefs%252FExample.xml
The first call of Uri.getLastPathSegment()
will decode "%25" to "%" and return the string:
%2E%2E%2F%2E%2E%2F%2E%2E%2Fdata%2Fdata%2Fcom.example.android.app%2Fshared_prefs%2FExample.xml
When this string is passed to the second Uri.getLastPathSegment(), "%2E" and "%2F" will be decoded and the result will be:
...
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
.
...
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
DRD07DRD08-J | High | Probable | Low | P18 | L1 |
Automated Detection
Automatic detection of the receipt of a URL is straightforward. It should also be feasible to automatically check whether the path has been canonicalized. However, if it has not, manual intervention would be required.
...
- JVN#78601526 GREE for Android vulnerable to directory traversal
Bibliography
...