1. MTP path traversal vulnerability in Android 4.4-----------------------------------------------
doSendObjectInfo() method of the MtpServer class implemented in
frameworks/av/media/mtp/MtpServer.cpp does not validate the name
parameter of the incoming MTP packet at all.
It is possible to upload files outside of the sdcard using a specially
crafted MTP request:
root () testpc:~/mtp-test# ./mtp-mysend sdf.txt \
../../../.././../data/data/com.android.providers.media/sdf.txt
libmtp version: 1.1.3
Device 0 (VID=18d1 and PID=4e42) is UNKNOWN.
Please report this VID/PID and the device model to the libmtp
development team
Android device detected, assigning default bug flags
Sending sdf.txt as
../../../../../../data/data/com.android.providers.media/sdf.txt
Sending file...
Progress: 25 of 25 (100%)
New file ID: 203
The file is written by the process com.android.providers.media:
root () grouper:/data/data/com.android.providers.media # ls -la
ls -la
drwxrwx--x u0_a6 u0_a6 2014-07-22 01:06 cache
drwxrwx--x u0_a6 u0_a6 2014-07-22 01:07 databases
lrwxrwxrwx install install 2014-07-22 01:05 lib ->
/data/app-lib/com.android.providers.media
-rw-rw-r-- u0_a6 media_rw 13 2014-09-24 01:36 sdf.txt
drwxrwx--x u0_a6 u0_a6 2014-07-22 01:06 shared_prefs
Tested on: Android 4.4.4
Reported on: 2014-09-26
Assigned CVE: CVE-2014-7954
Discovered by: Imre Rad / Search-Lab Ltd.
http://www.search-lab.hu
http://www.securecodingacademy.com/
2. ADB backup archive path traversal file overwrite ------------------------------------------------
Using adb one can create a backup of his/her Android device and store it
on the PC. The backup archive is based on the tar file format.
By modifying tar headers to contain ../../ like patterns it is possible
to overwrite files owned by the system user on writeable partitions.
An example pathname in the tar header:
apps/com.android.settings/sp/../../../../data/system/evil.txt
Tar header checksum must be corrected of course.
When restoring the modified archive the BackupManagerService overwrites
the resolved file name, since file name is not sanitized.
Bugfix in the version control:
https://android.googlesource.com/platform/frameworks/base/+/7bc601d%5E!/#F0
Android 5 (Lollipop) and newer versions are not affected (due to the
official bugfix linked above).
Additional conditions for exploiting on pre-Lollipop systems:
- Partition of the desination file must be mounted as writeable (eg.
/system won't work, but /data does)
- It is not possible to overwrite files owned by root, since the process
doing the restore is running as the same user as the package itself and
Android packages cannot run.
- It is not possible to overwrite files owned by system user since AOSP
4.3 due to Id6a0cb4c113c2e4a8c4605252cffa41bea22d8a3, a new hardening
was introduced "... ignoring non-agent system package ".
(If the operating system is custom and there is a system package
available with a full backup agent specified explicitly, then that
custom Android 4.3 and 4.4 might be affected too.)
Pre 4.3 AOSP systems are affected without further conditions: it is
possible to overwrite files owned by the system user or any other
packages installed on the system.
Tested on: Android 4.0.4:
Reported on: 2014-07-14
Assigned CVE: CVE-2014-7951
Android bug id: 16298491
Discovered by: Imre Rad / Search-Lab Ltd.
http://www.search-lab.hu
http://www.securecodingacademy.com/
3. Android backup agent arbitrary code execution---------------------------------------------
The Android backup agent implementation was vulnerable to privilege
escalation and race condition. An attacker with adb shell access could
run arbitrary code as the system (1000) user (or any other valid
package). The attack is tested on Android OS 4.4.4.
The main problem is inside bindBackupAgent method in the
ActivityManagerService.
This method is exported through Binder and is available to call by the
shell user, since android.permission.BACKUP is granted for it.
The method has an ApplicationInfo parameter, which is unsecured (not
cross validated through the PackageManager), so the uid member could be
manipulated. The supplied ApplicationInfo object will be direct
parameter for startProcessLocked().
Before invoking startProcessLocked, bindBackupAgent also tries to set
stopped state for the package.
This call is bound to an additional permission
(CHANGE_COMPONENT_ENABLED_STATE), which is a system permission, not even
shell user got it.
However, there is a race condition between PackageManager and
ActivityManagerService, so this security check can by bypassed.
Existence of the specified package happens first in
mSettings.setPackageStoppedStateLPw(). If the package does not exists
than IllegalArguemntException is thrown. (Permission would have been
validated as next step only resulting in a SecurityException)
So, if the package does not exists, IllegalArguemntException is thrown,
which is catched by bindBackupAgent, but the execution wont stop (only a
warning is being logged):
// Backup agent is now in use, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
app.packageName, false,
UserHandle.getUserId(app.uid));
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ app.packageName + ": " + e);
}
It was possible to perform the following steps in order to exploit:
1. execute "pm install helloworld.apk" (with package name
com.example.helloworld)
2. with another script process logcat's output and look for
the dexopt line (DexOpt: load 3ms, verify+opt 5ms, 161068 bytes)
3. trigger execution of the bindBackupAgent system call (with uid
spoofed to 1000 in ApplicationInfo) as soon as the dexopt line was seen
Since this is a race condition and timing is important, it might not
work at first. I was lucky at 3rd attempt.
In this lucky scenario the package did not exists while
setPackageStoppedStateLPw tried to find it, but then it became available
for startPackageLocked.
At this point a new process was forked by the Zygote:
shell () grouper:/ $ ps |grep hello
ps |grep hello
system 6826 141 692340 17312 ffffffff 00000000 S
com.example.helloworld
No code was executed however, since there exists an additional security
check in handleCreateBackupAgent in the ActivityThread:
PackageInfo requestedPackage =
getPackageManager().getPackageInfo(
data.appInfo.packageName, 0, UserHandle.myUserId());
if (requestedPackage.applicationInfo.uid != Process.myUid()) {
Slog.w(TAG, "Asked to instantiate non-matching package "
+ data.appInfo.packageName);
return;
}
But the process com.example.helloserver was executed with debug flags
(due to the simple fact that it was built by us and we built it as
debug) so DDMS could be attached to it.
To verify actual code execution, I added
Runtime.getRuntime().exec("touch /data/app/testSystem")
as an expression in the debugger to be evaluated by the process.
The command was executed successfully:
shell () grouper:/data/app $ ls -la testSystem
ls -la testSystem
-rw------- system system 0 2014-08-06 01:52 testSystem
13 byte bugfix for all the above in the version control:
https://android.googlesource.com/platform/frameworks/base/+/a8f6d1b%5E!/
Lollipop is not affected, earlier Android versions are.
Tested on: Android 4.4.4:
Reported on: 2014-08-15
Assigned CVE: CVE-2014-7951
Android bug id: 15829193
Discovered by: Imre Rad / Search-Lab Ltd.
http://www.search-lab.hu
http://www.securecodingacademy.com/