背景介绍
- 近日,京东探索研究院信息安全实验室的研究团队发现一项高危Android 11系统漏洞链,利用该漏洞链,黑客可能在用户毫无感知的情况下,获取用户手机中所有APP的隐私数据和权限,如获取任一社交软件的聊天记录,任意劫持邮箱、公司内部沟通软件、支付软件等等。
- 听起来影响很大,但是往往最具威力的漏洞都有着很朴素的技术原理,魔形女系列漏洞正是如此。本文将在法律允许的范围内对魔形女系列漏洞进行技术解析。
故事的开始——CVE-2021-25485 of Samsung
- 这是一个三星手机的漏洞,下面是三星官方的披露信息。
Path traversal vulnerability in FactoryAirCommnadManger prior to SMR Oct-2021 Release 1 allows attackers to write file as system UID via BT remote socket.
- 根据这个信息,在Galaxy S21的相关组件中我们可以找到下面的代码,极有可能和该漏洞相关(其中省略了部分代码)
public void startSocket(Context context2) {
byte[] buffer = new byte[8192];
byte[] newBuffer = new byte[8192];
int maxLength = 0;
ACUtil.log_i(CLASS_NAME, "startSocket");
this.readSocket = new BufferedReader(new InputStreamReader(this.is, Charset.forName("UTF-8")));
ACUtil.log_i(CLASS_NAME, "readSocket", "readSocket: " + this.readSocket);
this.isRunning = true;
while (true) {
try {
int read = this.is.read(buffer); // Read data from bluetooth socket
//...
ACUtil.log_i(CLASS_NAME, "Socket", "Receive " + read + " bytes: " + Support.Functions.byteArrayToHexString(buffer, read));
if (this.isFileMode) {
//...
} else if (this.isMetaMode) {
//...
} else {
System.arraycopy(buffer, 0, newBuffer, maxLength, read);
maxLength += read;
if (newBuffer[maxLength - 1] == 126) {
//...
} else if (maxLength > 1 && newBuffer[maxLength - 2] == 13 && newBuffer[maxLength - 1] == 10) {
ACUtil.log_i(CLASS_NAME, "Socket", "string");
byte[] fullBuffer2 = new byte[maxLength];
System.arraycopy(newBuffer, 0, fullBuffer2, 0, maxLength);
String str3 = new String(fullBuffer2, 0, maxLength, "UTF-8");
if (str3.toUpperCase().contains("AT+FACMFILE")) {
this.isFileMode = true;
String subStr = str3.substring(str3.indexOf("=") + 1, str3.length() - 2);
this.fileName = subStr.split(",")[0];
this.fileLength = Integer.parseInt(subStr.split(",")[1]);
ACUtil.log_i(CLASS_NAME, "Socket", "name: " + this.fileName + " length: " + this.fileLength);
File file = new File(savePath);
if (!file.exists()) {
file.mkdirs(); // Create directory
}
File file2 = new File(savePath + this.fileName);
ACUtil.log_d(CLASS_NAME, "Socket", "Save: " + file2.getPath());
if (this.fileLength != 0) {
this.fos = new FileOutputStream(file2); // Write file
this.mHandler.sendEmptyMessage(0);
}
maxLength = 0;
Arrays.fill(newBuffer, (byte) 0);
} else {
//...
}
}
}
} catch (Exception e) {
e.printStackTrace();
BluetoothService.mHandler.sendEmptyMessageDelayed(1000, 3000);
}
}
//...
}
- 可以看到这里实际上是一个蓝牙的Socket接口,接收了相关的参数并进行的文件写入操作,这里面存在两个问题:
- 该Socket接口并没有任何的权限校验
- 在写入文件的过程中存在路径穿越问题,会导致任意文件写入
- 同时更严重的问题是,这个应用使用的是system uid运行,同时SELinux标签是system_app,这是一个特权应用。
Double Kill——CVE-2021-25450 of Samsung
- 在三星的相同组件中还存在第二个漏洞,下面是三星官方的披露信息。
Path traversal vulnerability in FactoryAirCommnadManger prior to SMR Sep-2021 Release 1 allows attackers to write file as system uid via remote socket.
- 同样地我们找到了下面的代码,极有可能和该漏洞相关(其中省略了部分代码)
public Void doInBackground(Void... voids) {
File checkFolder;
int n;
try {
this.dis = new DataInputStream(this.socket.getInputStream());
} catch (Exception e) {
e.printStackTrace();
}
while (true) {
ACUtil.log_d(CLASS_NAME, "doInBackground", "Wait for data...");
try {
//...
while (true) {
if (i >= count || isCancelled()) {
break;
}
String fileName = this.dis.readUTF(); // Read file name
String filePath = this.dis.readUTF(); // Read file path
long transferSize = this.dis.readLong(); // Read file size
ACUtil.log_d(CLASS_NAME, "doInBackground", "transferSize: " + transferSize);
String filePath2 = savePath + this.uniqueNumber + "/" + folderCount + "/" + filePath;
File file = new File(filePath2);
ACUtil.log_d(CLASS_NAME, "doInBackground", "filePath: " + filePath2);
ACUtil.log_d(CLASS_NAME, "doInBackground", "getCanonicalPath: " + file.getCanonicalPath());
if (!(file.getCanonicalPath() + '/').equals(filePath2)) {
cancel(true);
break;
}
if (!file.exists()) {
file.mkdirs(); // Create directory
}
File file2 = new File(filePath2 + fileName);
if (!file2.getCanonicalFile().toString().equals(filePath2 + fileName)) {
cancel(true);
break;
}
ACUtil.log_d(CLASS_NAME, "doInBackground", "Save: " + file2.getCanonicalFile());
this.fos = new FileOutputStream(file2);
byte[] b = new byte[1024];
long fileSize = transferSize;
long totalSize = 0;
while (fileSize > 0 && (n = this.dis.read(b, 0, (int) Math.min((long) b.length, fileSize))) != -1) {
this.fos.write(b, 0, n); // Write file
fileSize -= (long) n;
totalSize += (long) n;
}
ACUtil.log_d(CLASS_NAME, "doInBackground", "totalSize: " + totalSize);
ACUtil.log_d(CLASS_NAME, "doInBackground", "Save: " + (i + 1) + "/" + count);
this.context.sendBroadcast(new Intent(WifiCommandService.PROGRESS_CHANGE).putExtra("value", i + 1));
this.fos.close();
i++;
}
this.context.sendBroadcast(new Intent(WifiCommandService.PROGRESS_FINISH).putExtra("path", checkFolder.getPath()));
} catch (RuntimeException e2) {
throw e2;
} catch (Exception e3) {
e3.printStackTrace();
}
}
ACUtil.log_d(CLASS_NAME, "doInBackground", "Data Input Stream is null");
try {
if (this.fos != null) {
this.fos.close();
ACUtil.log_d(CLASS_NAME, "doInBackground", "fos close");
}
if (this.dis != null) {
this.dis.close();
ACUtil.log_d(CLASS_NAME, "doInBackground", "dis close");
}
} catch (Exception e4) {
e4.printStackTrace();
}
this.context.sendBroadcast(new Intent(WifiCommandService.PROGRESS_FINISH));
if (isCancelled()) {
return null;
}
this.context.sendBroadcast(new Intent(WifiCommandService.START_FILE_RECEIVE));
return null;
}
- 和上面的漏洞非常类似,这里是一个网络Socket接口,和漏洞披露的信息也是对的上的,也同样是接收了相关的参数并进行的文件写入操作,这里面也存在两个问题:
- 该Socket接口并没有任何的权限校验
- 在写入文件的过程中存在路径穿越问题,会导致任意文件写入
- 当然,该代码依旧是特权应用的一部分,不再赘述。
Triple kill——CVE-2021-23243 of OPPO
- 其实魔形女系列漏洞还包括一个OPPO的漏洞,但是由于我并没有OPPO的设备,并且对OPPO也不是很感兴趣,所以不深入分析,我估计原理和上两个漏洞应该也是非常类似的,都是system_app的路径穿越导致的任意文件写入。
如何将文件写入转化为代码执行
Google的迷之操作——CVE-2021-0691
# Settings need to access app name and icon from asec
allow system_app asec_apk_file:file r_file_perms;
-# Allow system_app (adb data loader) to write data to /data/incremental
-allow system_app apk_data_file:file write;
-
-# Allow system app (adb data loader) to read logs
-allow system_app incremental_control_file:file r_file_perms;
-
# Allow system apps (like Settings) to interact with statsd
binder_call(system_app, statsd)
apk_data_file
正是各种应用的apk文件的标签,Google错误地允许system_app对apk_data_file执行文件写入操作。这个问题只在Android 11中存在,我当时攻击的目标,是基于Android 10的ROM,而这段代码是Android 11升级的时候才加入的。
-rw-r--r-- 1 system system u:object_r:apk_data_file:s0 114976454 2021-11-12 16:01 base.apk
drwxr-xr-x 3 system system u:object_r:apk_data_file:s0 3488 2021-11-12 16:01 lib
- 后面的事情就顺理成章了,我们只需要覆盖任意一个会自启动的apk文件即可,后面就可以为所欲为了,就像开头说的一样。
后记
- 以上漏洞均在Google 2021 #9公告,三星的2021 #9和#10公告中得到了修复,并且该套利用只影响Android 11版本,虽然对于Google来说这个问题非常严重,因为是最新的版本。对于最终用户而言,Android 11的手机占比约为24.3%,大概1/4的Android客户受影响(经评论区提示,已经根据Android 开发者信息分发中心的新数据进行更新)。
Android 11 Google 11月公开的数据是全球24.2%,不是<1%哦: https://9to5google.com/2021/11/22/android-2021-distribution-numbers/
之前引用的是Android Studio新工程向导中的数据,刚才看了一下,确实也已经更新为24.3%。
指的是 https://developer.android.com/about/dashboards/ 中的“您可以在 Android Studio 的“Create New Project”向导中找到平台版本信息。”